diff options
681 files changed, 39883 insertions, 10846 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index 531e44ec8e..0900eea0cf 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -66,3 +66,6 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-sp/android.hardware $(call add-clean-step, find $(PRODUCT_OUT)/system $(PRODUCT_OUT)/vendor -type f -name "android\.hardware\.configstore\@1\.1*" -print0 | xargs -0 rm -f) $(call add-clean-step, find $(PRODUCT_OUT)/system $(PRODUCT_OUT)/vendor -type f -name "android\.hardware\.configstore*" -print0 | xargs -0 rm -f) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/seccomp_policy/configstore@1.0.policy) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/seccomp_policy/configstore@1.1.policy) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.configstore@1.1-service) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.configstore@1.1-service.rc) diff --git a/audio/5.0/Android.bp b/audio/5.0/Android.bp index 27c1ef5f5e..3586b8e308 100644 --- a/audio/5.0/Android.bp +++ b/audio/5.0/Android.bp @@ -20,6 +20,7 @@ hidl_interface { "android.hardware.audio.common@5.0", "android.hardware.audio.effect@5.0", "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", ], types: [ "AudioDrain", @@ -28,18 +29,13 @@ hidl_interface { "AudioMicrophoneCoordinate", "AudioMicrophoneDirectionality", "AudioMicrophoneLocation", - "DeviceAddress", "MessageQueueFlagBits", "MicrophoneInfo", "MmapBufferFlag", "MmapBufferInfo", "MmapPosition", "ParameterValue", - "PlaybackTrackMetadata", - "RecordTrackMetadata", "Result", - "SinkMetadata", - "SourceMetadata", "TimeSpec", ], gen_java: false, diff --git a/audio/5.0/IDevice.hal b/audio/5.0/IDevice.hal index afb4fad211..9e45ba5f5b 100644 --- a/audio/5.0/IDevice.hal +++ b/audio/5.0/IDevice.hal @@ -133,7 +133,7 @@ interface IDevice { * @param config stream configuration. * @param flags additional flags. * @param sinkMetadata Description of the audio that is suggested by the client. - * May be used by implementations to configure hardware effects. + * May be used by implementations to configure processing effects. * @return retval operation completion status. * @return inStream in case of success, created input stream. * @return suggestedConfig in case of invalid parameters, suggested config. diff --git a/audio/5.0/IStreamIn.hal b/audio/5.0/IStreamIn.hal index d33cfdc773..b042960b17 100644 --- a/audio/5.0/IStreamIn.hal +++ b/audio/5.0/IStreamIn.hal @@ -165,4 +165,27 @@ interface IStreamIn extends IStream { */ getActiveMicrophones() generates(Result retval, vec<MicrophoneInfo> microphones); + + /** + * Specifies the logical microphone (for processing). + * + * Optional method + * + * @param Direction constant + * @return retval OK if the call is successful, an error code otherwise. + */ + setMicrophoneDirection(MicrophoneDirection direction) + generates(Result retval); + + /** + * Specifies the zoom factor for the selected microphone (for processing). + * + * Optional method + * + * @param the desired field dimension of microphone capture. Range is from -1 (wide angle), + * though 0 (no zoom) to 1 (maximum zoom). + * + * @return retval OK if the call is not successful, an error code otherwise. + */ + setMicrophoneFieldDimension(float zoom) generates(Result retval); }; diff --git a/audio/5.0/config/api/current.txt b/audio/5.0/config/api/current.txt index b8dcb43fb0..17f38c1647 100644 --- a/audio/5.0/config/api/current.txt +++ b/audio/5.0/config/api/current.txt @@ -20,8 +20,10 @@ package audio.policy.configuration.V5_0 { enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET; + enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_HDMI; + enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_IP; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_LINE; enum_constant public static final audio.policy.configuration.V5_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK; @@ -91,6 +93,10 @@ package audio.policy.configuration.V5_0 { enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_ERLC; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LATM; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LC; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LD; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AAC_LTP; @@ -106,7 +112,9 @@ package audio.policy.configuration.V5_0 { enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_APE; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_APTX; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_APTX_HD; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_CELT; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_DSD; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_DTS; @@ -122,6 +130,8 @@ package audio.policy.configuration.V5_0 { enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_IEC61937; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_LDAC; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_LHDC; + enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_LHDC_LL; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_MAT_1_0; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_MAT_2_0; enum_constant public static final audio.policy.configuration.V5_0.AudioFormat AUDIO_FORMAT_MAT_2_1; @@ -187,6 +197,7 @@ package audio.policy.configuration.V5_0 { public static class DevicePorts.DevicePort { ctor public DevicePorts.DevicePort(); method public String getAddress(); + method public java.util.List<audio.policy.configuration.V5_0.AudioFormat> getEncodedFormats(); method public audio.policy.configuration.V5_0.Gains getGains(); method public java.util.List<audio.policy.configuration.V5_0.Profile> getProfile(); method public audio.policy.configuration.V5_0.Role getRole(); @@ -194,6 +205,7 @@ package audio.policy.configuration.V5_0 { method public String getType(); method public boolean get_default(); method public void setAddress(String); + method public void setEncodedFormats(java.util.List<audio.policy.configuration.V5_0.AudioFormat>); method public void setGains(audio.policy.configuration.V5_0.Gains); method public void setRole(audio.policy.configuration.V5_0.Role); method public void setTagName(String); diff --git a/audio/5.0/config/audio_policy_configuration.xsd b/audio/5.0/config/audio_policy_configuration.xsd index b0927b25d4..ee3a437d1d 100644 --- a/audio/5.0/config/audio_policy_configuration.xsd +++ b/audio/5.0/config/audio_policy_configuration.xsd @@ -277,6 +277,8 @@ <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/> <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/> <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/> + <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/> + <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/> <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/> <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/> </xs:restriction> @@ -364,6 +366,14 @@ <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/> <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/> <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/> + <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/> + <xs:enumeration value="AUDIO_FORMAT_CELT"/> + <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/> + <xs:enumeration value="AUDIO_FORMAT_LHDC"/> + <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="extendableAudioFormat"> @@ -461,6 +471,8 @@ </xs:documentation> </xs:annotation> </xs:attribute> + <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional" + default="" /> </xs:complexType> <xs:unique name="devicePortProfileUniqueness"> <xs:selector xpath="profile"/> @@ -595,7 +607,7 @@ <xs:element name="formats" type="surroundFormats"/> </xs:sequence> </xs:complexType> - <xs:simpleType name="surroundFormatsList"> + <xs:simpleType name="audioFormatsList"> <xs:list itemType="audioFormat" /> </xs:simpleType> <xs:complexType name="surroundFormats"> @@ -603,7 +615,7 @@ <xs:element name="format" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:attribute name="name" type="audioFormat" use="required"/> - <xs:attribute name="subformats" type="surroundFormatsList" /> + <xs:attribute name="subformats" type="audioFormatsList" /> </xs:complexType> </xs:element> </xs:sequence> diff --git a/audio/5.0/types.hal b/audio/5.0/types.hal index 988f584b62..2c153c6ea4 100644 --- a/audio/5.0/types.hal +++ b/audio/5.0/types.hal @@ -49,34 +49,11 @@ struct TimeSpec { uint64_t tvNSec; // nanoseconds }; -/** - * IEEE 802 MAC address. - */ -typedef uint8_t[6] MacAddress; - struct ParameterValue { string key; string value; }; -/** - * Specifies a device in case when several devices of the same type - * can be connected (e.g. BT A2DP, USB). - */ -struct DeviceAddress { - AudioDevice device; // discriminator - union Address { - MacAddress mac; // used for BLUETOOTH_A2DP_* - uint8_t[4] ipv4; // used for IP - struct Alsa { - int32_t card; - int32_t device; - } alsa; // used for USB_* - } address; - string busAddress; // used for BUS - string rSubmixAddress; // used for REMOTE_SUBMIX -}; - enum MmapBufferFlag : uint32_t { NONE = 0x0, /** @@ -244,3 +221,29 @@ struct MicrophoneInfo { */ AudioMicrophoneCoordinate orientation; }; + +/** + * Constants used by the HAL to determine how to select microphones and process those inputs in + * order to optimize for capture in the specified direction. + * + * MicrophoneDirection Constants are defined in MicrophoneDirection.java. + */ +@export(name="audio_microphone_direction_t", value_prefix="MIC_DIRECTION_") +enum MicrophoneDirection : int32_t { + /** + * 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, +}; diff --git a/audio/README b/audio/README index 1f1e8e3ad8..abe979c0fa 100644 --- a/audio/README +++ b/audio/README @@ -1,48 +1,33 @@ Directory structure of the audio HIDL related code. audio -|-- 2.0 <== HIDL (.hal) can not be moved to fit the directory structure -| because that would create a separate HAL +|-- 2.0 <== core 2.0 HIDL API. .hal can not be moved into the core directory +| because that would change its namespace and include path |-- 4.0 <== Version 4.0 of the core API | +|-- ... +| |-- common <== code common to audio core and effect API -| |-- 2.0 -| | |-- default <== code that wraps the legacy API -| | `-- vts <== vts of 2.0 core and effect API common code +| |-- 2.0 <== HIDL API of V2 | |-- 4.0 -| | |-- default -| | `-- vts -| |-- ... <== The future versions should continue this structure -| | |-- default -| | `-- vts +| |-- ... | `-- all_versions <== code common to all version of both core and effect API -| |-- default -| `-- vts <== vts of core and effect API common version independent code +| |-- default <== implementation shared code between core and effect impl +| |-- test <== utilities used by tests +| `-- util <== utilities used by both implementation and tests | -|-- core <== code relative to the core API -| |-- 2.0 <== 2.0 core API code (except .hal, see audio/2.0) -| | |-- default -| | `-- vts -| |-- 4.0 -| | |-- default <== default implementation of the core 4.0 api -| | `-- vts <== vts code of the 4.0 API -| |-- ... -| | |-- default -| | `-- vts -| `-- all_versions -| |-- default -| `-- vts <== vts of core API common version independent code +|-- core <== VTS and default implementation of the core API (not HIDL, see /audio/2.0)) +| `-- all_versions <== Code is version independent through #if and separate files +| |-- default <== code that wraps the legacy API +| `-- vts <== vts of core API +| |-- 2.0 <== 2.0 specific tests and helpers +| |-- 4.0 +| |-- ... | `-- effect <== idem for the effect API |-- 2.0 - | |-- default - | `-- vts |-- 4.0 - | |-- default - | `-- vts |-- ... - | |-- default - | `-- vts `-- all_versions |-- default `-- vts diff --git a/audio/common/2.0/default/VersionUtils.h b/audio/common/2.0/default/VersionUtils.h deleted file mode 100644 index 60d1f9cb6d..0000000000 --- a/audio/common/2.0/default/VersionUtils.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_VERSION_UTILS_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_VERSION_UTILS_H - -#include <android/hardware/audio/common/2.0/types.h> - -namespace android { -namespace hardware { -namespace audio { -namespace common { -namespace V2_0 { -namespace implementation { - -typedef common::V2_0::AudioDevice AudioDeviceBitfield; -typedef common::V2_0::AudioChannelMask AudioChannelBitfield; -typedef common::V2_0::AudioOutputFlag AudioOutputFlagBitfield; -typedef common::V2_0::AudioInputFlag AudioInputFlagBitfield; - -} // namespace implementation -} // namespace V2_0 -} // namespace common -} // namespace audio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_VERSION_UTILS_H diff --git a/audio/common/5.0/Android.bp b/audio/common/5.0/Android.bp index 663f8470f9..86d935475f 100644 --- a/audio/common/5.0/Android.bp +++ b/audio/common/5.0/Android.bp @@ -9,6 +9,9 @@ hidl_interface { srcs: [ "types.hal", ], + interfaces: [ + "android.hidl.safe_union@1.0", + ], types: [ "AudioChannelMask", "AudioConfig", @@ -38,7 +41,12 @@ hidl_interface { "AudioSource", "AudioStreamType", "AudioUsage", + "DeviceAddress", "FixedChannelCount", + "PlaybackTrackMetadata", + "RecordTrackMetadata", + "SinkMetadata", + "SourceMetadata", "ThreadInfo", "Uuid", ], diff --git a/audio/common/5.0/types.hal b/audio/common/5.0/types.hal index 2ce2929dce..ffe45069a8 100644 --- a/audio/common/5.0/types.hal +++ b/audio/common/5.0/types.hal @@ -16,6 +16,8 @@ package android.hardware.audio.common@5.0; +import android.hidl.safe_union@1.0; + /* * * IDs and Handles @@ -131,7 +133,18 @@ enum AudioSource : int32_t { * and raw signal analysis. */ UNPROCESSED = 9, - + /** + * Source for capturing audio meant to be processed in real time and played back for live + * performance (e.g karaoke). The capture path will minimize latency and coupling with + * playback path. + */ + VOICE_PERFORMANCE = 10, + /** + * Source for an echo canceller to capture the reference signal to be cancelled. + * The echo reference signal will be captured as close as possible to the DAC in order + * to include all post processing applied to the playback path. + */ + ECHO_REFERENCE = 1997, FM_TUNER = 1998, }; @@ -222,6 +235,12 @@ enum AudioFormat : uint32_t { LDAC = 0x23000000UL, /** Dolby Metadata-enhanced Audio Transmission */ MAT = 0x24000000UL, + AAC_LATM = 0x25000000UL, + CELT = 0x26000000UL, + APTX_ADAPTIVE = 0x27000000UL, + LHDC = 0x28000000UL, + LHDC_LL = 0x29000000UL, + /** Deprecated */ MAIN_MASK = 0xFF000000UL, SUB_MASK = 0x00FFFFFFUL, @@ -293,6 +312,9 @@ enum AudioFormat : uint32_t { MAT_1_0 = (MAT | MAT_SUB_1_0), MAT_2_0 = (MAT | MAT_SUB_2_0), MAT_2_1 = (MAT | MAT_SUB_2_1), + AAC_LATM_LC = (AAC_LATM | AAC_SUB_LC), + AAC_LATM_HE_V1 = (AAC_LATM | AAC_SUB_HE_V1), + AAC_LATM_HE_V2 = (AAC_LATM | AAC_SUB_HE_V2), }; /** @@ -376,6 +398,16 @@ enum AudioChannelMask : uint32_t { OUT_TOP_SIDE_LEFT = 0x40000, OUT_TOP_SIDE_RIGHT = 0x80000, + /** + * Haptic channel characteristics are specific to a device and + * only used to play device specific resources (eg: ringtones). + * The HAL can freely map A and B to haptic controllers, the + * framework shall not interpret those values and forward them + * from the device audio assets. + */ + OUT_HAPTIC_A = 0x20000000, + OUT_HAPTIC_B = 0x10000000, + OUT_MONO = OUT_FRONT_LEFT, OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT), OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY), @@ -423,6 +455,12 @@ enum AudioChannelMask : uint32_t { OUT_7POINT1POINT4 = (OUT_7POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT), + OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A), + OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A), + OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B), + OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B), + OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_HAPTIC_A | OUT_HAPTIC_B), // Note that the 2.0 OUT_ALL* have been moved to helper functions /* These are bits only, not complete values */ @@ -580,12 +618,36 @@ enum AudioDevice : uint32_t { IN_PROXY = BIT_IN | 0x1000000, IN_USB_HEADSET = BIT_IN | 0x2000000, IN_BLUETOOTH_BLE = BIT_IN | 0x4000000, + IN_ECHO_REFERENCE = BIT_IN | 0x10000000, IN_DEFAULT = BIT_IN | BIT_DEFAULT, // Note that the 2.0 IN_ALL* have been moved to helper functions }; /** + * IEEE 802 MAC address. + */ +typedef uint8_t[6] MacAddress; + +/** + * Specifies a device address in case when several devices of the same type + * can be connected (e.g. BT A2DP, USB). + */ +struct DeviceAddress { + AudioDevice device; // discriminator + union Address { + MacAddress mac; // used for BLUETOOTH_A2DP_* + uint8_t[4] ipv4; // used for IP + struct Alsa { + int32_t card; + int32_t device; + } alsa; // used for USB_* + } address; + string busAddress; // used for BUS + string rSubmixAddress; // used for REMOTE_SUBMIX +}; + +/** * The audio output flags serve two purposes: * * - when an AudioTrack is created they indicate a "wish" to be connected to an @@ -732,9 +794,17 @@ struct RecordTrackMetadata { * Must not be negative. */ float gain; + /** + * Indicates the destination of an input stream, can be left unspecified. + */ + safe_union Destination { + Monostate unspecified; + DeviceAddress device; + }; + Destination destination; }; -/** Metadatas of the source of a StreamIn. */ +/** Metadatas of the sink of a StreamIn. */ struct SinkMetadata { vec<RecordTrackMetadata> tracks; }; diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp index 4a27bb76cb..c0bd34c45f 100644 --- a/audio/common/all-versions/default/Android.bp +++ b/audio/common/all-versions/default/Android.bp @@ -17,9 +17,6 @@ cc_library_shared { name: "android.hardware.audio.common-util", defaults: ["hidl_defaults"], vendor_available: true, - vndk: { - enabled: true, - }, srcs: [ "EffectMap.cpp", ], @@ -41,3 +38,72 @@ cc_library_shared { "android.hardware.audio.common.util@all-versions", ] } + +cc_defaults { + name: "android.hardware.audio.common-util_default", + defaults: ["hidl_defaults"], + + vendor_available: true, + srcs: [ + "HidlUtils.cpp", + ], + + export_include_dirs: ["."], + + shared_libs: [ + "liblog", + "libutils", + "libhidlbase", + "android.hardware.audio.common-util", + ], + export_shared_lib_headers: [ + "android.hardware.audio.common-util" + ], + + header_libs: [ + "libaudio_system_headers", + "libhardware_headers", + ], +} + +cc_library_shared { + name: "android.hardware.audio.common@2.0-util", + defaults: ["android.hardware.audio.common-util_default"], + + shared_libs: [ + "android.hardware.audio.common@2.0", + ], + cflags: [ + "-DMAJOR_VERSION=2", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_library_shared { + name: "android.hardware.audio.common@4.0-util", + defaults: ["android.hardware.audio.common-util_default"], + + shared_libs: [ + "android.hardware.audio.common@4.0", + ], + cflags: [ + "-DMAJOR_VERSION=4", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_library_shared { + name: "android.hardware.audio.common@5.0-util", + defaults: ["android.hardware.audio.common-util_default"], + + shared_libs: [ + "android.hardware.audio.common@5.0", + ], + cflags: [ + "-DMAJOR_VERSION=5", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} diff --git a/audio/common/all-versions/default/EffectMap.cpp b/audio/common/all-versions/default/EffectMap.cpp index 7f8da1e2ab..cb3e3d59d7 100644 --- a/audio/common/all-versions/default/EffectMap.cpp +++ b/audio/common/all-versions/default/EffectMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. diff --git a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h b/audio/common/all-versions/default/HidlUtils.cpp index 8ab73501bc..08002c8788 100644 --- a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h +++ b/audio/common/all-versions/default/HidlUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,36 +14,23 @@ * limitations under the License. */ -#ifndef AUDIO_HAL_VERSION -#error "AUDIO_HAL_VERSION must be set before including this file." -#endif +#include "HidlUtils.h" #include <common/all-versions/VersionUtils.h> #include <string.h> -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioGainMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMixLatencyClass; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortConfigMask; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortRole; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortType; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioStreamType; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioUsage; - -using ::android::hardware::audio::common::utils::mkEnumConverter; +using ::android::hardware::audio::common::utils::EnumBitfield; namespace android { namespace hardware { namespace audio { namespace common { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { +namespace implementation { void HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) { config->sampleRateHz = halConfig.sample_rate; - config->channelMask = mkEnumConverter<AudioChannelMask>(halConfig.channel_mask); + config->channelMask = EnumBitfield<AudioChannelMask>(halConfig.channel_mask); config->format = AudioFormat(halConfig.format); audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo); config->frameCount = halConfig.frame_count; @@ -61,8 +48,8 @@ void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halC void HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig, AudioGainConfig* config) { config->index = halConfig.index; - config->mode = mkEnumConverter<AudioGainMode>(halConfig.mode); - config->channelMask = mkEnumConverter<AudioChannelMask>(halConfig.channel_mask); + config->mode = EnumBitfield<AudioGainMode>(halConfig.mode); + config->channelMask = EnumBitfield<AudioChannelMask>(halConfig.channel_mask); for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) { config->values[i] = halConfig.values[i]; } @@ -82,8 +69,8 @@ void HidlUtils::audioGainConfigToHal(const AudioGainConfig& config, } void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) { - gain->mode = mkEnumConverter<AudioGainMode>(halGain.mode); - gain->channelMask = mkEnumConverter<AudioChannelMask>(halGain.channel_mask); + gain->mode = EnumBitfield<AudioGainMode>(halGain.mode); + gain->channelMask = EnumBitfield<AudioChannelMask>(halGain.channel_mask); gain->minValue = halGain.min_value; gain->maxValue = halGain.max_value; gain->defaultValue = halGain.default_value; @@ -122,7 +109,7 @@ audio_usage_t HidlUtils::audioUsageToHal(const AudioUsage usage) { void HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, AudioOffloadInfo* offload) { offload->sampleRateHz = halOffload.sample_rate; - offload->channelMask = mkEnumConverter<AudioChannelMask>(halOffload.channel_mask); + offload->channelMask = EnumBitfield<AudioChannelMask>(halOffload.channel_mask); offload->format = AudioFormat(halOffload.format); offload->streamType = AudioStreamType(halOffload.stream_type); offload->bitRatePerSecond = halOffload.bit_rate; @@ -155,9 +142,9 @@ void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig config->id = halConfig.id; config->role = AudioPortRole(halConfig.role); config->type = AudioPortType(halConfig.type); - config->configMask = mkEnumConverter<AudioPortConfigMask>(halConfig.config_mask); + config->configMask = EnumBitfield<AudioPortConfigMask>(halConfig.config_mask); config->sampleRateHz = halConfig.sample_rate; - config->channelMask = mkEnumConverter<AudioChannelMask>(halConfig.channel_mask); + config->channelMask = EnumBitfield<AudioChannelMask>(halConfig.channel_mask); config->format = AudioFormat(halConfig.format); audioGainConfigFromHal(halConfig.gain, &config->gain); switch (halConfig.type) { @@ -174,9 +161,9 @@ void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig config->ext.mix.hwModule = halConfig.ext.mix.hw_module; config->ext.mix.ioHandle = halConfig.ext.mix.handle; if (halConfig.role == AUDIO_PORT_ROLE_SOURCE) { - config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source); - } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) { config->ext.mix.useCase.stream = AudioStreamType(halConfig.ext.mix.usecase.stream); + } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) { + config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source); } break; } @@ -212,11 +199,11 @@ void HidlUtils::audioPortConfigToHal(const AudioPortConfig& config, halConfig->ext.mix.hw_module = config.ext.mix.hwModule; halConfig->ext.mix.handle = config.ext.mix.ioHandle; if (config.role == AudioPortRole::SOURCE) { - halConfig->ext.mix.usecase.source = - static_cast<audio_source_t>(config.ext.mix.useCase.source); - } else if (config.role == AudioPortRole::SINK) { halConfig->ext.mix.usecase.stream = static_cast<audio_stream_type_t>(config.ext.mix.useCase.stream); + } else if (config.role == AudioPortRole::SINK) { + halConfig->ext.mix.usecase.source = + static_cast<audio_source_t>(config.ext.mix.useCase.source); } break; } @@ -257,7 +244,7 @@ void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* po } port->channelMasks.resize(halPort.num_channel_masks); for (size_t i = 0; i < halPort.num_channel_masks; ++i) { - port->channelMasks[i] = mkEnumConverter<AudioChannelMask>(halPort.channel_masks[i]); + port->channelMasks[i] = EnumBitfield<AudioChannelMask>(halPort.channel_masks[i]); } port->formats.resize(halPort.num_formats); for (size_t i = 0; i < halPort.num_formats; ++i) { @@ -358,7 +345,8 @@ void HidlUtils::uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid) { memcpy(halUuid->node, uuid.node.data(), uuid.node.size()); } -} // namespace AUDIO_HAL_VERSION +} // namespace implementation +} // namespace CPP_VERSION } // namespace common } // namespace audio } // namespace hardware diff --git a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h index f9a5697418..758a7f43d1 100644 --- a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.h +++ b/audio/common/all-versions/default/HidlUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,28 +14,25 @@ * limitations under the License. */ -#ifndef AUDIO_HAL_VERSION -#error "AUDIO_HAL_VERSION must be set before including this file." -#endif +#ifndef android_hardware_audio_Hidl_Utils_H_ +#define android_hardware_audio_Hidl_Utils_H_ + +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) #include <memory> #include <system/audio.h> -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioConfig; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioGain; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioGainConfig; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioOffloadInfo; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPort; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortConfig; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::Uuid; using ::android::hardware::hidl_vec; namespace android { namespace hardware { namespace audio { namespace common { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { +namespace implementation { + +using namespace ::android::hardware::audio::common::CPP_VERSION; class HidlUtils { public: @@ -68,8 +65,11 @@ class HidlUtils { static void uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid); }; -} // namespace AUDIO_HAL_VERSION +} // namespace implementation +} // namespace CPP_VERSION } // namespace common } // namespace audio } // namespace hardware } // namespace android + +#endif // android_hardware_audio_Hidl_Utils_H_ diff --git a/audio/common/2.0/default/OWNERS b/audio/common/all-versions/default/OWNERS index 6fdc97ca29..6fdc97ca29 100644 --- a/audio/common/2.0/default/OWNERS +++ b/audio/common/all-versions/default/OWNERS diff --git a/audio/common/4.0/default/VersionUtils.h b/audio/common/all-versions/default/VersionUtils.h index b7f2aec8f9..e7755b1a7a 100644 --- a/audio/common/4.0/default/VersionUtils.h +++ b/audio/common/all-versions/default/VersionUtils.h @@ -17,22 +17,29 @@ #ifndef ANDROID_HARDWARE_AUDIO_EFFECT_VERSION_UTILS_H #define ANDROID_HARDWARE_AUDIO_EFFECT_VERSION_UTILS_H -#include <android/hardware/audio/common/4.0/types.h> +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) namespace android { namespace hardware { namespace audio { namespace common { -namespace V4_0 { +namespace CPP_VERSION { namespace implementation { -typedef hidl_bitfield<common::V4_0::AudioDevice> AudioDeviceBitfield; -typedef hidl_bitfield<common::V4_0::AudioChannelMask> AudioChannelBitfield; -typedef hidl_bitfield<common::V4_0::AudioOutputFlag> AudioOutputFlagBitfield; -typedef hidl_bitfield<common::V4_0::AudioInputFlag> AudioInputFlagBitfield; +#if MAJOR_VERSION == 2 +typedef common::CPP_VERSION::AudioDevice AudioDeviceBitfield; +typedef common::CPP_VERSION::AudioChannelMask AudioChannelBitfield; +typedef common::CPP_VERSION::AudioOutputFlag AudioOutputFlagBitfield; +typedef common::CPP_VERSION::AudioInputFlag AudioInputFlagBitfield; +#elif MAJOR_VERSION >= 4 +typedef hidl_bitfield<common::CPP_VERSION::AudioDevice> AudioDeviceBitfield; +typedef hidl_bitfield<common::CPP_VERSION::AudioChannelMask> AudioChannelBitfield; +typedef hidl_bitfield<common::CPP_VERSION::AudioOutputFlag> AudioOutputFlagBitfield; +typedef hidl_bitfield<common::CPP_VERSION::AudioInputFlag> AudioInputFlagBitfield; +#endif } // namespace implementation -} // namespace V4_0 +} // namespace CPP_VERSION } // namespace common } // namespace audio } // namespace hardware diff --git a/audio/common/all-versions/default/include/common/all-versions/default/EffectMap.h b/audio/common/all-versions/default/include/common/all-versions/default/EffectMap.h index 547c6d5a9f..7f630bf09e 100644 --- a/audio/common/all-versions/default/include/common/all-versions/default/EffectMap.h +++ b/audio/common/all-versions/default/include/common/all-versions/default/EffectMap.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. diff --git a/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk index 43d7fe19c5..58987c7810 100644 --- a/audio/common/all-versions/default/service/Android.mk +++ b/audio/common/all-versions/default/service/Android.mk @@ -31,21 +31,27 @@ LOCAL_SRC_FILES := \ LOCAL_CFLAGS := -Wall -Werror LOCAL_SHARED_LIBRARIES := \ + libcutils \ libbinder \ libhidlbase \ libhidltransport \ liblog \ libutils \ libhardware \ + libhwbinder \ android.hardware.audio@2.0 \ android.hardware.audio@4.0 \ + android.hardware.audio@5.0 \ android.hardware.audio.common@2.0 \ android.hardware.audio.common@4.0 \ + android.hardware.audio.common@5.0 \ android.hardware.audio.effect@2.0 \ android.hardware.audio.effect@4.0 \ + android.hardware.audio.effect@5.0 \ android.hardware.bluetooth.a2dp@1.0 \ android.hardware.soundtrigger@2.0 \ - android.hardware.soundtrigger@2.1 + android.hardware.soundtrigger@2.1 \ + android.hardware.soundtrigger@2.2 # Can not switch to Android.bp until AUDIOSERVER_MULTILIB # is deprecated as build config variable are not supported diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp index c7ce638e7f..15ce5e0bca 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -18,35 +18,51 @@ #include <android/hardware/audio/2.0/IDevicesFactory.h> #include <android/hardware/audio/4.0/IDevicesFactory.h> +#include <android/hardware/audio/5.0/IDevicesFactory.h> #include <android/hardware/audio/effect/2.0/IEffectsFactory.h> #include <android/hardware/audio/effect/4.0/IEffectsFactory.h> +#include <android/hardware/audio/effect/5.0/IEffectsFactory.h> #include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h> #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> #include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h> +#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h> #include <binder/ProcessState.h> +#include <cutils/properties.h> #include <hidl/HidlTransportSupport.h> #include <hidl/LegacySupport.h> +#include <hwbinder/ProcessState.h> using namespace android::hardware; using android::OK; int main(int /* argc */, char* /* argv */ []) { - android::ProcessState::initWithDriver("/dev/vndbinder"); + ::android::ProcessState::initWithDriver("/dev/vndbinder"); // start a threadpool for vndbinder interactions - android::ProcessState::self()->startThreadPool(); + ::android::ProcessState::self()->startThreadPool(); + + const int32_t defaultValue = -1; + int32_t value = + property_get_int32("persist.vendor.audio.service.hwbinder.size_kbyte", defaultValue); + if (value != defaultValue) { + ALOGD("Configuring hwbinder with mmap size %d KBytes", value); + ProcessState::initWithMmapSize(static_cast<size_t>(value) * 1024); + } configureRpcThreadpool(16, true /*callerWillJoin*/); - bool fail = registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK && + bool fail = registerPassthroughServiceImplementation<audio::V5_0::IDevicesFactory>() != OK && + registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK && registerPassthroughServiceImplementation<audio::V2_0::IDevicesFactory>() != OK; - LOG_ALWAYS_FATAL_IF(fail, "Could not register audio core API 2.0 nor 4.0"); + LOG_ALWAYS_FATAL_IF(fail, "Could not register audio core API 2, 4 nor 5"); - fail = registerPassthroughServiceImplementation<audio::effect::V4_0::IEffectsFactory>() != OK && + fail = registerPassthroughServiceImplementation<audio::effect::V5_0::IEffectsFactory>() != OK && + registerPassthroughServiceImplementation<audio::effect::V4_0::IEffectsFactory>() != OK && registerPassthroughServiceImplementation<audio::effect::V2_0::IEffectsFactory>() != OK, - LOG_ALWAYS_FATAL_IF(fail, "Could not register audio effect API 2.0 nor 4.0"); + LOG_ALWAYS_FATAL_IF(fail, "Could not register audio effect API 2, 4 nor 5"); - fail = registerPassthroughServiceImplementation<soundtrigger::V2_1::ISoundTriggerHw>() != OK && + fail = registerPassthroughServiceImplementation<soundtrigger::V2_2::ISoundTriggerHw>() != OK && + registerPassthroughServiceImplementation<soundtrigger::V2_1::ISoundTriggerHw>() != OK && registerPassthroughServiceImplementation<soundtrigger::V2_0::ISoundTriggerHw>() != OK, - ALOGW_IF(fail, "Could not register soundtrigger API 2.0 nor 2.1"); + ALOGW_IF(fail, "Could not register soundtrigger API 2.0, 2.1 nor 2.2"); fail = registerPassthroughServiceImplementation<bluetooth::a2dp::V1_0::IBluetoothAudioOffload>() != diff --git a/audio/common/all-versions/test/utility/include/utility/AssertOk.h b/audio/common/all-versions/test/utility/include/utility/AssertOk.h index 11e1c24783..5ac2fdc936 100644 --- a/audio/common/all-versions/test/utility/include/utility/AssertOk.h +++ b/audio/common/all-versions/test/utility/include/utility/AssertOk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. diff --git a/audio/common/all-versions/test/utility/include/utility/Documentation.h b/audio/common/all-versions/test/utility/include/utility/Documentation.h index e10cf79ecc..1b555b996a 100644 --- a/audio/common/all-versions/test/utility/include/utility/Documentation.h +++ b/audio/common/all-versions/test/utility/include/utility/Documentation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h index 7a08a54fc8..0e416f3c64 100644 --- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h +++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. diff --git a/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h b/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h index abc2ff5f82..3833fd072e 100644 --- a/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h +++ b/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -14,10 +14,6 @@ * limitations under the License. */ -#ifndef AUDIO_HAL_VERSION -#error "AUDIO_HAL_VERSION must be set before including this file." -#endif - #ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H #define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H @@ -40,19 +36,19 @@ namespace audio { #define DEFINE_GTEST_PRINT_TO(T) \ inline void PrintTo(const T& val, ::std::ostream* os) { *os << toString(val); } -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { DEFINE_GTEST_PRINT_TO(IPrimaryDevice::TtyMode) DEFINE_GTEST_PRINT_TO(Result) -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION namespace common { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { DEFINE_GTEST_PRINT_TO(AudioConfig) DEFINE_GTEST_PRINT_TO(AudioMode) DEFINE_GTEST_PRINT_TO(AudioDevice) DEFINE_GTEST_PRINT_TO(AudioFormat) DEFINE_GTEST_PRINT_TO(AudioChannelMask) -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace common #undef DEFINE_GTEST_PRINT_TO diff --git a/audio/common/all-versions/test/utility/include/utility/ReturnIn.h b/audio/common/all-versions/test/utility/include/utility/ReturnIn.h index 7fd0d4a437..de16809380 100644 --- a/audio/common/all-versions/test/utility/include/utility/ReturnIn.h +++ b/audio/common/all-versions/test/utility/include/utility/ReturnIn.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. diff --git a/audio/common/all-versions/test/utility/include/utility/ValidateXml.h b/audio/common/all-versions/test/utility/include/utility/ValidateXml.h index 91adfc12c8..ee206f7458 100644 --- a/audio/common/all-versions/test/utility/include/utility/ValidateXml.h +++ b/audio/common/all-versions/test/utility/include/utility/ValidateXml.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp index 1a906d668b..bdafa82d6b 100644 --- a/audio/common/all-versions/test/utility/src/ValidateXml.cpp +++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -162,8 +162,8 @@ template <bool atLeastOneRequired> << "\n Which is: " << xmlFileName << "\n In the following folders: " << xmlFileLocationsExpr << "\n Which is: " << ::testing::PrintToString(xmlFileLocations) - << (atLeastOneRequired ? "Where at least one file must be found." - : "Where no file might exist."); + << (atLeastOneRequired ? "\nWhere at least one file must be found." + : "\nWhere no file might exist."); } template ::testing::AssertionResult validateXmlMultipleLocations<true>(const char*, const char*, diff --git a/audio/common/all-versions/util/Android.bp b/audio/common/all-versions/util/Android.bp index 5d33a3a189..3c7e62e4e4 100644 --- a/audio/common/all-versions/util/Android.bp +++ b/audio/common/all-versions/util/Android.bp @@ -2,9 +2,6 @@ cc_library_headers { name: "android.hardware.audio.common.util@all-versions", defaults: ["hidl_defaults"], vendor_available: true, - vndk: { - enabled: true, - }, export_include_dirs: ["include"], } diff --git a/audio/common/all-versions/util/include/common/all-versions/IncludeGuard.h b/audio/common/all-versions/util/include/common/all-versions/IncludeGuard.h deleted file mode 100644 index 2d5481625c..0000000000 --- a/audio/common/all-versions/util/include/common/all-versions/IncludeGuard.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 AUDIO_HAL_VERSION -#error "AUDIO_HAL_VERSION must be set before including this file." -#endif diff --git a/audio/common/all-versions/util/include/common/all-versions/VersionMacro.h b/audio/common/all-versions/util/include/common/all-versions/VersionMacro.h new file mode 100644 index 0000000000..dc54cee206 --- /dev/null +++ b/audio/common/all-versions/util/include/common/all-versions/VersionMacro.h @@ -0,0 +1,43 @@ +/* + * 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 ANDROID_HARDWARE_VERSION_MACRO_H +#define ANDROID_HARDWARE_VERSION_MACRO_H + +#if !defined(MAJOR_VERSION) || !defined(MINOR_VERSION) +#error "MAJOR_VERSION and MINOR_VERSION must be defined" +#endif + +/** Allows macro expansion for x and add surrounding `<>`. + * Is intended to be used for version dependant includes as + * `#include` do not macro expand if starting with < or " + * Example usage: + * #include PATH(path/to/FILE_VERSION/file) + * @note: uses the implementation-define "Computed Includes" feature. + */ +#define PATH(x) <x> + +#define CONCAT_3(a, b, c) a##b##c +#define EXPAND_CONCAT_3(a, b, c) CONCAT_3(a, b, c) +/** The directory name of the version: <major>.<minor> */ +#define FILE_VERSION EXPAND_CONCAT_3(MAJOR_VERSION, ., MINOR_VERSION) + +#define CONCAT_4(a, b, c, d) a##b##c##d +#define EXPAND_CONCAT_4(a, b, c, d) CONCAT_4(a, b, c, d) +/** The c++ namespace of the version: V<major>_<minor> */ +#define CPP_VERSION EXPAND_CONCAT_4(V, MAJOR_VERSION, _, MINOR_VERSION) + +#endif // ANDROID_HARDWARE_VERSION_MACRO_H diff --git a/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h b/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h index 70c3d56a42..3b5c0fbc4f 100644 --- a/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h +++ b/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h @@ -26,36 +26,31 @@ namespace audio { namespace common { namespace utils { -/** Similar to static_cast but also casts to hidl_bitfield depending on - * return type inference (emulated through user-define conversion). - */ -template <class Source, class Destination = Source> -class EnumConverter { +/** Converting between a bitfield or itself. */ +template <class Enum> +class EnumBitfield { public: - static_assert(std::is_enum<Source>::value || std::is_enum<Destination>::value, - "Source or destination should be an enum"); + using Bitfield = ::android::hardware::hidl_bitfield<Enum>; - explicit EnumConverter(Source source) : mSource(source) {} + EnumBitfield(const EnumBitfield&) = default; + explicit EnumBitfield(Enum value) : mValue(value) {} + explicit EnumBitfield(Bitfield value) : EnumBitfield(static_cast<Enum>(value)) {} - operator Destination() const { return static_cast<Destination>(mSource); } + EnumBitfield& operator=(const EnumBitfield&) = default; + EnumBitfield& operator=(Enum value) { return *this = EnumBitfield{value}; } + EnumBitfield& operator=(Bitfield value) { return *this = EnumBitfield{value}; } - template <class = std::enable_if_t<std::is_enum<Destination>::value>> - operator ::android::hardware::hidl_bitfield<Destination>() { - return static_cast<std::underlying_type_t<Destination>>(mSource); - } + operator Enum() const { return mValue; } + operator Bitfield() const { return static_cast<Bitfield>(mValue); } private: - const Source mSource; + Enum mValue; }; -template <class Destination, class Source> -auto mkEnumConverter(Source source) { - return EnumConverter<Source, Destination>{source}; -} -/** Allows converting an enum to its bitfield or itself. */ +/** ATD way to create a EnumBitfield. */ template <class Enum> -EnumConverter<Enum> mkBitfield(Enum value) { - return EnumConverter<Enum>{value}; +EnumBitfield<Enum> mkEnumBitfield(Enum value) { + return EnumBitfield<Enum>{value}; } } // namespace utils diff --git a/audio/core/2.0/default/Android.bp b/audio/core/2.0/default/Android.bp deleted file mode 100644 index 625df74a88..0000000000 --- a/audio/core/2.0/default/Android.bp +++ /dev/null @@ -1,53 +0,0 @@ -cc_library_shared { - name: "android.hardware.audio@2.0-impl", - relative_install_path: "hw", - proprietary: true, - vendor: true, - srcs: [ - "Conversions.cpp", - "Device.cpp", - "DevicesFactory.cpp", - "ParametersUtil.cpp", - "PrimaryDevice.cpp", - "Stream.cpp", - "StreamIn.cpp", - "StreamOut.cpp", - ], - - cflags: [ - "-DAUDIO_HAL_VERSION_2_0", - ], - - defaults: ["hidl_defaults"], - - export_include_dirs: ["include"], - - shared_libs: [ - "libbase", - "libcutils", - "libfmq", - "libhardware", - "libhidlbase", - "libhidltransport", - "liblog", - "libutils", - "android.hardware.audio@2.0", - "android.hardware.audio.common@2.0", - "android.hardware.audio.common@2.0-util", - "android.hardware.audio.common-util", - ], - - header_libs: [ - "android.hardware.audio.common.util@all-versions", - "android.hardware.audio.core@all-versions-impl", - "libaudioclient_headers", - "libaudio_system_headers", - "libhardware_headers", - "libmedia_headers", - ], - - whole_static_libs: [ - "libmedia_helper", - ], - -} diff --git a/audio/core/2.0/default/Conversions.cpp b/audio/core/2.0/default/Conversions.cpp deleted file mode 100644 index 6c32090626..0000000000 --- a/audio/core/2.0/default/Conversions.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 "core/2.0/default/Conversions.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/Conversions.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/2.0/default/ParametersUtil.cpp b/audio/core/2.0/default/ParametersUtil.cpp deleted file mode 100644 index 963e291de0..0000000000 --- a/audio/core/2.0/default/ParametersUtil.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 "core/2.0/default/ParametersUtil.h" -#include "core/2.0/default/Util.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/ParametersUtil.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/2.0/default/PrimaryDevice.cpp b/audio/core/2.0/default/PrimaryDevice.cpp deleted file mode 100644 index decaa14658..0000000000 --- a/audio/core/2.0/default/PrimaryDevice.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "PrimaryDeviceHAL" - -#include "core/2.0/default/PrimaryDevice.h" -#include "core/2.0/default/Util.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/PrimaryDevice.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/2.0/default/Stream.cpp b/audio/core/2.0/default/Stream.cpp deleted file mode 100644 index 0863a7c399..0000000000 --- a/audio/core/2.0/default/Stream.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "StreamHAL" - -#include "core/2.0/default/Stream.h" -#include "common/all-versions/default/EffectMap.h" -#include "core/2.0/default/Conversions.h" -#include "core/2.0/default/Util.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/Stream.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/2.0/default/StreamIn.cpp b/audio/core/2.0/default/StreamIn.cpp deleted file mode 100644 index 2021df1c49..0000000000 --- a/audio/core/2.0/default/StreamIn.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "StreamInHAL" - -#include "core/2.0/default/StreamIn.h" -#include "core/2.0/default/Util.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/StreamIn.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/2.0/default/StreamOut.cpp b/audio/core/2.0/default/StreamOut.cpp deleted file mode 100644 index 940a251272..0000000000 --- a/audio/core/2.0/default/StreamOut.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "StreamOutHAL" - -#include "core/2.0/default/StreamOut.h" -#include "core/2.0/default/Util.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/StreamOut.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/2.0/default/include/core/2.0/default/Device.h b/audio/core/2.0/default/include/core/2.0/default/Device.h deleted file mode 100644 index 3ec74649ec..0000000000 --- a/audio/core/2.0/default/include/core/2.0/default/Device.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H -#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H - -#include <android/hardware/audio/2.0/IDevice.h> - -#include "ParametersUtil.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/Device.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H diff --git a/audio/core/2.0/default/include/core/2.0/default/DevicesFactory.h b/audio/core/2.0/default/include/core/2.0/default/DevicesFactory.h deleted file mode 100644 index 8e8ee88ffa..0000000000 --- a/audio/core/2.0/default/include/core/2.0/default/DevicesFactory.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H -#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H - -#include <android/hardware/audio/2.0/IDevicesFactory.h> - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/DevicesFactory.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H diff --git a/audio/core/2.0/default/include/core/2.0/default/ParametersUtil.h b/audio/core/2.0/default/include/core/2.0/default/ParametersUtil.h deleted file mode 100644 index a5c1c78f94..0000000000 --- a/audio/core/2.0/default/include/core/2.0/default/ParametersUtil.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V2_0_PARAMETERS_UTIL_H_ -#define ANDROID_HARDWARE_AUDIO_V2_0_PARAMETERS_UTIL_H_ - -#include <android/hardware/audio/2.0/types.h> - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/ParametersUtil.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_PARAMETERS_UTIL_H_ diff --git a/audio/core/2.0/default/include/core/2.0/default/PrimaryDevice.h b/audio/core/2.0/default/include/core/2.0/default/PrimaryDevice.h deleted file mode 100644 index f89859700a..0000000000 --- a/audio/core/2.0/default/include/core/2.0/default/PrimaryDevice.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H -#define ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H - -#include <android/hardware/audio/2.0/IPrimaryDevice.h> - -#include "Device.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/PrimaryDevice.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H diff --git a/audio/core/2.0/default/include/core/2.0/default/Stream.h b/audio/core/2.0/default/include/core/2.0/default/Stream.h deleted file mode 100644 index a2d845609c..0000000000 --- a/audio/core/2.0/default/include/core/2.0/default/Stream.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H -#define ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H - -#include <android/hardware/audio/2.0/IStream.h> - -#include "ParametersUtil.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/Stream.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H diff --git a/audio/core/2.0/default/include/core/2.0/default/StreamIn.h b/audio/core/2.0/default/include/core/2.0/default/StreamIn.h deleted file mode 100644 index c36abbd68e..0000000000 --- a/audio/core/2.0/default/include/core/2.0/default/StreamIn.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H -#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H - -#include <android/hardware/audio/2.0/IStreamIn.h> - -#include "Device.h" -#include "Stream.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/StreamIn.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H diff --git a/audio/core/2.0/default/include/core/2.0/default/StreamOut.h b/audio/core/2.0/default/include/core/2.0/default/StreamOut.h deleted file mode 100644 index ab35687414..0000000000 --- a/audio/core/2.0/default/include/core/2.0/default/StreamOut.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H -#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H - -#include <android/hardware/audio/2.0/IStreamOut.h> - -#include "Device.h" -#include "Stream.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/StreamOut.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H diff --git a/audio/core/2.0/vts/OWNERS b/audio/core/2.0/vts/OWNERS deleted file mode 100644 index 8711a9ff6a..0000000000 --- a/audio/core/2.0/vts/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -elaurent@google.com -krocard@google.com -mnaganov@google.com -yim@google.com -zhuoyao@google.com
\ No newline at end of file diff --git a/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp b/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp deleted file mode 100644 index bef0e8276c..0000000000 --- a/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 <unistd.h> -#include <string> - -#include "utility/ValidateXml.h" - -TEST(CheckConfig, audioPolicyConfigurationValidation) { - RecordProperty("description", - "Verify that the audio policy configuration file " - "is valid according to the schema"); - - std::vector<const char*> locations = {"/odm/etc", "/vendor/etc", "/system/etc"}; - EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations, - "/data/local/tmp/audio_policy_configuration.xsd"); -} diff --git a/audio/core/4.0/default/Android.bp b/audio/core/4.0/default/Android.bp deleted file mode 100644 index 8e415459be..0000000000 --- a/audio/core/4.0/default/Android.bp +++ /dev/null @@ -1,53 +0,0 @@ -cc_library_shared { - name: "android.hardware.audio@4.0-impl", - relative_install_path: "hw", - proprietary: true, - vendor: true, - srcs: [ - "Conversions.cpp", - "Device.cpp", - "DevicesFactory.cpp", - "ParametersUtil.cpp", - "PrimaryDevice.cpp", - "Stream.cpp", - "StreamIn.cpp", - "StreamOut.cpp", - ], - - cflags: [ - "-DAUDIO_HAL_VERSION_4_0", - ], - - defaults: ["hidl_defaults"], - - export_include_dirs: ["include"], - - shared_libs: [ - "libbase", - "libcutils", - "libfmq", - "libhardware", - "libhidlbase", - "libhidltransport", - "liblog", - "libutils", - "android.hardware.audio@4.0", - "android.hardware.audio.common@4.0", - "android.hardware.audio.common@4.0-util", - "android.hardware.audio.common-util", - ], - - header_libs: [ - "android.hardware.audio.common.util@all-versions", - "android.hardware.audio.core@all-versions-impl", - "libaudioclient_headers", - "libaudio_system_headers", - "libhardware_headers", - "libmedia_headers", - ], - - whole_static_libs: [ - "libmedia_helper", - ], - -} diff --git a/audio/core/4.0/default/Conversions.cpp b/audio/core/4.0/default/Conversions.cpp deleted file mode 100644 index 4f1874412c..0000000000 --- a/audio/core/4.0/default/Conversions.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 "core/4.0/default/Conversions.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/Conversions.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/4.0/default/Device.cpp b/audio/core/4.0/default/Device.cpp deleted file mode 100644 index b33434ecfb..0000000000 --- a/audio/core/4.0/default/Device.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "DeviceHAL" - -#include "core/4.0/default/Device.h" -#include <HidlUtils.h> -#include "core/4.0/default/Conversions.h" -#include "core/4.0/default/StreamIn.h" -#include "core/4.0/default/StreamOut.h" -#include "core/4.0/default/Util.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/Device.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/4.0/default/DevicesFactory.cpp b/audio/core/4.0/default/DevicesFactory.cpp deleted file mode 100644 index cb8a3c3e97..0000000000 --- a/audio/core/4.0/default/DevicesFactory.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "DevicesFactoryHAL" - -#include "core/4.0/default/DevicesFactory.h" -#include "core/4.0/default/Device.h" -#include "core/4.0/default/PrimaryDevice.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/DevicesFactory.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/4.0/default/OWNERS b/audio/core/4.0/default/OWNERS deleted file mode 100644 index 6fdc97ca29..0000000000 --- a/audio/core/4.0/default/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -elaurent@google.com -krocard@google.com -mnaganov@google.com diff --git a/audio/core/4.0/default/ParametersUtil.cpp b/audio/core/4.0/default/ParametersUtil.cpp deleted file mode 100644 index 2cc9fb56a3..0000000000 --- a/audio/core/4.0/default/ParametersUtil.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 "core/4.0/default/ParametersUtil.h" -#include "core/4.0/default/Util.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/ParametersUtil.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/4.0/default/PrimaryDevice.cpp b/audio/core/4.0/default/PrimaryDevice.cpp deleted file mode 100644 index e3e49768d5..0000000000 --- a/audio/core/4.0/default/PrimaryDevice.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "PrimaryDeviceHAL" - -#include "core/4.0/default/PrimaryDevice.h" -#include "core/4.0/default/Util.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/PrimaryDevice.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/4.0/default/Stream.cpp b/audio/core/4.0/default/Stream.cpp deleted file mode 100644 index b8c71de7b7..0000000000 --- a/audio/core/4.0/default/Stream.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "StreamHAL" - -#include "core/4.0/default/Stream.h" -#include "common/all-versions/default/EffectMap.h" -#include "core/4.0/default/Conversions.h" -#include "core/4.0/default/Util.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/Stream.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/4.0/default/StreamIn.cpp b/audio/core/4.0/default/StreamIn.cpp deleted file mode 100644 index 718bd25a63..0000000000 --- a/audio/core/4.0/default/StreamIn.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "StreamInHAL" - -#include "core/4.0/default/StreamIn.h" -#include "core/4.0/default/Util.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/StreamIn.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/4.0/default/StreamOut.cpp b/audio/core/4.0/default/StreamOut.cpp deleted file mode 100644 index db88e401d2..0000000000 --- a/audio/core/4.0/default/StreamOut.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "StreamOutHAL" - -#include "core/4.0/default/StreamOut.h" -#include "core/4.0/default/Util.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/StreamOut.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/core/4.0/default/include/core/4.0/default/Conversions.h b/audio/core/4.0/default/include/core/4.0/default/Conversions.h deleted file mode 100644 index 32c2f887ee..0000000000 --- a/audio/core/4.0/default/include/core/4.0/default/Conversions.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V4_0_CONVERSIONS_H_ -#define ANDROID_HARDWARE_AUDIO_V4_0_CONVERSIONS_H_ - -#include <android/hardware/audio/4.0/types.h> - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/Conversions.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_CONVERSIONS_H_ diff --git a/audio/core/4.0/default/include/core/4.0/default/Device.h b/audio/core/4.0/default/include/core/4.0/default/Device.h deleted file mode 100644 index 770d606720..0000000000 --- a/audio/core/4.0/default/include/core/4.0/default/Device.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V4_0_DEVICE_H -#define ANDROID_HARDWARE_AUDIO_V4_0_DEVICE_H - -#include <android/hardware/audio/4.0/IDevice.h> - -#include "ParametersUtil.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/Device.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_DEVICE_H diff --git a/audio/core/4.0/default/include/core/4.0/default/DevicesFactory.h b/audio/core/4.0/default/include/core/4.0/default/DevicesFactory.h deleted file mode 100644 index 200e59d96f..0000000000 --- a/audio/core/4.0/default/include/core/4.0/default/DevicesFactory.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V4_0_DEVICESFACTORY_H -#define ANDROID_HARDWARE_AUDIO_V4_0_DEVICESFACTORY_H - -#include <android/hardware/audio/4.0/IDevicesFactory.h> - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/DevicesFactory.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_DEVICESFACTORY_H diff --git a/audio/core/4.0/default/include/core/4.0/default/ParametersUtil.h b/audio/core/4.0/default/include/core/4.0/default/ParametersUtil.h deleted file mode 100644 index fa31ee9dd3..0000000000 --- a/audio/core/4.0/default/include/core/4.0/default/ParametersUtil.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V4_0_PARAMETERS_UTIL_H_ -#define ANDROID_HARDWARE_AUDIO_V4_0_PARAMETERS_UTIL_H_ - -#include <android/hardware/audio/4.0/types.h> - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/ParametersUtil.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_PARAMETERS_UTIL_H_ diff --git a/audio/core/4.0/default/include/core/4.0/default/PrimaryDevice.h b/audio/core/4.0/default/include/core/4.0/default/PrimaryDevice.h deleted file mode 100644 index e7f846b622..0000000000 --- a/audio/core/4.0/default/include/core/4.0/default/PrimaryDevice.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V4_0_PRIMARYDEVICE_H -#define ANDROID_HARDWARE_AUDIO_V4_0_PRIMARYDEVICE_H - -#include <android/hardware/audio/4.0/IPrimaryDevice.h> - -#include "Device.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/PrimaryDevice.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_PRIMARYDEVICE_H diff --git a/audio/core/4.0/default/include/core/4.0/default/Stream.h b/audio/core/4.0/default/include/core/4.0/default/Stream.h deleted file mode 100644 index afad80fe53..0000000000 --- a/audio/core/4.0/default/include/core/4.0/default/Stream.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V4_0_STREAM_H -#define ANDROID_HARDWARE_AUDIO_V4_0_STREAM_H - -#include <android/hardware/audio/4.0/IStream.h> - -#include "ParametersUtil.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/Stream.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_STREAM_H diff --git a/audio/core/4.0/default/include/core/4.0/default/StreamIn.h b/audio/core/4.0/default/include/core/4.0/default/StreamIn.h deleted file mode 100644 index 151f03fc2b..0000000000 --- a/audio/core/4.0/default/include/core/4.0/default/StreamIn.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V4_0_STREAMIN_H -#define ANDROID_HARDWARE_AUDIO_V4_0_STREAMIN_H - -#include <android/hardware/audio/4.0/IStreamIn.h> - -#include "Device.h" -#include "Stream.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/StreamIn.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_STREAMIN_H diff --git a/audio/core/4.0/default/include/core/4.0/default/StreamOut.h b/audio/core/4.0/default/include/core/4.0/default/StreamOut.h deleted file mode 100644 index dbf3bd16ce..0000000000 --- a/audio/core/4.0/default/include/core/4.0/default/StreamOut.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_V4_0_STREAMOUT_H -#define ANDROID_HARDWARE_AUDIO_V4_0_STREAMOUT_H - -#include <android/hardware/audio/4.0/IStreamOut.h> - -#include "Device.h" -#include "Stream.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/StreamOut.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_STREAMOUT_H diff --git a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp deleted file mode 100644 index 8a8338bb43..0000000000 --- a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp +++ /dev/null @@ -1,1554 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "VtsHalAudioV4_0TargetTest" - -#include <algorithm> -#include <cmath> -#include <cstddef> -#include <cstdio> -#include <initializer_list> -#include <limits> -#include <list> -#include <string> -#include <vector> - -#include <fcntl.h> -#include <unistd.h> - -#include <hwbinder/IPCThreadState.h> - -#include <VtsHalHidlTargetTestBase.h> - -#include <android-base/logging.h> - -#include <android/hardware/audio/4.0/IDevice.h> -#include <android/hardware/audio/4.0/IDevicesFactory.h> -#include <android/hardware/audio/4.0/IPrimaryDevice.h> -#include <android/hardware/audio/4.0/types.h> -#include <android/hardware/audio/common/4.0/types.h> -#include <fmq/EventFlag.h> -#include <fmq/MessageQueue.h> - -#include <common/all-versions/VersionUtils.h> - -#include "utility/AssertOk.h" -#include "utility/Documentation.h" -#include "utility/EnvironmentTearDown.h" -#define AUDIO_HAL_VERSION V4_0 -#include "utility/PrettyPrintAudioTypes.h" -#include "utility/ReturnIn.h" - -using std::initializer_list; -using std::string; -using std::to_string; -using std::vector; -using std::list; - -using ::android::sp; -using ::android::hardware::EventFlag; -using ::android::hardware::hidl_bitfield; -using ::android::hardware::hidl_enum_range; -using ::android::hardware::hidl_handle; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::kSynchronizedReadWrite; -using ::android::hardware::IPCThreadState; -using ::android::hardware::MessageQueue; -using ::android::hardware::MQDescriptorSync; -using ::android::hardware::Return; -using ::android::hardware::audio::V4_0::AudioDrain; -using ::android::hardware::audio::V4_0::DeviceAddress; -using ::android::hardware::audio::V4_0::IDevice; -using ::android::hardware::audio::V4_0::IPrimaryDevice; -using Rotation = ::android::hardware::audio::V4_0::IPrimaryDevice::Rotation; -using TtyMode = ::android::hardware::audio::V4_0::IPrimaryDevice::TtyMode; -using ::android::hardware::audio::V4_0::IDevicesFactory; -using ::android::hardware::audio::V4_0::IStream; -using ::android::hardware::audio::V4_0::IStreamIn; -using ::android::hardware::audio::V4_0::MessageQueueFlagBits; -using ::android::hardware::audio::V4_0::TimeSpec; -using ReadParameters = ::android::hardware::audio::V4_0::IStreamIn::ReadParameters; -using ReadStatus = ::android::hardware::audio::V4_0::IStreamIn::ReadStatus; -using ::android::hardware::audio::V4_0::IStreamOut; -using ::android::hardware::audio::V4_0::IStreamOutCallback; -using ::android::hardware::audio::V4_0::MicrophoneInfo; -using ::android::hardware::audio::V4_0::MmapBufferInfo; -using ::android::hardware::audio::V4_0::MmapPosition; -using ::android::hardware::audio::V4_0::ParameterValue; -using ::android::hardware::audio::V4_0::Result; -using ::android::hardware::audio::V4_0::SourceMetadata; -using ::android::hardware::audio::V4_0::SinkMetadata; -using ::android::hardware::audio::common::V4_0::AudioChannelMask; -using ::android::hardware::audio::common::V4_0::AudioConfig; -using ::android::hardware::audio::common::V4_0::AudioContentType; -using ::android::hardware::audio::common::V4_0::AudioDevice; -using ::android::hardware::audio::common::V4_0::AudioFormat; -using ::android::hardware::audio::common::V4_0::AudioHandleConsts; -using ::android::hardware::audio::common::V4_0::AudioHwSync; -using ::android::hardware::audio::common::V4_0::AudioInputFlag; -using ::android::hardware::audio::common::V4_0::AudioIoHandle; -using ::android::hardware::audio::common::V4_0::AudioMode; -using ::android::hardware::audio::common::V4_0::AudioOffloadInfo; -using ::android::hardware::audio::common::V4_0::AudioOutputFlag; -using ::android::hardware::audio::common::V4_0::AudioSource; -using ::android::hardware::audio::common::V4_0::AudioUsage; -using ::android::hardware::audio::common::V4_0::ThreadInfo; -using ::android::hardware::audio::common::utils::mkBitfield; - -using namespace ::android::hardware::audio::common::test::utility; - -// Typical accepted results from interface methods -static auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED}; -static auto okOrNotSupportedOrInvalidArgs = {Result::OK, Result::NOT_SUPPORTED, - Result::INVALID_ARGUMENTS}; -static auto okOrInvalidStateOrNotSupported = {Result::OK, Result::INVALID_STATE, - Result::NOT_SUPPORTED}; -static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED}; -static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED}; - -class AudioHidlTestEnvironment : public ::Environment { - public: - virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); } -}; - -// Instance to register global tearDown -static AudioHidlTestEnvironment* environment; - -class HidlTest : public ::testing::VtsHalHidlTargetTestBase { - protected: - // Convenient member to store results - Result res; -}; - -////////////////////////////////////////////////////////////////////////////// -////////////////////// getService audio_devices_factory ////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// Test all audio devices -class AudioHidlTest : public HidlTest { - public: - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base - - if (devicesFactory == nullptr) { - environment->registerTearDown([] { devicesFactory.clear(); }); - devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>( - environment->getServiceName<IDevicesFactory>("default")); - } - ASSERT_TRUE(devicesFactory != nullptr); - } - - protected: - // Cache the devicesFactory retrieval to speed up each test by ~0.5s - static sp<IDevicesFactory> devicesFactory; -}; -sp<IDevicesFactory> AudioHidlTest::devicesFactory; - -TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) { - doc::test("Test the getService (called in SetUp)"); -} - -TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) { - doc::test("Test passing an invalid parameter to openDevice"); - Result result; - sp<IDevice> device; - ASSERT_OK(devicesFactory->openDevice("Non existing device", returnIn(result, device))); - ASSERT_EQ(Result::INVALID_ARGUMENTS, result); - ASSERT_TRUE(device == nullptr); -} - -TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { - doc::test("Calling openDevice(\"primary\") should return the primary device."); - { - Result result; - sp<IDevice> baseDevice; - ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice))); - ASSERT_OK(result); - ASSERT_TRUE(baseDevice != nullptr); - - Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice); - ASSERT_TRUE(primaryDevice.isOk()); - ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr); - } // Destroy local IDevice proxy - // FIXME: there is no way to know when the remote IDevice is being destroyed - // Binder does not support testing if an object is alive, thus - // wait for 100ms to let the binder destruction propagates and - // the remote device has the time to be destroyed. - // flushCommand makes sure all local command are sent, thus should reduce - // the latency between local and remote destruction. - IPCThreadState::self()->flushCommands(); - usleep(100); -} - -////////////////////////////////////////////////////////////////////////////// -/////////////////////////////// openDevice primary /////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// Test the primary device -class AudioPrimaryHidlTest : public AudioHidlTest { - public: - /** Primary HAL test are NOT thread safe. */ - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base - - if (device == nullptr) { - Result result; - ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device))); - ASSERT_OK(result); - ASSERT_TRUE(device != nullptr); - - environment->registerTearDown([] { device.clear(); }); - } - } - - protected: - // Cache the device opening to speed up each test by ~0.5s - static sp<IPrimaryDevice> device; -}; -sp<IPrimaryDevice> AudioPrimaryHidlTest::device; - -TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) { - doc::test("Test the openDevice (called in SetUp)"); -} - -TEST_F(AudioPrimaryHidlTest, Init) { - doc::test("Test that the audio primary hal initialized correctly"); - ASSERT_OK(device->initCheck()); -} - -////////////////////////////////////////////////////////////////////////////// -///////////////////// {set,get}{Master,Mic}{Mute,Volume} ///////////////////// -////////////////////////////////////////////////////////////////////////////// - -template <class Property> -class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { - protected: - enum Optionality { REQUIRED, OPTIONAL }; - struct Initial { // Initial property value - Initial(Property value, Optionality check = REQUIRED) : value(value), check(check) {} - Property value; - Optionality check; // If this initial value should be checked - }; - /** Test a property getter and setter. - * The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL. - */ - template <Optionality optionality = REQUIRED, class Getter, class Setter> - void testAccessors(const string& propertyName, const Initial expectedInitial, - list<Property> valuesToTest, Setter setter, Getter getter, - const vector<Property>& invalidValues = {}) { - const auto expectedResults = {Result::OK, - optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK}; - - Property initialValue = expectedInitial.value; - ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue))); - ASSERT_RESULT(expectedResults, res); - if (res == Result::OK && expectedInitial.check == REQUIRED) { - EXPECT_EQ(expectedInitial.value, initialValue); - } - - valuesToTest.push_front(expectedInitial.value); - valuesToTest.push_back(initialValue); - for (Property setValue : valuesToTest) { - SCOPED_TRACE("Test " + propertyName + " getter and setter for " + - testing::PrintToString(setValue)); - auto ret = (device.get()->*setter)(setValue); - ASSERT_RESULT(expectedResults, ret); - if (ret == Result::NOT_SUPPORTED) { - doc::partialTest(propertyName + " setter is not supported"); - break; - } - Property getValue; - // Make sure the getter returns the same value just set - ASSERT_OK((device.get()->*getter)(returnIn(res, getValue))); - ASSERT_RESULT(expectedResults, res); - if (res == Result::NOT_SUPPORTED) { - doc::partialTest(propertyName + " getter is not supported"); - continue; - } - EXPECT_EQ(setValue, getValue); - } - - for (Property invalidValue : invalidValues) { - SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " + - testing::PrintToString(invalidValue)); - EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue)); - } - - // Restore initial value - EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue)); - } -}; - -using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>; - -TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) { - doc::test("Check that the mic can be muted and unmuted"); - testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute); - // TODO: check that the mic is really muted (all sample are 0) -} - -TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) { - doc::test("If master mute is supported, try to mute and unmute the master output"); - testAccessors<OPTIONAL>("master mute", Initial{false}, {true}, &IDevice::setMasterMute, - &IDevice::getMasterMute); - // TODO: check that the master volume is really muted -} - -using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>; -TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { - doc::test("Test the master volume if supported"); - testAccessors<OPTIONAL>( - "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, - {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()}); - // TODO: check that the master volume is really changed -} - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////////// AudioPatches //////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest { - protected: - bool areAudioPatchesSupported() { - auto result = device->supportsAudioPatches(); - EXPECT_IS_OK(result); - return result; - } -}; - -TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { - doc::test("Test if audio patches are supported"); - if (!areAudioPatchesSupported()) { - doc::partialTest("Audio patches are not supported"); - return; - } - // TODO: test audio patches -} - -////////////////////////////////////////////////////////////////////////////// -//////////////// Required and recommended audio format support /////////////// -// From: -// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording -// From: -// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback -/////////// TODO: move to the beginning of the file for easier update //////// -////////////////////////////////////////////////////////////////////////////// - -class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { - public: - // Cache result ? - static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() { - return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, - {8000, 11025, 16000, 22050, 32000, 44100}, - {AudioFormat::PCM_16_BIT}); - } - - static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() { - return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, - {24000, 48000}, {AudioFormat::PCM_16_BIT}); - } - - static const vector<AudioConfig> getSupportedPlaybackAudioConfig() { - // TODO: retrieve audio config supported by the platform - // as declared in the policy configuration - return {}; - } - - static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() { - return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100}, - {AudioFormat::PCM_16_BIT}); - } - static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() { - return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000}, - {AudioFormat::PCM_16_BIT}); - } - static const vector<AudioConfig> getSupportedCaptureAudioConfig() { - // TODO: retrieve audio config supported by the platform - // as declared in the policy configuration - return {}; - } - - private: - static const vector<AudioConfig> combineAudioConfig(vector<AudioChannelMask> channelMasks, - vector<uint32_t> sampleRates, - vector<AudioFormat> formats) { - vector<AudioConfig> configs; - for (auto channelMask : channelMasks) { - for (auto sampleRate : sampleRates) { - for (auto format : formats) { - AudioConfig config{}; - // leave offloadInfo to 0 - config.channelMask = mkBitfield(channelMask); - config.sampleRateHz = sampleRate; - config.format = format; - // FIXME: leave frameCount to 0 ? - configs.push_back(config); - } - } - } - return configs; - } -}; - -/** Generate a test name based on an audio config. - * - * As the only parameter changing are channel mask and sample rate, - * only print those ones in the test name. - */ -static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) { - const AudioConfig& config = info.param; - return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" + - // "MONO" is more clear than "FRONT_LEFT" - ((config.channelMask == mkBitfield(AudioChannelMask::OUT_MONO) || - config.channelMask == mkBitfield(AudioChannelMask::IN_MONO)) - ? "MONO" - : ::testing::PrintToString(config.channelMask)); -} - -////////////////////////////////////////////////////////////////////////////// -///////////////////////////// getInputBufferSize ///////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// FIXME: execute input test only if platform declares -// android.hardware.microphone -// how to get this value ? is it a property ??? - -class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest, - public ::testing::WithParamInterface<AudioConfig> { - protected: - void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) { - uint64_t bufferSize; - ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize))); - - switch (res) { - case Result::INVALID_ARGUMENTS: - EXPECT_FALSE(supportRequired); - break; - case Result::OK: - // Check that the buffer is of a sane size - // For now only that it is > 0 - EXPECT_GT(bufferSize, uint64_t(0)); - break; - default: - FAIL() << "Invalid return status: " << ::testing::PrintToString(res); - } - } -}; - -// Test that the required capture config and those declared in the policy are -// indeed supported -class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {}; -TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) { - doc::test( - "Input buffer size must be retrievable for a format with required " - "support."); - inputBufferSizeTest(GetParam(), true); -} -INSTANTIATE_TEST_CASE_P( - RequiredInputBufferSize, RequiredInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()), - &generateTestName); -INSTANTIATE_TEST_CASE_P( - SupportedInputBufferSize, RequiredInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()), - &generateTestName); - -// Test that the recommended capture config are supported or lead to a -// INVALID_ARGUMENTS return -class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {}; -TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { - doc::test( - "Input buffer size should be retrievable for a format with recommended " - "support."); - inputBufferSizeTest(GetParam(), false); -} -INSTANTIATE_TEST_CASE_P( - RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()), - &generateTestName); - -////////////////////////////////////////////////////////////////////////////// -/////////////////////////////// setScreenState /////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -TEST_F(AudioPrimaryHidlTest, setScreenState) { - doc::test("Check that the hal can receive the screen state"); - for (bool turnedOn : {false, true, true, false, false}) { - ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn)); - } -} - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////// {get,set}Parameters ///////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -TEST_F(AudioPrimaryHidlTest, getParameters) { - doc::test("Check that the hal can set and get parameters"); - hidl_vec<ParameterValue> context; - hidl_vec<hidl_string> keys; - hidl_vec<ParameterValue> values; - ASSERT_OK(device->getParameters(context, keys, returnIn(res, values))); - ASSERT_OK(device->setParameters(context, values)); - values.resize(0); - ASSERT_OK(device->setParameters(context, values)); -} - -////////////////////////////////////////////////////////////////////////////// -/////////////////////////// get(Active)Microphones /////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { - doc::test("Make sure getMicrophones always succeeds"); - hidl_vec<MicrophoneInfo> microphones; - ASSERT_OK(device->getMicrophones(returnIn(res, microphones))); - ASSERT_OK(res); - if (microphones.size() > 0) { - // When there is microphone on the phone, try to open an input stream - // and query for the active microphones. - doc::test( - "Make sure getMicrophones always succeeds" - "and getActiveMicrophones always succeeds when recording from these microphones."); - AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE; - AudioConfig config{}; - config.channelMask = mkBitfield(AudioChannelMask::IN_MONO); - config.sampleRateHz = 8000; - config.format = AudioFormat::PCM_16_BIT; - auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE); - const SinkMetadata initialMetadata = {{{AudioSource::MIC, 1 /* gain */}}}; - EventFlag* efGroup; - for (auto microphone : microphones) { - if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) { - continue; - } - sp<IStreamIn> stream; - AudioConfig suggestedConfig{}; - ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags, - initialMetadata, - returnIn(res, stream, suggestedConfig))); - if (res != Result::OK) { - ASSERT_TRUE(stream == nullptr); - AudioConfig suggestedConfigRetry{}; - ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, - suggestedConfig, flags, initialMetadata, - returnIn(res, stream, suggestedConfigRetry))); - } - ASSERT_OK(res); - hidl_vec<MicrophoneInfo> activeMicrophones; - Result readRes; - typedef MessageQueue<ReadParameters, kSynchronizedReadWrite> CommandMQ; - typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ; - std::unique_ptr<CommandMQ> commandMQ; - std::unique_ptr<DataMQ> dataMQ; - size_t frameSize = stream->getFrameSize(); - size_t frameCount = stream->getBufferSize() / frameSize; - ASSERT_OK(stream->prepareForReading( - frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto&) { - readRes = r; - if (readRes == Result::OK) { - commandMQ.reset(new CommandMQ(c)); - dataMQ.reset(new DataMQ(d)); - if (dataMQ->isValid() && dataMQ->getEventFlagWord()) { - EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup); - } - } - })); - ASSERT_OK(readRes); - ReadParameters params; - params.command = IStreamIn::ReadCommand::READ; - ASSERT_TRUE(commandMQ != nullptr); - ASSERT_TRUE(commandMQ->isValid()); - ASSERT_TRUE(commandMQ->write(¶ms)); - efGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); - uint32_t efState = 0; - efGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); - if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) { - ASSERT_OK(stream->getActiveMicrophones(returnIn(res, activeMicrophones))); - ASSERT_OK(res); - ASSERT_NE(0U, activeMicrophones.size()); - } - stream->close(); - if (efGroup) { - EventFlag::deleteEventFlag(&efGroup); - } - } - } -} - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////////// debugDebug ////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -template <class DebugDump> -static void testDebugDump(DebugDump debugDump) { - // File descriptors to our pipe. fds[0] corresponds to the read end and - // fds[1] to the write end. - int fds[2]; - ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno; - - // Make sure that the pipe is at least 1 MB in size. The test process runs - // in su domain, so it should be safe to make this call. - fcntl(fds[0], F_SETPIPE_SZ, 1 << 20); - - // Wrap the temporary file file descriptor in a native handle - auto* nativeHandle = native_handle_create(1, 0); - ASSERT_NE(nullptr, nativeHandle); - nativeHandle->data[0] = fds[1]; - - // Wrap this native handle in a hidl handle - hidl_handle handle; - handle.setTo(nativeHandle, false /*take ownership*/); - - ASSERT_OK(debugDump(handle)); - - // Check that at least one bit was written by the hal - // TODO: debugDump does not return a Result. - // This mean that the hal can not report that it not implementing the - // function. - char buff; - if (read(fds[0], &buff, 1) != 1) { - doc::note("debugDump does not seem implemented"); - } - EXPECT_EQ(0, close(fds[0])) << errno; - EXPECT_EQ(0, close(fds[1])) << errno; -} - -TEST_F(AudioPrimaryHidlTest, DebugDump) { - doc::test("Check that the hal can dump its state without error"); - testDebugDump([](const auto& handle) { return device->debug(handle, {/* options */}); }); -} - -TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { - doc::test("Check that the hal dump doesn't crash on invalid arguments"); - ASSERT_OK(device->debug(hidl_handle(), {/* options */})); -} - -TEST_F(AudioPrimaryHidlTest, SetConnectedState) { - doc::test("Check that the HAL can be notified of device connection and deconnection"); - using AD = AudioDevice; - for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { - SCOPED_TRACE("device=" + ::testing::PrintToString(deviceType)); - for (bool state : {true, false}) { - SCOPED_TRACE("state=" + ::testing::PrintToString(state)); - DeviceAddress address = {}; - address.device = deviceType; - auto ret = device->setConnectedState(address, state); - ASSERT_TRUE(ret.isOk()); - if (ret == Result::NOT_SUPPORTED) { - doc::partialTest("setConnectedState is not supported"); - return; - } - ASSERT_OK(ret); - } - } -} - -////////////////////////////////////////////////////////////////////////////// -////////////////////////// open{Output,Input}Stream ////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -template <class Stream> -class OpenStreamTest : public AudioConfigPrimaryTest, - public ::testing::WithParamInterface<AudioConfig> { - protected: - template <class Open> - void testOpen(Open openStream, const AudioConfig& config) { - // FIXME: Open a stream without an IOHandle - // This is not required to be accepted by hal implementations - AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE; - AudioConfig suggestedConfig{}; - ASSERT_OK(openStream(ioHandle, config, returnIn(res, stream, suggestedConfig))); - - // TODO: only allow failure for RecommendedPlaybackAudioConfig - switch (res) { - case Result::OK: - ASSERT_TRUE(stream != nullptr); - audioConfig = config; - break; - case Result::INVALID_ARGUMENTS: - ASSERT_TRUE(stream == nullptr); - AudioConfig suggestedConfigRetry; - // Could not open stream with config, try again with the - // suggested one - ASSERT_OK(openStream(ioHandle, suggestedConfig, - returnIn(res, stream, suggestedConfigRetry))); - // This time it must succeed - ASSERT_OK(res); - ASSERT_TRUE(stream != nullptr); - audioConfig = suggestedConfig; - break; - default: - FAIL() << "Invalid return status: " << ::testing::PrintToString(res); - } - open = true; - } - - Return<Result> closeStream() { - open = false; - return stream->close(); - } - - private: - void TearDown() override { - if (open) { - ASSERT_OK(stream->close()); - } - } - - protected: - AudioConfig audioConfig; - DeviceAddress address = {}; - sp<Stream> stream; - bool open = false; -}; - -////////////////////////////// openOutputStream ////////////////////////////// - -class OutputStreamTest : public OpenStreamTest<IStreamOut> { - virtual void SetUp() override { - ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base - address.device = AudioDevice::OUT_DEFAULT; - const AudioConfig& config = GetParam(); - // TODO: test all flag combination - auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE); - testOpen( - [&](AudioIoHandle handle, AudioConfig config, auto cb) { - return device->openOutputStream(handle, address, config, flags, initialMetadata, - cb); - }, - config); - } - - protected: - const SourceMetadata initialMetadata = { - {{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}}; -}; -TEST_P(OutputStreamTest, OpenOutputStreamTest) { - doc::test( - "Check that output streams can be open with the required and " - "recommended config"); - // Open done in SetUp -} -INSTANTIATE_TEST_CASE_P( - RequiredOutputStreamConfigSupport, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()), - &generateTestName); -INSTANTIATE_TEST_CASE_P( - SupportedOutputStreamConfig, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()), - &generateTestName); - -INSTANTIATE_TEST_CASE_P( - RecommendedOutputStreamConfigSupport, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()), - &generateTestName); - -////////////////////////////// openInputStream ////////////////////////////// - -class InputStreamTest : public OpenStreamTest<IStreamIn> { - virtual void SetUp() override { - ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base - address.device = AudioDevice::IN_DEFAULT; - const AudioConfig& config = GetParam(); - // TODO: test all supported flags and source - auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE); - testOpen( - [&](AudioIoHandle handle, AudioConfig config, auto cb) { - return device->openInputStream(handle, address, config, flags, initialMetadata, cb); - }, - config); - } - - protected: - const SinkMetadata initialMetadata = {{{AudioSource::DEFAULT, 1 /* gain */}}}; -}; - -TEST_P(InputStreamTest, OpenInputStreamTest) { - doc::test( - "Check that input streams can be open with the required and " - "recommended config"); - // Open done in setup -} -INSTANTIATE_TEST_CASE_P( - RequiredInputStreamConfigSupport, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()), - &generateTestName); -INSTANTIATE_TEST_CASE_P( - SupportedInputStreamConfig, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()), - &generateTestName); - -INSTANTIATE_TEST_CASE_P( - RecommendedInputStreamConfigSupport, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()), - &generateTestName); - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////// IStream getters /////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/** Unpack the provided result. - * If the result is not OK, register a failure and return an undefined value. */ -template <class R> -static R extract(Return<R> ret) { - if (!ret.isOk()) { - EXPECT_IS_OK(ret); - return R{}; - } - return ret; -} - -/* Could not find a way to write a test for two parametrized class fixure - * thus use this macro do duplicate tests for Input and Output stream */ -#define TEST_IO_STREAM(test_name, documentation, code) \ - TEST_P(InputStreamTest, test_name) { \ - doc::test(documentation); \ - code; \ - } \ - TEST_P(OutputStreamTest, test_name) { \ - doc::test(documentation); \ - code; \ - } - -TEST_IO_STREAM(GetFrameCount, "Check that getting stream frame count does not crash the HAL.", - ASSERT_TRUE(stream->getFrameCount().isOk())) - -TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with", - ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate()))) - -TEST_IO_STREAM(GetChannelMask, "Check that the stream channel mask == the one it was opened with", - ASSERT_EQ(audioConfig.channelMask, extract(stream->getChannelMask()))) - -TEST_IO_STREAM(GetFormat, "Check that the stream format == the one it was opened with", - ASSERT_EQ(audioConfig.format, extract(stream->getFormat()))) - -// TODO: for now only check that the framesize is not incoherent -TEST_IO_STREAM(GetFrameSize, "Check that the stream frame size == the one it was opened with", - ASSERT_GT(extract(stream->getFrameSize()), 0U)) - -TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it was opened with", - ASSERT_GE(extract(stream->getBufferSize()), extract(stream->getFrameSize()))); - -template <class Property, class CapablityGetter> -static void testCapabilityGetter(const string& name, IStream* stream, - CapablityGetter capablityGetter, - Return<Property> (IStream::*getter)(), - Return<Result> (IStream::*setter)(Property), - bool currentMustBeSupported = true) { - hidl_vec<Property> capabilities; - auto ret = capablityGetter(stream, capabilities); - if (ret == Result::NOT_SUPPORTED) { - doc::partialTest(name + " is not supported"); - return; - }; - ASSERT_OK(ret); - - if (currentMustBeSupported) { - ASSERT_NE(0U, capabilities.size()) << name << " must not return an empty list"; - Property currentValue = extract((stream->*getter)()); - EXPECT_TRUE(std::find(capabilities.begin(), capabilities.end(), currentValue) != - capabilities.end()) - << "value returned by " << name << "() = " << testing::PrintToString(currentValue) - << " is not in the list of the supported ones " << toString(capabilities); - } - - // Check that all declared supported values are indeed supported - for (auto capability : capabilities) { - auto ret = (stream->*setter)(capability); - ASSERT_TRUE(ret.isOk()); - if (ret == Result::NOT_SUPPORTED) { - doc::partialTest("Setter is not supported"); - return; - } - ASSERT_OK(ret); - ASSERT_EQ(capability, extract((stream->*getter)())); - } -} - -Result getSupportedSampleRates(IStream* stream, hidl_vec<uint32_t>& rates) { - Result res; - EXPECT_OK(stream->getSupportedSampleRates(extract(stream->getFormat()), returnIn(res, rates))); - return res; -} - -Result getSupportedChannelMasks(IStream* stream, - hidl_vec<hidl_bitfield<AudioChannelMask>>& channels) { - Result res; - EXPECT_OK( - stream->getSupportedChannelMasks(extract(stream->getFormat()), returnIn(res, channels))); - return res; -} - -Result getSupportedFormats(IStream* stream, hidl_vec<AudioFormat>& capabilities) { - EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities))); - // TODO: this should be an optional function - return Result::OK; -} - -TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported", - testCapabilityGetter("getSupportedSampleRate", stream.get(), - &getSupportedSampleRates, &IStream::getSampleRate, - &IStream::setSampleRate, - // getSupportedSampleRate returns the native sampling rates, - // (the sampling rates that can be played without resampling) - // but other sampling rates can be supported by the HAL. - false)) - -TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported", - testCapabilityGetter("getSupportedChannelMask", stream.get(), - &getSupportedChannelMasks, &IStream::getChannelMask, - &IStream::setChannelMask)) - -TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported", - testCapabilityGetter("getSupportedFormat", stream.get(), &getSupportedFormats, - &IStream::getFormat, &IStream::setFormat)) - -static void testGetDevices(IStream* stream, AudioDevice expectedDevice) { - hidl_vec<DeviceAddress> devices; - Result res; - ASSERT_OK(stream->getDevices(returnIn(res, devices))); - if (res == Result::NOT_SUPPORTED) { - return doc::partialTest("GetDevices is not supported"); - } - // The stream was constructed with one device, thus getDevices must only return one - ASSERT_EQ(1U, devices.size()); - AudioDevice device = devices[0].device; - ASSERT_TRUE(device == expectedDevice) - << "Expected: " << ::testing::PrintToString(expectedDevice) - << "\n Actual: " << ::testing::PrintToString(device); -} - -TEST_IO_STREAM(GetDevices, "Check that the stream device == the one it was opened with", - areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") - : testGetDevices(stream.get(), address.device)) - -static void testSetDevices(IStream* stream, const DeviceAddress& address) { - DeviceAddress otherAddress = address; - otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER - : AudioDevice::IN_BUILTIN_MIC; - EXPECT_OK(stream->setDevices({otherAddress})); - - ASSERT_OK(stream->setDevices({address})); // Go back to the original value -} - -TEST_IO_STREAM(SetDevices, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC", - areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") - : testSetDevices(stream.get(), address)) - -static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) { - uint32_t sampleRateHz; - hidl_bitfield<AudioChannelMask> mask; - AudioFormat format; - - stream->getAudioProperties(returnIn(sampleRateHz, mask, format)); - - // FIXME: the qcom hal it does not currently negotiate the sampleRate & - // channel mask - EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz); - EXPECT_EQ(expectedConfig.channelMask, mask); - EXPECT_EQ(expectedConfig.format, format); -} - -TEST_IO_STREAM(GetAudioProperties, - "Check that the stream audio properties == the ones it was opened with", - testGetAudioProperties(stream.get(), audioConfig)) - -TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value", - ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, stream->setHwAvSync(666))) - -static void checkGetHwAVSync(IDevice* device) { - Result res; - AudioHwSync sync; - ASSERT_OK(device->getHwAvSync(returnIn(res, sync))); - if (res == Result::NOT_SUPPORTED) { - return doc::partialTest("getHwAvSync is not supported"); - } - ASSERT_OK(res); -} -TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get())); - -static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys, - initializer_list<Result> expectedResults) { - hidl_vec<ParameterValue> context; - hidl_vec<ParameterValue> parameters; - Result res; - ASSERT_OK(stream->getParameters(context, keys, returnIn(res, parameters))); - ASSERT_RESULT(expectedResults, res); - if (res == Result::OK) { - for (auto& parameter : parameters) { - ASSERT_EQ(0U, parameter.value.size()) << toString(parameter); - } - } -} - -/* Get/Set parameter is intended to be an opaque channel between vendors app and - * their HALs. - * Thus can not be meaningfully tested. - */ -TEST_IO_STREAM(getEmptySetParameter, "Retrieve the values of an empty set", - checkGetNoParameter(stream.get(), {} /* keys */, {Result::OK})) - -TEST_IO_STREAM(getNonExistingParameter, "Retrieve the values of an non existing parameter", - checkGetNoParameter(stream.get(), {"Non existing key"} /* keys */, - {Result::NOT_SUPPORTED})) - -TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters", - ASSERT_RESULT(Result::OK, stream->setParameters({}, {}))) - -TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter", - // Unfortunately, the set_parameter legacy interface did not return any - // error code when a key is not supported. - // To allow implementation to just wrapped the legacy one, consider OK as a - // valid result for setting a non existing parameter. - ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, - stream->setParameters({}, {{"non existing key", "0"}}))) - -TEST_IO_STREAM(DebugDump, "Check that a stream can dump its state without error", - testDebugDump([this](const auto& handle) { return stream->debug(handle, {}); })) - -TEST_IO_STREAM(DebugDumpInvalidArguments, - "Check that the stream dump doesn't crash on invalid arguments", - ASSERT_OK(stream->debug(hidl_handle(), {}))) - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////// addRemoveEffect /////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -TEST_IO_STREAM(AddNonExistingEffect, "Adding a non existing effect should fail", - ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->addEffect(666))) -TEST_IO_STREAM(RemoveNonExistingEffect, "Removing a non existing effect should fail", - ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->removeEffect(666))) - -// TODO: positive tests - -////////////////////////////////////////////////////////////////////////////// -/////////////////////////////// Control //////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby", - ASSERT_OK(stream->standby())) // can not fail - -TEST_IO_STREAM(startNoMmap, "Starting a mmaped stream before mapping it should fail", - ASSERT_RESULT(invalidStateOrNotSupported, stream->start())) - -TEST_IO_STREAM(stopNoMmap, "Stopping a mmaped stream before mapping it should fail", - ASSERT_RESULT(invalidStateOrNotSupported, stream->stop())) - -TEST_IO_STREAM(getMmapPositionNoMmap, "Get a stream Mmap position before mapping it should fail", - ASSERT_RESULT(invalidStateOrNotSupported, stream->stop())) - -TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream())) -TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", ASSERT_OK(closeStream()); - ASSERT_RESULT(Result::INVALID_STATE, closeStream())) - -static void testCreateTooBigMmapBuffer(IStream* stream) { - MmapBufferInfo info; - Result res; - // Assume that int max is a value too big to be allocated - // This is true currently with a 32bit media server, but might not when it - // will run in 64 bit - auto minSizeFrames = std::numeric_limits<int32_t>::max(); - ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info))); - ASSERT_RESULT(invalidArgsOrNotSupported, res); -} - -TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail", - testCreateTooBigMmapBuffer(stream.get())) - -static void testGetMmapPositionOfNonMmapedStream(IStream* stream) { - Result res; - MmapPosition position; - ASSERT_OK(stream->getMmapPosition(returnIn(res, position))); - ASSERT_RESULT(invalidArgsOrNotSupported, res); -} - -TEST_IO_STREAM(GetMmapPositionOfNonMmapedStream, - "Retrieving the mmap position of a non mmaped stream should fail", - testGetMmapPositionOfNonMmapedStream(stream.get())) - -////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// StreamIn /////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -TEST_P(InputStreamTest, GetAudioSource) { - doc::test("Retrieving the audio source of an input stream should always succeed"); - AudioSource source; - ASSERT_OK(stream->getAudioSource(returnIn(res, source))); - if (res == Result::NOT_SUPPORTED) { - doc::partialTest("getAudioSource is not supported"); - return; - } - ASSERT_OK(res); - ASSERT_EQ(AudioSource::DEFAULT, source); -} - -static void testUnitaryGain(std::function<Return<Result>(float)> setGain) { - for (float value : (float[]){-INFINITY, -1.0, 1.0 + std::numeric_limits<float>::epsilon(), 2.0, - INFINITY, NAN}) { - EXPECT_RESULT(Result::INVALID_ARGUMENTS, setGain(value)) << "value=" << value; - } - // Do not consider -0.0 as an invalid value as it is == with 0.0 - for (float value : {-0.0, 0.0, 0.01, 0.5, 0.09, 1.0 /* Restore volume*/}) { - EXPECT_OK(setGain(value)) << "value=" << value; - } -} - -static void testOptionalUnitaryGain(std::function<Return<Result>(float)> setGain, - string debugName) { - auto result = setGain(1); - ASSERT_IS_OK(result); - if (result == Result::NOT_SUPPORTED) { - doc::partialTest(debugName + " is not supported"); - return; - } - testUnitaryGain(setGain); -} - -TEST_P(InputStreamTest, SetGain) { - doc::test("The gain of an input stream should only be set between [0,1]"); - testOptionalUnitaryGain([this](float volume) { return stream->setGain(volume); }, - "InputStream::setGain"); -} - -static void testPrepareForReading(IStreamIn* stream, uint32_t frameSize, uint32_t framesCount) { - Result res; - // Ignore output parameters as the call should fail - ASSERT_OK(stream->prepareForReading(frameSize, framesCount, - [&res](auto r, auto&, auto&, auto&, auto&) { res = r; })); - EXPECT_RESULT(Result::INVALID_ARGUMENTS, res); -} - -TEST_P(InputStreamTest, PrepareForReadingWithZeroBuffer) { - doc::test("Preparing a stream for reading with a 0 sized buffer should fail"); - testPrepareForReading(stream.get(), 0, 0); -} - -TEST_P(InputStreamTest, PrepareForReadingWithHugeBuffer) { - doc::test("Preparing a stream for reading with a 2^32 sized buffer should fail"); - testPrepareForReading(stream.get(), 1, std::numeric_limits<uint32_t>::max()); -} - -TEST_P(InputStreamTest, PrepareForReadingCheckOverflow) { - doc::test( - "Preparing a stream for reading with a overflowing sized buffer should " - "fail"); - auto uintMax = std::numeric_limits<uint32_t>::max(); - testPrepareForReading(stream.get(), uintMax, uintMax); -} - -TEST_P(InputStreamTest, GetInputFramesLost) { - doc::test("The number of frames lost on a never started stream should be 0"); - auto ret = stream->getInputFramesLost(); - ASSERT_IS_OK(ret); - uint32_t framesLost{ret}; - ASSERT_EQ(0U, framesLost); -} - -TEST_P(InputStreamTest, getCapturePosition) { - doc::test( - "The capture position of a non prepared stream should not be " - "retrievable or 0"); - uint64_t frames; - uint64_t time; - ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time))); - ASSERT_RESULT(okOrInvalidStateOrNotSupported, res); - if (res == Result::OK) { - ASSERT_EQ(0U, frames); - ASSERT_LE(0U, time); - } -} - -TEST_P(InputStreamTest, updateSinkMetadata) { - doc::test("The HAL should not crash on metadata change"); - - hidl_enum_range<AudioSource> range; - // Test all possible track configuration - for (AudioSource source : range) { - for (float volume : {0.0, 0.5, 1.0}) { - const SinkMetadata metadata = {{{source, volume}}}; - ASSERT_OK(stream->updateSinkMetadata(metadata)) - << "source=" << toString(source) << ", volume=" << volume; - } - } - - // Do not test concurrent capture as this is not officially supported - - // Set no metadata as if all stream track had stopped - ASSERT_OK(stream->updateSinkMetadata({})); - - // Restore initial - ASSERT_OK(stream->updateSinkMetadata(initialMetadata)); -} - -////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// StreamOut ////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -TEST_P(OutputStreamTest, getLatency) { - doc::test("Make sure latency is over 0"); - auto result = stream->getLatency(); - ASSERT_IS_OK(result); - ASSERT_GT(result, 0U); -} - -TEST_P(OutputStreamTest, setVolume) { - doc::test("Try to set the output volume"); - testOptionalUnitaryGain([this](float volume) { return stream->setVolume(volume, volume); }, - "setVolume"); -} - -static void testPrepareForWriting(IStreamOut* stream, uint32_t frameSize, uint32_t framesCount) { - Result res; - // Ignore output parameters as the call should fail - ASSERT_OK(stream->prepareForWriting(frameSize, framesCount, - [&res](auto r, auto&, auto&, auto&, auto&) { res = r; })); - EXPECT_RESULT(Result::INVALID_ARGUMENTS, res); -} - -TEST_P(OutputStreamTest, PrepareForWriteWithZeroBuffer) { - doc::test("Preparing a stream for writing with a 0 sized buffer should fail"); - testPrepareForWriting(stream.get(), 0, 0); -} - -TEST_P(OutputStreamTest, PrepareForWriteWithHugeBuffer) { - doc::test("Preparing a stream for writing with a 2^32 sized buffer should fail"); - testPrepareForWriting(stream.get(), 1, std::numeric_limits<uint32_t>::max()); -} - -TEST_P(OutputStreamTest, PrepareForWritingCheckOverflow) { - doc::test( - "Preparing a stream for writing with a overflowing sized buffer should " - "fail"); - auto uintMax = std::numeric_limits<uint32_t>::max(); - testPrepareForWriting(stream.get(), uintMax, uintMax); -} - -struct Capability { - Capability(IStreamOut* stream) { - EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume))); - auto ret = stream->supportsDrain(); - EXPECT_IS_OK(ret); - if (ret.isOk()) { - drain = ret; - } - } - bool pause = false; - bool resume = false; - bool drain = false; -}; - -TEST_P(OutputStreamTest, SupportsPauseAndResumeAndDrain) { - doc::test("Implementation must expose pause, resume and drain capabilities"); - Capability(stream.get()); -} - -template <class Value> -static void checkInvalidStateOr0(Result res, Value value) { - switch (res) { - case Result::INVALID_STATE: - break; - case Result::OK: - ASSERT_EQ(0U, value); - break; - default: - FAIL() << "Unexpected result " << toString(res); - } -} - -TEST_P(OutputStreamTest, GetRenderPosition) { - doc::test("A new stream render position should be 0 or INVALID_STATE"); - uint32_t dspFrames; - ASSERT_OK(stream->getRenderPosition(returnIn(res, dspFrames))); - if (res == Result::NOT_SUPPORTED) { - doc::partialTest("getRenderPosition is not supported"); - return; - } - checkInvalidStateOr0(res, dspFrames); -} - -TEST_P(OutputStreamTest, GetNextWriteTimestamp) { - doc::test("A new stream next write timestamp should be 0 or INVALID_STATE"); - uint64_t timestampUs; - ASSERT_OK(stream->getNextWriteTimestamp(returnIn(res, timestampUs))); - if (res == Result::NOT_SUPPORTED) { - doc::partialTest("getNextWriteTimestamp is not supported"); - return; - } - checkInvalidStateOr0(res, timestampUs); -} - -/** Stub implementation of out stream callback. */ -class MockOutCallbacks : public IStreamOutCallback { - Return<void> onWriteReady() override { return {}; } - Return<void> onDrainReady() override { return {}; } - Return<void> onError() override { return {}; } -}; - -static bool isAsyncModeSupported(IStreamOut* stream) { - auto res = stream->setCallback(new MockOutCallbacks); - stream->clearCallback(); // try to restore the no callback state, ignore - // any error - EXPECT_RESULT(okOrNotSupported, res); - return res.isOk() ? res == Result::OK : false; -} - -TEST_P(OutputStreamTest, SetCallback) { - doc::test( - "If supported, registering callback for async operation should never " - "fail"); - if (!isAsyncModeSupported(stream.get())) { - doc::partialTest("The stream does not support async operations"); - return; - } - ASSERT_OK(stream->setCallback(new MockOutCallbacks)); - ASSERT_OK(stream->setCallback(new MockOutCallbacks)); -} - -TEST_P(OutputStreamTest, clearCallback) { - doc::test( - "If supported, clearing a callback to go back to sync operation should " - "not fail"); - if (!isAsyncModeSupported(stream.get())) { - doc::partialTest("The stream does not support async operations"); - return; - } - // TODO: Clarify if clearing a non existing callback should fail - ASSERT_OK(stream->setCallback(new MockOutCallbacks)); - ASSERT_OK(stream->clearCallback()); -} - -TEST_P(OutputStreamTest, Resume) { - doc::test( - "If supported, a stream should fail to resume if not previously " - "paused"); - if (!Capability(stream.get()).resume) { - doc::partialTest("The output stream does not support resume"); - return; - } - ASSERT_RESULT(Result::INVALID_STATE, stream->resume()); -} - -TEST_P(OutputStreamTest, Pause) { - doc::test( - "If supported, a stream should fail to pause if not previously " - "started"); - if (!Capability(stream.get()).pause) { - doc::partialTest("The output stream does not support pause"); - return; - } - ASSERT_RESULT(Result::INVALID_STATE, stream->pause()); -} - -static void testDrain(IStreamOut* stream, AudioDrain type) { - if (!Capability(stream).drain) { - doc::partialTest("The output stream does not support drain"); - return; - } - ASSERT_RESULT(Result::OK, stream->drain(type)); -} - -TEST_P(OutputStreamTest, DrainAll) { - doc::test("If supported, a stream should always succeed to drain"); - testDrain(stream.get(), AudioDrain::ALL); -} - -TEST_P(OutputStreamTest, DrainEarlyNotify) { - doc::test("If supported, a stream should always succeed to drain"); - testDrain(stream.get(), AudioDrain::EARLY_NOTIFY); -} - -TEST_P(OutputStreamTest, FlushStop) { - doc::test("If supported, a stream should always succeed to flush"); - auto ret = stream->flush(); - ASSERT_IS_OK(ret); - if (ret == Result::NOT_SUPPORTED) { - doc::partialTest("Flush is not supported"); - return; - } - ASSERT_OK(ret); -} - -TEST_P(OutputStreamTest, GetPresentationPositionStop) { - doc::test( - "If supported, a stream should always succeed to retrieve the " - "presentation position"); - uint64_t frames; - TimeSpec mesureTS; - ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, mesureTS))); - if (res == Result::NOT_SUPPORTED) { - doc::partialTest("getpresentationPosition is not supported"); - return; - } - ASSERT_EQ(0U, frames); - - if (mesureTS.tvNSec == 0 && mesureTS.tvSec == 0) { - // As the stream has never written a frame yet, - // the timestamp does not really have a meaning, allow to return 0 - return; - } - - // Make sure the return measure is not more than 1s old. - struct timespec currentTS; - ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, ¤tTS)) << errno; - - auto toMicroSec = [](uint64_t sec, auto nsec) { return sec * 1e+6 + nsec / 1e+3; }; - auto currentTime = toMicroSec(currentTS.tv_sec, currentTS.tv_nsec); - auto mesureTime = toMicroSec(mesureTS.tvSec, mesureTS.tvNSec); - ASSERT_PRED2([](auto c, auto m) { return c - m < 1e+6; }, currentTime, mesureTime); -} - -TEST_P(OutputStreamTest, SelectPresentation) { - doc::test("Verify that presentation selection does not crash"); - ASSERT_RESULT(okOrNotSupported, stream->selectPresentation(0, 0)); -} - -TEST_P(OutputStreamTest, updateSourceMetadata) { - doc::test("The HAL should not crash on metadata change"); - - hidl_enum_range<AudioUsage> usageRange; - hidl_enum_range<AudioContentType> contentRange; - // Test all possible track configuration - for (auto usage : usageRange) { - for (auto content : contentRange) { - for (float volume : {0.0, 0.5, 1.0}) { - const SourceMetadata metadata = {{{usage, content, volume}}}; - ASSERT_OK(stream->updateSourceMetadata(metadata)) - << "usage=" << toString(usage) << ", content=" << toString(content) - << ", volume=" << volume; - } - } - } - - // Set many track of different configuration - ASSERT_OK(stream->updateSourceMetadata( - {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 0.1}, - {AudioUsage::VOICE_COMMUNICATION, AudioContentType::SPEECH, 1.0}, - {AudioUsage::ALARM, AudioContentType::SONIFICATION, 0.0}, - {AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}})); - - // Set no metadata as if all stream track had stopped - ASSERT_OK(stream->updateSourceMetadata({})); - - // Restore initial - ASSERT_OK(stream->updateSourceMetadata(initialMetadata)); -} - -////////////////////////////////////////////////////////////////////////////// -/////////////////////////////// PrimaryDevice //////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -TEST_F(AudioPrimaryHidlTest, setVoiceVolume) { - doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]"); - testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); }); -} - -TEST_F(AudioPrimaryHidlTest, setMode) { - doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise"); - // Test Invalid values - for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) { - ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode))) - << "mode=" << mode; - } - // Test valid values - for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE, - AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { - ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode); - } -} - -TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) { - doc::test( - "Make sure setBtHfpSampleRate either succeeds or " - "indicates that it is not supported at all, or that the provided value is invalid"); - for (auto samplingRate : {8000, 16000, 22050, 24000}) { - ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate)); - } -} - -TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) { - doc::test( - "Make sure setBtHfpVolume is either not supported or " - "only succeed if volume is in [0,1]"); - auto ret = device->setBtHfpVolume(0.0); - ASSERT_TRUE(ret.isOk()); - if (ret == Result::NOT_SUPPORTED) { - doc::partialTest("setBtHfpVolume is not supported"); - return; - } - testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); }); -} - -TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) { - doc::test( - "Make sure setBtScoHeadsetDebugName either succeeds or " - "indicates that it is not supported"); - ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test")); -} - -TEST_F(AudioPrimaryHidlTest, updateRotation) { - doc::test("Check that the hal can receive the current rotation"); - for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180, - Rotation::DEG_270, Rotation::DEG_0}) { - ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation)); - } -} - -TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) { - doc::test("Query and set the BT SCO NR&EC state"); - testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true}, - &IPrimaryDevice::setBtScoNrecEnabled, - &IPrimaryDevice::getBtScoNrecEnabled); -} - -TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { - doc::test("Query and set the SCO whideband state"); - testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true}, - &IPrimaryDevice::setBtScoWidebandEnabled, - &IPrimaryDevice::getBtScoWidebandEnabled); -} - -TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) { - doc::test("Query and set the BT HFP state"); - testAccessors<OPTIONAL>("BtHfpEnabled", Initial{false, OPTIONAL}, {true}, - &IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled); -} - -using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<TtyMode>; -TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { - doc::test("Query and set the TTY mode state"); - testAccessors<OPTIONAL>("TTY mode", Initial{TtyMode::OFF}, - {TtyMode::HCO, TtyMode::VCO, TtyMode::FULL}, - &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode); -} - -TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) { - doc::test("Query and set the HAC state"); - testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled, - &IPrimaryDevice::getHacEnabled); -} - -////////////////////////////////////////////////////////////////////////////// -//////////////////// Clean caches on global tear down //////////////////////// -////////////////////////////////////////////////////////////////////////////// - -int main(int argc, char** argv) { - environment = new AudioHidlTestEnvironment; - ::testing::AddGlobalTestEnvironment(environment); - ::testing::InitGoogleTest(&argc, argv); - environment->init(&argc, argv); - int status = RUN_ALL_TESTS(); - return status; -} diff --git a/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp b/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp deleted file mode 100644 index a64513fc81..0000000000 --- a/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 <unistd.h> -#include <string> - -#include "utility/ValidateXml.h" - -TEST(CheckConfig, audioPolicyConfigurationValidation) { - RecordProperty("description", - "Verify that the audio policy configuration file " - "is valid according to the schema"); - - std::vector<const char*> locations = {"/odm/etc", "/vendor/etc", "/system/etc"}; - EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations, - "/data/local/tmp/audio_policy_configuration_V4_0.xsd"); -} diff --git a/audio/core/all-versions/OWNERS b/audio/core/all-versions/OWNERS deleted file mode 100644 index 6fdc97ca29..0000000000 --- a/audio/core/all-versions/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -elaurent@google.com -krocard@google.com -mnaganov@google.com diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp index bb02863ba6..a1af3c4db5 100644 --- a/audio/core/all-versions/default/Android.bp +++ b/audio/core/all-versions/default/Android.bp @@ -1,7 +1,18 @@ -cc_library_headers { - name: "android.hardware.audio.core@all-versions-impl", +cc_defaults { + name: "android.hardware.audio-impl_default", relative_install_path: "hw", + proprietary: true, vendor: true, + srcs: [ + "Conversions.cpp", + "Device.cpp", + "DevicesFactory.cpp", + "ParametersUtil.cpp", + "PrimaryDevice.cpp", + "Stream.cpp", + "StreamIn.cpp", + "StreamOut.cpp", + ], defaults: ["hidl_defaults"], @@ -20,10 +31,65 @@ cc_library_headers { ], header_libs: [ + "android.hardware.audio.common.util@all-versions", "libaudioclient_headers", "libaudio_system_headers", "libhardware_headers", "libmedia_headers", - "android.hardware.audio.common.util@all-versions", ], + + whole_static_libs: [ + "libmedia_helper", + ], +} + +cc_library_shared { + name: "android.hardware.audio@2.0-impl", + defaults: ["android.hardware.audio-impl_default"], + + shared_libs: [ + "android.hardware.audio@2.0", + "android.hardware.audio.common@2.0", + "android.hardware.audio.common@2.0-util", + ], + + cflags: [ + "-DMAJOR_VERSION=2", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_library_shared { + name: "android.hardware.audio@4.0-impl", + defaults: ["android.hardware.audio-impl_default"], + + shared_libs: [ + "android.hardware.audio@4.0", + "android.hardware.audio.common@4.0", + "android.hardware.audio.common@4.0-util", + ], + + cflags: [ + "-DMAJOR_VERSION=4", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_library_shared { + name: "android.hardware.audio@5.0-impl", + defaults: ["android.hardware.audio-impl_default"], + + shared_libs: [ + "android.hardware.audio@5.0", + "android.hardware.audio.common@5.0", + "android.hardware.audio.common@5.0-util", + ], + + cflags: [ + "-DMAJOR_VERSION=5", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] } diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h b/audio/core/all-versions/default/Conversions.cpp index 5828c3f373..11872c0e00 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h +++ b/audio/core/all-versions/default/Conversions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#include "core/default/Conversions.h" #include <stdio.h> @@ -23,11 +23,9 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; - std::string deviceAddressToHal(const DeviceAddress& address) { // HAL assumes that the address is NUL-terminated. char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; @@ -58,7 +56,7 @@ std::string deviceAddressToHal(const DeviceAddress& address) { return halAddress; } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 status_t deviceAddressFromHal(audio_devices_t device, const char* halAddress, DeviceAddress* address) { if (address == nullptr) { @@ -188,7 +186,7 @@ bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst, #endif } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h b/audio/core/all-versions/default/Device.cpp index 230b8de243..bec22df6d5 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h +++ b/audio/core/all-versions/default/Device.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,14 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "DeviceHAL" + +#include "core/default/Device.h" +#include <HidlUtils.h> +#include "core/default/Conversions.h" +#include "core/default/StreamIn.h" +#include "core/default/StreamOut.h" +#include "core/default/Util.h" //#define LOG_NDEBUG 0 @@ -24,14 +31,14 @@ #include <android/log.h> -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::HidlUtils; - namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { +using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; + Device::Device(audio_hw_device_t* device) : mDevice(device) {} Device::~Device() { @@ -40,8 +47,9 @@ Device::~Device() { mDevice = nullptr; } -Result Device::analyzeStatus(const char* funcName, int status) { - return util::analyzeStatus("Device", funcName, status); +Result Device::analyzeStatus(const char* funcName, int status, + const std::vector<int>& ignoreErrors) { + return util::analyzeStatus("Device", funcName, status, ignoreErrors); } void Device::closeInputStream(audio_stream_in_t* stream) { @@ -60,7 +68,7 @@ int Device::halSetParameters(const char* keysAndValues) { return mDevice->set_parameters(mDevice, keysAndValues); } -// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice follow. +// Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow. Return<Result> Device::initCheck() { return analyzeStatus("init_check", mDevice->init_check(mDevice)); } @@ -129,12 +137,11 @@ Return<void> Device::getInputBufferSize(const AudioConfig& config, getInputBuffe return Void(); } -Return<void> Device::openOutputStream(int32_t ioHandle, const DeviceAddress& device, - const AudioConfig& config, AudioOutputFlagBitfield flags, -#ifdef AUDIO_HAL_VERSION_4_0 - const SourceMetadata& /* sourceMetadata */, -#endif - openOutputStream_cb _hidl_cb) { +std::tuple<Result, sp<IStreamOut>> Device::openOutputStreamImpl(int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlagBitfield flags, + AudioConfig* suggestedConfig) { audio_config_t halConfig; HidlUtils::audioConfigToHal(config, &halConfig); audio_stream_out_t* halStream; @@ -153,15 +160,13 @@ Return<void> Device::openOutputStream(int32_t ioHandle, const DeviceAddress& dev if (status == OK) { streamOut = new StreamOut(this, halStream); } - AudioConfig suggestedConfig; - HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig); - _hidl_cb(analyzeStatus("open_output_stream", status), streamOut, suggestedConfig); - return Void(); + HidlUtils::audioConfigFromHal(halConfig, suggestedConfig); + return {analyzeStatus("open_output_stream", status, {EINVAL} /*ignore*/), streamOut}; } -Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& device, - const AudioConfig& config, AudioInputFlagBitfield flags, - AudioSource source, openInputStream_cb _hidl_cb) { +std::tuple<Result, sp<IStreamIn>> Device::openInputStreamImpl( + int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, + AudioInputFlagBitfield flags, AudioSource source, AudioConfig* suggestedConfig) { audio_config_t halConfig; HidlUtils::audioConfigToHal(config, &halConfig); audio_stream_in_t* halStream; @@ -181,13 +186,46 @@ Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& devi if (status == OK) { streamIn = new StreamIn(this, halStream); } + HidlUtils::audioConfigFromHal(halConfig, suggestedConfig); + return {analyzeStatus("open_input_stream", status, {EINVAL} /*ignore*/), streamIn}; +} + +#if MAJOR_VERSION == 2 +Return<void> Device::openOutputStream(int32_t ioHandle, const DeviceAddress& device, + const AudioConfig& config, AudioOutputFlagBitfield flags, + openOutputStream_cb _hidl_cb) { + AudioConfig suggestedConfig; + auto [result, streamOut] = + openOutputStreamImpl(ioHandle, device, config, flags, &suggestedConfig); + _hidl_cb(result, streamOut, suggestedConfig); + return Void(); +} + +Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& device, + const AudioConfig& config, AudioInputFlagBitfield flags, + AudioSource source, openInputStream_cb _hidl_cb) { + AudioConfig suggestedConfig; + auto [result, streamIn] = + openInputStreamImpl(ioHandle, device, config, flags, source, &suggestedConfig); + _hidl_cb(result, streamIn, suggestedConfig); + return Void(); +} + +#elif MAJOR_VERSION >= 4 +Return<void> Device::openOutputStream(int32_t ioHandle, const DeviceAddress& device, + const AudioConfig& config, AudioOutputFlagBitfield flags, + const SourceMetadata& sourceMetadata, + openOutputStream_cb _hidl_cb) { AudioConfig suggestedConfig; - HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig); - _hidl_cb(analyzeStatus("open_input_stream", status), streamIn, suggestedConfig); + auto [result, streamOut] = + openOutputStreamImpl(ioHandle, device, config, flags, &suggestedConfig); + if (streamOut) { + streamOut->updateSourceMetadata(sourceMetadata); + } + _hidl_cb(result, streamOut, suggestedConfig); return Void(); } -#ifdef AUDIO_HAL_VERSION_4_0 Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioInputFlagBitfield flags, const SinkMetadata& sinkMetadata, @@ -199,11 +237,18 @@ Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& devi _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, AudioConfig()); return Void(); } - // Pick the first one as the main until the legacy API is update + // Pick the first one as the main. AudioSource source = sinkMetadata.tracks[0].source; - return openInputStream(ioHandle, device, config, flags, source, _hidl_cb); + AudioConfig suggestedConfig; + auto [result, streamIn] = + openInputStreamImpl(ioHandle, device, config, flags, source, &suggestedConfig); + if (streamIn) { + streamIn->updateSinkMetadata(sinkMetadata); + } + _hidl_cb(result, streamIn, suggestedConfig); + return Void(); } -#endif +#endif /* MAJOR_VERSION */ Return<bool> Device::supportsAudioPatches() { return version() >= AUDIO_DEVICE_API_VERSION_3_0; @@ -260,13 +305,13 @@ Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) { return Result::NOT_SUPPORTED; } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<AudioHwSync> Device::getHwAvSync() { int halHwAvSync; Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync); return retval == Result::OK ? halHwAvSync : AUDIO_HW_SYNC_INVALID; } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> Device::getHwAvSync(getHwAvSync_cb _hidl_cb) { int halHwAvSync; Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync); @@ -279,7 +324,7 @@ Return<Result> Device::setScreenState(bool turnedOn) { return setParam(AudioParameter::keyScreenState, turnedOn); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> Device::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { getParametersImpl({}, keys, _hidl_cb); return Void(); @@ -288,7 +333,7 @@ Return<void> Device::getParameters(const hidl_vec<hidl_string>& keys, getParamet Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& parameters) { return setParametersImpl({} /* context */, parameters); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> Device::getParameters(const hidl_vec<ParameterValue>& context, const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { getParametersImpl(context, keys, _hidl_cb); @@ -300,7 +345,7 @@ Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& context, } #endif -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> Device::debugDump(const hidl_handle& fd) { return debug(fd, {}); } @@ -313,7 +358,7 @@ Return<void> Device::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& / return Void(); } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return<void> Device::getMicrophones(getMicrophones_cb _hidl_cb) { Result retval = Result::NOT_SUPPORTED; size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT; @@ -339,7 +384,7 @@ Return<Result> Device::setConnectedState(const DeviceAddress& address, bool conn #endif } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android diff --git a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h b/audio/core/all-versions/default/DevicesFactory.cpp index 43e5d6eaed..729f18cf91 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h +++ b/audio/core/all-versions/default/DevicesFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,11 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "DevicesFactoryHAL" + +#include "core/default/DevicesFactory.h" +#include "core/default/Device.h" +#include "core/default/PrimaryDevice.h" #include <string.h> @@ -23,10 +27,10 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) { switch (device) { case IDevicesFactory::Device::PRIMARY: @@ -43,8 +47,7 @@ Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevi _hidl_cb(Result::INVALID_ARGUMENTS, nullptr); return Void(); } -#endif -#ifdef AUDIO_HAL_VERSION_4_0 +#elif MAJOR_VERSION >= 4 Return<void> DevicesFactory::openDevice(const hidl_string& moduleName, openDevice_cb _hidl_cb) { if (moduleName == AUDIO_HARDWARE_MODULE_ID_PRIMARY) { return openDevice<PrimaryDevice>(moduleName.c_str(), _hidl_cb); @@ -106,12 +109,12 @@ out: return rc; } -IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) { - return new DevicesFactory(); +IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name) { + return strcmp(name, "default") == 0 ? new DevicesFactory() : nullptr; } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android diff --git a/audio/common/4.0/default/OWNERS b/audio/core/all-versions/default/OWNERS index 6fdc97ca29..6fdc97ca29 100644 --- a/audio/common/4.0/default/OWNERS +++ b/audio/core/all-versions/default/OWNERS diff --git a/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.impl.h b/audio/core/all-versions/default/ParametersUtil.cpp index 34bc53c7a7..0c8e28af8b 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.impl.h +++ b/audio/core/all-versions/default/ParametersUtil.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,14 +14,16 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> -#include <core/all-versions/default/Conversions.h> +#include "core/default/ParametersUtil.h" +#include "core/default/Conversions.h" +#include "core/default/Util.h" + #include <system/audio.h> namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { /** Converts a status_t in Result according to the rules of AudioParameter::get* @@ -159,7 +161,7 @@ Result ParametersUtil::setParams(const AudioParameter& param) { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android diff --git a/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.impl.h b/audio/core/all-versions/default/PrimaryDevice.cpp index f269dd4f91..99590b0bdc 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.impl.h +++ b/audio/core/all-versions/default/PrimaryDevice.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,23 +14,26 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "PrimaryDeviceHAL" -#ifdef AUDIO_HAL_VERSION_4_0 +#include "core/default/PrimaryDevice.h" +#include "core/default/Util.h" + +#if MAJOR_VERSION >= 4 #include <cmath> #endif namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { PrimaryDevice::PrimaryDevice(audio_hw_device_t* device) : mDevice(new Device(device)) {} PrimaryDevice::~PrimaryDevice() {} -// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice follow. +// Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow. Return<Result> PrimaryDevice::initCheck() { return mDevice->initCheck(); } @@ -64,7 +67,7 @@ Return<void> PrimaryDevice::getInputBufferSize(const AudioConfig& config, return mDevice->getInputBufferSize(config, _hidl_cb); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> PrimaryDevice::openOutputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioOutputFlagBitfield flags, @@ -77,7 +80,7 @@ Return<void> PrimaryDevice::openInputStream(int32_t ioHandle, const DeviceAddres AudioSource source, openInputStream_cb _hidl_cb) { return mDevice->openInputStream(ioHandle, device, config, flags, source, _hidl_cb); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> PrimaryDevice::openOutputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioOutputFlagBitfield flags, @@ -120,7 +123,7 @@ Return<Result> PrimaryDevice::setScreenState(bool turnedOn) { return mDevice->setScreenState(turnedOn); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<AudioHwSync> PrimaryDevice::getHwAvSync() { return mDevice->getHwAvSync(); } @@ -137,7 +140,7 @@ Return<Result> PrimaryDevice::setParameters(const hidl_vec<ParameterValue>& para Return<void> PrimaryDevice::debugDump(const hidl_handle& fd) { return mDevice->debugDump(fd); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> PrimaryDevice::getHwAvSync(getHwAvSync_cb _hidl_cb) { return mDevice->getHwAvSync(_hidl_cb); } @@ -158,7 +161,7 @@ Return<Result> PrimaryDevice::setConnectedState(const DeviceAddress& address, bo } #endif -// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IPrimaryDevice follow. +// Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow. Return<Result> PrimaryDevice::setVoiceVolume(float volume) { if (!isGainNormalized(volume)) { ALOGW("Can not set a voice volume (%f) outside [0,1]", volume); @@ -271,7 +274,7 @@ Return<Result> PrimaryDevice::setHacEnabled(bool enabled) { return mDevice->setParam(AUDIO_PARAMETER_KEY_HAC, enabled); } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return<Result> PrimaryDevice::setBtScoHeadsetDebugName(const hidl_string& name) { return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_HEADSET_NAME, name.c_str()); } @@ -307,7 +310,7 @@ Return<void> PrimaryDevice::debug(const hidl_handle& fd, const hidl_vec<hidl_str } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Stream.impl.h b/audio/core/all-versions/default/Stream.cpp index 72d7a3760a..b995657087 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/Stream.impl.h +++ b/audio/core/all-versions/default/Stream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "StreamHAL" + +#include "core/default/Stream.h" +#include "common/all-versions/default/EffectMap.h" +#include "core/default/Conversions.h" +#include "core/default/Util.h" #include <inttypes.h> @@ -28,7 +33,7 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { Stream::Stream(audio_stream_t* stream) : mStream(stream) {} @@ -42,7 +47,6 @@ Result Stream::analyzeStatus(const char* funcName, int status) { return util::analyzeStatus("stream", funcName, status); } - // static Result Stream::analyzeStatus(const char* funcName, int status, const std::vector<int>& ignoreErrors) { @@ -57,7 +61,7 @@ int Stream::halSetParameters(const char* keysAndValues) { return mStream->set_parameters(mStream, keysAndValues); } -// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow. +// Methods from ::android::hardware::audio::CPP_VERSION::IStream follow. Return<uint64_t> Stream::getFrameSize() { // Needs to be implemented by interface subclasses. But can't be declared as pure virtual, // since interface subclasses implementation do not inherit from this class. @@ -79,7 +83,7 @@ Return<uint32_t> Stream::getSampleRate() { return mStream->get_sample_rate(mStream); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> Stream::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { return getSupportedSampleRates(getFormat(), _hidl_cb); } @@ -107,9 +111,9 @@ Return<void> Stream::getSupportedSampleRates(AudioFormat format, result = Result::NOT_SUPPORTED; } } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 _hidl_cb(sampleRates); -#elif AUDIO_HAL_VERSION_4_0 +#elif MAJOR_VERSION >= 4 _hidl_cb(result, sampleRates); #endif return Void(); @@ -136,9 +140,9 @@ Return<void> Stream::getSupportedChannelMasks(AudioFormat format, result = Result::NOT_SUPPORTED; } } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 _hidl_cb(channelMasks); -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 _hidl_cb(result, channelMasks); #endif return Void(); @@ -217,7 +221,7 @@ Return<Result> Stream::setHwAvSync(uint32_t hwAvSync) { return setParam(AudioParameter::keyStreamHwAvSync, static_cast<int>(hwAvSync)); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<AudioDevice> Stream::getDevice() { int device = 0; Result retval = getParam(AudioParameter::keyRouting, &device); @@ -242,7 +246,7 @@ Return<Result> Stream::setConnectedState(const DeviceAddress& address, bool conn connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect, address); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> Stream::getDevices(getDevices_cb _hidl_cb) { int device = 0; Result retval = getParam(AudioParameter::keyRouting, &device); @@ -314,14 +318,14 @@ Return<void> Stream::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& / return Void(); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> Stream::debugDump(const hidl_handle& fd) { return debug(fd, {} /* options */); } #endif } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h b/audio/core/all-versions/default/StreamIn.cpp index 64c85ab5fc..daba6f7ef2 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h +++ b/audio/core/all-versions/default/StreamIn.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,11 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "StreamInHAL" + +#include "core/default/StreamIn.h" +#include "core/default/Conversions.h" +#include "core/default/Util.h" //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_AUDIO @@ -24,17 +28,12 @@ #include <utils/Trace.h> #include <memory> -using ::android::hardware::audio::AUDIO_HAL_VERSION::MessageQueueFlagBits; -#include "Conversions.h" - namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::ThreadInfo; - namespace { class ReadThread : public Thread { @@ -162,7 +161,7 @@ StreamIn::~StreamIn() { mStream = nullptr; } -// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow. +// Methods from ::android::hardware::audio::CPP_VERSION::IStream follow. Return<uint64_t> StreamIn::getFrameSize() { return audio_stream_in_frame_size(mStream); } @@ -179,7 +178,7 @@ Return<uint32_t> StreamIn::getSampleRate() { return mStreamCommon->getSampleRate(); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { return mStreamCommon->getSupportedChannelMasks(_hidl_cb); } @@ -241,7 +240,7 @@ Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) { return mStreamCommon->setHwAvSync(hwAvSync); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) { return mStreamCommon->setConnectedState(address, connected); } @@ -265,7 +264,7 @@ Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameter Return<void> StreamIn::debugDump(const hidl_handle& fd) { return mStreamCommon->debugDump(fd); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> StreamIn::getDevices(getDevices_cb _hidl_cb) { return mStreamCommon->getDevices(_hidl_cb); } @@ -313,7 +312,7 @@ Return<Result> StreamIn::close() { return Result::OK; } -// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn follow. +// Methods from ::android::hardware::audio::CPP_VERSION::IStreamIn follow. Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) { int halSource; Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource); @@ -342,7 +341,6 @@ Return<void> StreamIn::prepareForReading(uint32_t frameSize, uint32_t framesCoun auto sendError = [&threadInfo, &_hidl_cb](Result result) { _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); - }; // Create message queues. @@ -448,7 +446,7 @@ Return<void> StreamIn::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& return mStreamCommon->debug(fd, options); } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) { if (mStream->update_sink_metadata == nullptr) { return Void(); // not supported by the HAL @@ -456,11 +454,23 @@ Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) { std::vector<record_track_metadata> halTracks; halTracks.reserve(sinkMetadata.tracks.size()); for (auto& metadata : sinkMetadata.tracks) { - halTracks.push_back( - {.source = static_cast<audio_source_t>(metadata.source), .gain = metadata.gain}); + record_track_metadata halTrackMetadata = { + .source = static_cast<audio_source_t>(metadata.source), .gain = metadata.gain}; +#if MAJOR_VERSION >= 5 + if (metadata.destination.getDiscriminator() == + RecordTrackMetadata::Destination::hidl_discriminator::device) { + halTrackMetadata.dest_device = + static_cast<audio_devices_t>(metadata.destination.device().device); + strncpy(halTrackMetadata.dest_device_address, + deviceAddressToHal(metadata.destination.device()).c_str(), + AUDIO_DEVICE_MAX_ADDRESS_LEN); + } +#endif + halTracks.push_back(halTrackMetadata); } const sink_metadata_t halMetadata = { - .track_count = halTracks.size(), .tracks = halTracks.data(), + .track_count = halTracks.size(), + .tracks = halTracks.data(), }; mStream->update_sink_metadata(mStream, &halMetadata); return Void(); @@ -486,8 +496,29 @@ Return<void> StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) { } #endif +#if MAJOR_VERSION >= 5 +Return<Result> StreamIn::setMicrophoneDirection(MicrophoneDirection direction) { + if (mStream->set_microphone_direction == nullptr) { + return Result::NOT_SUPPORTED; + } + return Stream::analyzeStatus( + "set_microphone_direction", + mStream->set_microphone_direction( + mStream, static_cast<audio_microphone_direction_t>(direction))); +} + +Return<Result> StreamIn::setMicrophoneFieldDimension(float zoom) { + if (mStream->set_microphone_field_dimension == nullptr) { + return Result::NOT_SUPPORTED; + } + return Stream::analyzeStatus("set_microphone_field_dimension", + mStream->set_microphone_field_dimension(mStream, zoom)); +} + +#endif + } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h b/audio/core/all-versions/default/StreamOut.cpp index 6fb157f7de..82cc408e99 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h +++ b/audio/core/all-versions/default/StreamOut.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,10 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "StreamOutHAL" + +#include "core/default/StreamOut.h" +#include "core/default/Util.h" //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_AUDIO @@ -28,11 +31,9 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::ThreadInfo; - namespace { class WriteThread : public Thread { @@ -165,7 +166,7 @@ StreamOut::~StreamOut() { mStream = nullptr; } -// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow. +// Methods from ::android::hardware::audio::CPP_VERSION::IStream follow. Return<uint64_t> StreamOut::getFrameSize() { return audio_stream_out_frame_size(mStream); } @@ -182,7 +183,7 @@ Return<uint32_t> StreamOut::getSampleRate() { return mStreamCommon->getSampleRate(); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { return mStreamCommon->getSupportedChannelMasks(_hidl_cb); } @@ -244,7 +245,7 @@ Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) { return mStreamCommon->setHwAvSync(hwAvSync); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) { return mStreamCommon->setConnectedState(address, connected); } @@ -269,7 +270,7 @@ Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& paramete Return<void> StreamOut::debugDump(const hidl_handle& fd) { return mStreamCommon->debugDump(fd); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> StreamOut::getDevices(getDevices_cb _hidl_cb) { return mStreamCommon->getDevices(_hidl_cb); } @@ -301,7 +302,7 @@ Return<Result> StreamOut::close() { return Result::OK; } -// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut follow. +// Methods from ::android::hardware::audio::CPP_VERSION::IStreamOut follow. Return<uint32_t> StreamOut::getLatency() { return mStream->get_latency(mStream); } @@ -326,7 +327,6 @@ Return<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCou auto sendError = [&threadInfo, &_hidl_cb](Result result) { _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); - }; // Create message queues. @@ -545,7 +545,7 @@ Return<void> StreamOut::debug(const hidl_handle& fd, const hidl_vec<hidl_string> return mStreamCommon->debug(fd, options); } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) { if (mStream->update_source_metadata == nullptr) { return Void(); // not supported by the HAL @@ -560,7 +560,8 @@ Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadat }); } const source_metadata_t halMetadata = { - .track_count = halTracks.size(), .tracks = halTracks.data(), + .track_count = halTracks.size(), + .tracks = halTracks.data(), }; mStream->update_source_metadata(mStream, &halMetadata); return Void(); @@ -571,7 +572,7 @@ Return<Result> StreamOut::selectPresentation(int32_t /*presentationId*/, int32_t #endif } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h b/audio/core/all-versions/default/include/core/default/Conversions.h index b38eca35a1..cb7914fceb 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h +++ b/audio/core/all-versions/default/include/core/default/Conversions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,10 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_CONVERSIONS_H_ +#define ANDROID_HARDWARE_AUDIO_CONVERSIONS_H_ + +#include PATH(android/hardware/audio/FILE_VERSION/types.h) #include <string> @@ -23,20 +26,23 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; std::string deviceAddressToHal(const DeviceAddress& address); -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst, const struct audio_microphone_characteristic_t& src); #endif } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_CONVERSIONS_H_ diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h index eb53b482b2..e64f00f205 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/Device.h +++ b/audio/core/all-versions/default/include/core/default/Device.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_DEVICE_H +#define ANDROID_HARDWARE_AUDIO_DEVICE_H + +#include PATH(android/hardware/audio/FILE_VERSION/IDevice.h) + +#include "ParametersUtil.h" #include <memory> @@ -30,41 +35,23 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioConfig; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioHwSync; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioInputFlag; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioOutputFlag; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPatchHandle; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPort; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortConfig; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::implementation::AudioInputFlagBitfield; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::implementation:: - AudioOutputFlagBitfield; -using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut; -using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue; -using ::android::hardware::audio::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; - -#ifdef AUDIO_HAL_VERSION_4_0 -using ::android::hardware::audio::AUDIO_HAL_VERSION::SourceMetadata; -using ::android::hardware::audio::AUDIO_HAL_VERSION::SinkMetadata; -#endif +using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioInputFlagBitfield; +using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioOutputFlagBitfield; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; struct Device : public IDevice, public ParametersUtil { explicit Device(audio_hw_device_t* device); - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow. Return<Result> initCheck() override; Return<Result> setMasterVolume(float volume) override; Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb) override; @@ -75,15 +62,22 @@ struct Device : public IDevice, public ParametersUtil { Return<void> getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) override; - // V2 openInputStream is called by V4 input stream thus present in both versions - Return<void> openInputStream(int32_t ioHandle, const DeviceAddress& device, - const AudioConfig& config, AudioInputFlagBitfield flags, - AudioSource source, openInputStream_cb _hidl_cb); -#ifdef AUDIO_HAL_VERSION_2_0 + std::tuple<Result, sp<IStreamOut>> openOutputStreamImpl(int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlagBitfield flags, + AudioConfig* suggestedConfig); + std::tuple<Result, sp<IStreamIn>> openInputStreamImpl( + int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, + AudioInputFlagBitfield flags, AudioSource source, AudioConfig* suggestedConfig); +#if MAJOR_VERSION == 2 Return<void> openOutputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioOutputFlagBitfield flags, openOutputStream_cb _hidl_cb) override; -#elif defined(AUDIO_HAL_VERSION_4_0) + Return<void> openInputStream(int32_t ioHandle, const DeviceAddress& device, + const AudioConfig& config, AudioInputFlagBitfield flags, + AudioSource source, openInputStream_cb _hidl_cb) override; +#elif MAJOR_VERSION >= 4 Return<void> openOutputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioOutputFlagBitfield flags, const SourceMetadata& sourceMetadata, @@ -104,13 +98,13 @@ struct Device : public IDevice, public ParametersUtil { Return<Result> setScreenState(bool turnedOn) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<AudioHwSync> getHwAvSync() override; Return<void> getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; Return<void> debugDump(const hidl_handle& fd) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> getHwAvSync(getHwAvSync_cb _hidl_cb) override; Return<void> getParameters(const hidl_vec<ParameterValue>& context, const hidl_vec<hidl_string>& keys, @@ -124,7 +118,8 @@ struct Device : public IDevice, public ParametersUtil { Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; // Utility methods for extending interfaces. - Result analyzeStatus(const char* funcName, int status); + Result analyzeStatus(const char* funcName, int status, + const std::vector<int>& ignoreErrors = {}); void closeInputStream(audio_stream_in_t* stream); void closeOutputStream(audio_stream_out_t* stream); audio_hw_device_t* device() const { return mDevice; } @@ -142,7 +137,9 @@ struct Device : public IDevice, public ParametersUtil { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_DEVICE_H diff --git a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.h b/audio/core/all-versions/default/include/core/default/DevicesFactory.h index 1509ad170c..9f93a38a0e 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.h +++ b/audio/core/all-versions/default/include/core/default/DevicesFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,10 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_DEVICESFACTORY_H +#define ANDROID_HARDWARE_AUDIO_DEVICESFACTORY_H + +#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h) #include <hardware/audio.h> @@ -24,23 +27,20 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IDevicesFactory; -using ::android::hardware::audio::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::CPP_VERSION; struct DevicesFactory : public IDevicesFactory { -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) override; -#endif -#ifdef AUDIO_HAL_VERSION_4_0 +#elif MAJOR_VERSION >= 4 Return<void> openDevice(const hidl_string& device, openDevice_cb _hidl_cb) override; Return<void> openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) override; #endif @@ -56,7 +56,9 @@ struct DevicesFactory : public IDevicesFactory { extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name); } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_DEVICESFACTORY_H diff --git a/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.h b/audio/core/all-versions/default/include/core/default/ParametersUtil.h index 35ff1105ea..45d9b2140d 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.h +++ b/audio/core/all-versions/default/include/core/default/ParametersUtil.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,10 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_PARAMETERS_UTIL_H_ +#define ANDROID_HARDWARE_AUDIO_PARAMETERS_UTIL_H_ + +#include PATH(android/hardware/audio/FILE_VERSION/types.h) #include <functional> #include <memory> @@ -25,14 +28,13 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress; -using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue; -using ::android::hardware::audio::AUDIO_HAL_VERSION::Result; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; class ParametersUtil { public: @@ -60,7 +62,9 @@ class ParametersUtil { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_PARAMETERS_UTIL_H_ diff --git a/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h index 42996d703e..9d69cb0994 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.h +++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_PRIMARYDEVICE_H +#define ANDROID_HARDWARE_AUDIO_PRIMARYDEVICE_H + +#include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h) + +#include "Device.h" #include <hidl/Status.h> @@ -23,33 +28,21 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioConfig; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioInputFlag; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioOutputFlag; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPort; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortConfig; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IPrimaryDevice; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut; -using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue; -using ::android::hardware::audio::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; struct PrimaryDevice : public IPrimaryDevice { explicit PrimaryDevice(audio_hw_device_t* device); - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IDevice follow. Return<Result> initCheck() override; Return<Result> setMasterVolume(float volume) override; Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb) override; @@ -62,7 +55,7 @@ struct PrimaryDevice : public IPrimaryDevice { Return<void> openOutputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioOutputFlagBitfield flags, -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 const SourceMetadata& sourceMetadata, #endif openOutputStream_cb _hidl_cb) override; @@ -70,7 +63,7 @@ struct PrimaryDevice : public IPrimaryDevice { Return<void> openInputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioInputFlagBitfield flags, AudioSource source, openInputStream_cb _hidl_cb); -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return<void> openInputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioInputFlagBitfield flags, const SinkMetadata& sinkMetadata, @@ -87,13 +80,13 @@ struct PrimaryDevice : public IPrimaryDevice { Return<Result> setScreenState(bool turnedOn) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<AudioHwSync> getHwAvSync() override; Return<void> getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; Return<void> debugDump(const hidl_handle& fd) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> getHwAvSync(getHwAvSync_cb _hidl_cb) override; Return<void> getParameters(const hidl_vec<ParameterValue>& context, const hidl_vec<hidl_string>& keys, @@ -106,7 +99,7 @@ struct PrimaryDevice : public IPrimaryDevice { Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IPrimaryDevice follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow. Return<Result> setVoiceVolume(float volume) override; Return<Result> setMode(AudioMode mode) override; Return<void> getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) override; @@ -118,7 +111,7 @@ struct PrimaryDevice : public IPrimaryDevice { Return<void> getHacEnabled(getHacEnabled_cb _hidl_cb) override; Return<Result> setHacEnabled(bool enabled) override; -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return<Result> setBtScoHeadsetDebugName(const hidl_string& name) override; Return<void> getBtHfpEnabled(getBtHfpEnabled_cb _hidl_cb) override; Return<Result> setBtHfpEnabled(bool enabled) override; @@ -134,7 +127,9 @@ struct PrimaryDevice : public IPrimaryDevice { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_PRIMARYDEVICE_H diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Stream.h b/audio/core/all-versions/default/include/core/default/Stream.h index 7cf12dd433..91df0c7703 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/Stream.h +++ b/audio/core/all-versions/default/include/core/default/Stream.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_STREAM_H +#define ANDROID_HARDWARE_AUDIO_STREAM_H + +#include PATH(android/hardware/audio/FILE_VERSION/IStream.h) + +#include "ParametersUtil.h" #include <vector> @@ -28,22 +33,17 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::implementation::AudioChannelBitfield; -using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStream; -using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue; -using ::android::hardware::audio::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioChannelBitfield; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; struct Stream : public IStream, public ParametersUtil { explicit Stream(audio_stream_t* stream); @@ -55,12 +55,12 @@ struct Stream : public IStream, public ParametersUtil { */ static constexpr uint32_t MAX_BUFFER_SIZE = 2 << 30 /* == 1GiB */; - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IStream follow. Return<uint64_t> getFrameSize() override; Return<uint64_t> getFrameCount() override; Return<uint64_t> getBufferSize() override; Return<uint32_t> getSampleRate() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; #endif @@ -76,14 +76,14 @@ struct Stream : public IStream, public ParametersUtil { Return<Result> addEffect(uint64_t effectId) override; Return<Result> removeEffect(uint64_t effectId) override; Return<Result> standby() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<AudioDevice> getDevice() override; Return<Result> setDevice(const DeviceAddress& address) override; Return<void> getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> getDevices(getDevices_cb _hidl_cb) override; Return<Result> setDevices(const hidl_vec<DeviceAddress>& devices) override; Return<void> getParameters(const hidl_vec<ParameterValue>& context, @@ -100,7 +100,7 @@ struct Stream : public IStream, public ParametersUtil { Return<Result> close() override; Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> debugDump(const hidl_handle& fd) override; #endif @@ -171,7 +171,7 @@ Return<void> StreamMmap<T>::createMmapBuffer(int32_t minSizeFrames, size_t frame halInfo.buffer_size_frames = abs(halInfo.buffer_size_frames); info.sharedMemory = // hidl_memory size must always be positive hidl_memory("audio_buffer", hidlHandle, frameSize * halInfo.buffer_size_frames); -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 if (applicationShareable) { halInfo.buffer_size_frames *= -1; } @@ -210,7 +210,9 @@ Return<void> StreamMmap<T>::getMmapPosition(IStream::getMmapPosition_cb _hidl_cb } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_STREAM_H diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.h b/audio/core/all-versions/default/include/core/default/StreamIn.h index f226e63f70..6209b8f996 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.h +++ b/audio/core/all-versions/default/include/core/default/StreamIn.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,13 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_STREAMIN_H +#define ANDROID_HARDWARE_AUDIO_STREAMIN_H + +#include PATH(android/hardware/audio/FILE_VERSION/IStreamIn.h) + +#include "Device.h" +#include "Stream.h" #include <atomic> #include <memory> @@ -28,23 +34,16 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStream; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn; -using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue; -using ::android::hardware::audio::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; struct StreamIn : public IStreamIn { typedef MessageQueue<ReadParameters, kSynchronizedReadWrite> CommandMQ; @@ -53,12 +52,12 @@ struct StreamIn : public IStreamIn { StreamIn(const sp<Device>& device, audio_stream_in_t* stream); - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IStream follow. Return<uint64_t> getFrameSize() override; Return<uint64_t> getFrameCount() override; Return<uint64_t> getBufferSize() override; Return<uint32_t> getSampleRate() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; #endif @@ -74,14 +73,14 @@ struct StreamIn : public IStreamIn { Return<Result> addEffect(uint64_t effectId) override; Return<Result> removeEffect(uint64_t effectId) override; Return<Result> standby() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<AudioDevice> getDevice() override; Return<Result> setDevice(const DeviceAddress& address) override; Return<void> getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> getDevices(getDevices_cb _hidl_cb) override; Return<Result> setDevices(const hidl_vec<DeviceAddress>& devices) override; Return<void> getParameters(const hidl_vec<ParameterValue>& context, @@ -94,11 +93,11 @@ struct StreamIn : public IStreamIn { Return<Result> close() override; Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> debugDump(const hidl_handle& fd) override; #endif - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IStreamIn follow. Return<void> getAudioSource(getAudioSource_cb _hidl_cb) override; Return<Result> setGain(float gain) override; Return<void> prepareForReading(uint32_t frameSize, uint32_t framesCount, @@ -109,11 +108,14 @@ struct StreamIn : public IStreamIn { Return<Result> stop() override; Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override; -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return<void> updateSinkMetadata(const SinkMetadata& sinkMetadata) override; Return<void> getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) override; #endif - +#if MAJOR_VERSION >= 5 + Return<Result> setMicrophoneDirection(MicrophoneDirection direction) override; + Return<Result> setMicrophoneFieldDimension(float zoom) override; +#endif static Result getCapturePositionImpl(audio_stream_in_t* stream, uint64_t* frames, uint64_t* time); @@ -134,7 +136,9 @@ struct StreamIn : public IStreamIn { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_STREAMIN_H diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h index 134d7b9bbe..b0980053e4 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.h +++ b/audio/core/all-versions/default/include/core/default/StreamOut.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,13 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_STREAMOUT_H +#define ANDROID_HARDWARE_AUDIO_STREAMOUT_H + +#include PATH(android/hardware/audio/FILE_VERSION/IStreamOut.h) + +#include "Device.h" +#include "Stream.h" #include <atomic> #include <memory> @@ -28,25 +34,16 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat; -using ::android::hardware::audio::AUDIO_HAL_VERSION::AudioDrain; -using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStream; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut; -using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOutCallback; -using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue; -using ::android::hardware::audio::AUDIO_HAL_VERSION::Result; -using ::android::hardware::audio::AUDIO_HAL_VERSION::TimeSpec; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; struct StreamOut : public IStreamOut { typedef MessageQueue<WriteCommand, kSynchronizedReadWrite> CommandMQ; @@ -55,12 +52,12 @@ struct StreamOut : public IStreamOut { StreamOut(const sp<Device>& device, audio_stream_out_t* stream); - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IStream follow. Return<uint64_t> getFrameSize() override; Return<uint64_t> getFrameCount() override; Return<uint64_t> getBufferSize() override; Return<uint32_t> getSampleRate() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; #endif @@ -76,14 +73,14 @@ struct StreamOut : public IStreamOut { Return<Result> addEffect(uint64_t effectId) override; Return<Result> removeEffect(uint64_t effectId) override; Return<Result> standby() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<AudioDevice> getDevice() override; Return<Result> setDevice(const DeviceAddress& address) override; Return<void> getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return<void> getDevices(getDevices_cb _hidl_cb) override; Return<Result> setDevices(const hidl_vec<DeviceAddress>& devices) override; Return<void> getParameters(const hidl_vec<ParameterValue>& context, @@ -96,11 +93,11 @@ struct StreamOut : public IStreamOut { Return<Result> close() override; Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return<void> debugDump(const hidl_handle& fd) override; #endif - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IStreamOut follow. Return<uint32_t> getLatency() override; Return<Result> setVolume(float left, float right) override; Return<void> prepareForWriting(uint32_t frameSize, uint32_t framesCount, @@ -120,7 +117,7 @@ struct StreamOut : public IStreamOut { Return<Result> stop() override; Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override; -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override; Return<Result> selectPresentation(int32_t presentationId, int32_t programId) override; #endif @@ -148,7 +145,9 @@ struct StreamOut : public IStreamOut { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_STREAMOUT_H diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Util.h b/audio/core/all-versions/default/include/core/default/Util.h index 350fd867e6..78ae03eab2 100644 --- a/audio/core/all-versions/default/include/core/all-versions/default/Util.h +++ b/audio/core/all-versions/default/include/core/default/Util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -14,7 +14,10 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_UTIL_H +#define ANDROID_HARDWARE_AUDIO_UTIL_H + +#include PATH(android/hardware/audio/FILE_VERSION/types.h) #include <algorithm> #include <vector> @@ -24,10 +27,11 @@ namespace android { namespace hardware { namespace audio { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::AUDIO_HAL_VERSION::Result; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; /** @return true if gain is between 0 and 1 included. */ constexpr bool isGainNormalized(float gain) { @@ -68,7 +72,9 @@ static inline Result analyzeStatus(const char* className, const char* funcName, } // namespace util } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_UTIL_H diff --git a/audio/core/4.0/vts/OWNERS b/audio/core/all-versions/vts/OWNERS index 8711a9ff6a..0ea4666443 100644 --- a/audio/core/4.0/vts/OWNERS +++ b/audio/core/all-versions/vts/OWNERS @@ -2,4 +2,4 @@ elaurent@google.com krocard@google.com mnaganov@google.com yim@google.com -zhuoyao@google.com
\ No newline at end of file +zhuoyao@google.com diff --git a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp new file mode 100644 index 0000000000..7906bf1b62 --- /dev/null +++ b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp @@ -0,0 +1,78 @@ +/* + * 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 "AudioPrimaryHidlHalTest.h" + +static void testGetDevice(IStream* stream, AudioDevice expectedDevice) { + // Unfortunately the interface does not allow the implementation to return + // NOT_SUPPORTED + // Thus allow NONE as signaling that the call is not supported. + auto ret = stream->getDevice(); + ASSERT_IS_OK(ret); + AudioDevice device = ret; + ASSERT_TRUE(device == expectedDevice || device == AudioDevice::NONE) + << "Expected: " << ::testing::PrintToString(expectedDevice) + << "\n Actual: " << ::testing::PrintToString(device); +} + +TEST_IO_STREAM(GetDevice, "Check that the stream device == the one it was opened with", + areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") + : testGetDevice(stream.get(), address.device)) + +static void testSetDevice(IStream* stream, const DeviceAddress& address) { + DeviceAddress otherAddress = address; + otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER + : AudioDevice::IN_BUILTIN_MIC; + EXPECT_OK(stream->setDevice(otherAddress)); + + ASSERT_OK(stream->setDevice(address)); // Go back to the original value +} + +TEST_IO_STREAM(SetDevice, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC", + areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") + : testSetDevice(stream.get(), address)) + +static void testConnectedState(IStream* stream) { + DeviceAddress address = {}; + using AD = AudioDevice; + for (auto device : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { + address.device = device; + + ASSERT_OK(stream->setConnectedState(address, true)); + ASSERT_OK(stream->setConnectedState(address, false)); + } +} +TEST_IO_STREAM(SetConnectedState, + "Check that the stream can be notified of device connection and " + "deconnection", + testConnectedState(stream.get())) + +TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync())); + +TEST_F(AudioPrimaryHidlTest, setMode) { + doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise"); + // Test Invalid values + for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) { + SCOPED_TRACE("mode=" + toString(mode)); + ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode)); + } + // Test valid values + for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE, + AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { + SCOPED_TRACE("mode=" + toString(mode)); + ASSERT_OK(device->setMode(mode)); + } +} diff --git a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalUtils.h b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalUtils.h new file mode 100644 index 0000000000..1cffd41831 --- /dev/null +++ b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalUtils.h @@ -0,0 +1,74 @@ +/* + * 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 PATH(android/hardware/audio/FILE_VERSION/IStream.h) +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) +#include <hidl/HidlSupport.h> + +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::audio::common::CPP_VERSION::AudioChannelMask; +using ::android::hardware::audio::common::CPP_VERSION::AudioFormat; +using ::android::hardware::audio::CPP_VERSION::IStream; +using ::android::hardware::audio::CPP_VERSION::ParameterValue; +using ::android::hardware::audio::CPP_VERSION::Result; + +using namespace ::android::hardware::audio::common::test::utility; + +struct Parameters { + template <class T, class ReturnIn> + static auto get(T t, hidl_vec<hidl_string> keys, ReturnIn returnIn) { + return t->getParameters(keys, returnIn); + } + template <class T> + static auto set(T t, hidl_vec<ParameterValue> values) { + return t->setParameters(values); + } +}; + +// The default hal should probably return a NOT_SUPPORTED if the hal +// does not expose +// capability retrieval. For now it returns an empty list if not +// implemented +struct GetSupported { + template <class Vec> + static Result convertToResult(const Vec& vec) { + return vec.size() == 0 ? Result::NOT_SUPPORTED : Result::OK; + } + + static Result sampleRates(IStream* stream, hidl_vec<uint32_t>& rates) { + EXPECT_OK(stream->getSupportedSampleRates(returnIn(rates))); + return convertToResult(rates); + } + + static Result channelMasks(IStream* stream, hidl_vec<AudioChannelMask>& channels) { + EXPECT_OK(stream->getSupportedChannelMasks(returnIn(channels))); + return convertToResult(channels); + } + + static Result formats(IStream* stream, hidl_vec<AudioFormat>& capabilities) { + EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities))); + // TODO: this should be an optional function + return Result::OK; + } +}; + +template <class T> +auto dump(T t, hidl_handle handle) { + return t->debugDump(handle); +} diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp new file mode 100644 index 0000000000..022f75e849 --- /dev/null +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -0,0 +1,309 @@ +/* + * 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 "AudioPrimaryHidlHalTest.h" + +static void waitForDeviceDestruction() { + // FIXME: there is no way to know when the remote IDevice is being destroyed + // Binder does not support testing if an object is alive, thus + // wait for 100ms to let the binder destruction propagates and + // the remote device has the time to be destroyed. + // flushCommand makes sure all local command are sent, thus should reduce + // the latency between local and remote destruction. + IPCThreadState::self()->flushCommands(); + usleep(100); +} + +TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { + doc::test("Calling openDevice(\"primary\") should return the primary device."); + { + Result result; + sp<IDevice> baseDevice; + ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice))); + ASSERT_OK(result); + ASSERT_TRUE(baseDevice != nullptr); + + Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice); + ASSERT_TRUE(primaryDevice.isOk()); + ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr); + } // Destroy local IDevice proxy + waitForDeviceDestruction(); +} + +////////////////////////////////////////////////////////////////////////////// +/////////////////////////// get(Active)Microphones /////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { + doc::test("Make sure getMicrophones always succeeds"); + hidl_vec<MicrophoneInfo> microphones; + ASSERT_OK(device->getMicrophones(returnIn(res, microphones))); + ASSERT_OK(res); + if (microphones.size() > 0) { + // When there is microphone on the phone, try to open an input stream + // and query for the active microphones. + doc::test( + "Make sure getMicrophones always succeeds" + "and getActiveMicrophones always succeeds when recording from these microphones."); + AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE; + AudioConfig config{}; + config.channelMask = mkEnumBitfield(AudioChannelMask::IN_MONO); + config.sampleRateHz = 8000; + config.format = AudioFormat::PCM_16_BIT; + auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE); + const SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}}; + EventFlag* efGroup; + for (auto microphone : microphones) { + if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) { + continue; + } + sp<IStreamIn> stream; + AudioConfig suggestedConfig{}; + ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags, + initMetadata, + returnIn(res, stream, suggestedConfig))); + if (res != Result::OK) { + ASSERT_TRUE(stream == nullptr); + AudioConfig suggestedConfigRetry{}; + ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, + suggestedConfig, flags, initMetadata, + returnIn(res, stream, suggestedConfigRetry))); + } + ASSERT_OK(res); + hidl_vec<MicrophoneInfo> activeMicrophones; + Result readRes; + typedef MessageQueue<IStreamIn::ReadParameters, kSynchronizedReadWrite> CommandMQ; + typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ; + std::unique_ptr<CommandMQ> commandMQ; + std::unique_ptr<DataMQ> dataMQ; + size_t frameSize = stream->getFrameSize(); + size_t frameCount = stream->getBufferSize() / frameSize; + ASSERT_OK(stream->prepareForReading( + frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto&) { + readRes = r; + if (readRes == Result::OK) { + commandMQ.reset(new CommandMQ(c)); + dataMQ.reset(new DataMQ(d)); + if (dataMQ->isValid() && dataMQ->getEventFlagWord()) { + EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup); + } + } + })); + ASSERT_OK(readRes); + IStreamIn::ReadParameters params; + params.command = IStreamIn::ReadCommand::READ; + ASSERT_TRUE(commandMQ != nullptr); + ASSERT_TRUE(commandMQ->isValid()); + ASSERT_TRUE(commandMQ->write(¶ms)); + efGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); + uint32_t efState = 0; + efGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); + if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) { + ASSERT_OK(stream->getActiveMicrophones(returnIn(res, activeMicrophones))); + ASSERT_OK(res); + ASSERT_NE(0U, activeMicrophones.size()); + } + stream->close(); + if (efGroup) { + EventFlag::deleteEventFlag(&efGroup); + } + } + } +} + +TEST_F(AudioPrimaryHidlTest, SetConnectedState) { + doc::test("Check that the HAL can be notified of device connection and deconnection"); + using AD = AudioDevice; + for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { + SCOPED_TRACE("device=" + ::testing::PrintToString(deviceType)); + for (bool state : {true, false}) { + SCOPED_TRACE("state=" + ::testing::PrintToString(state)); + DeviceAddress address = {}; + address.device = deviceType; + auto ret = device->setConnectedState(address, state); + ASSERT_TRUE(ret.isOk()); + if (ret == Result::NOT_SUPPORTED) { + doc::partialTest("setConnectedState is not supported"); + break; // other deviceType might be supported + } + ASSERT_OK(ret); + } + } + + // Because there is no way of knowing if the devices were connected before + // calling setConnectedState, there is no way to restore the HAL to its + // initial state. To workaround this, destroy the HAL at the end of this test. + device.clear(); + waitForDeviceDestruction(); +} + +static void testGetDevices(IStream* stream, AudioDevice expectedDevice) { + hidl_vec<DeviceAddress> devices; + Result res; + ASSERT_OK(stream->getDevices(returnIn(res, devices))); + if (res == Result::NOT_SUPPORTED) { + return doc::partialTest("GetDevices is not supported"); + } + // The stream was constructed with one device, thus getDevices must only return one + ASSERT_EQ(1U, devices.size()); + AudioDevice device = devices[0].device; + ASSERT_TRUE(device == expectedDevice) + << "Expected: " << ::testing::PrintToString(expectedDevice) + << "\n Actual: " << ::testing::PrintToString(device); +} + +TEST_IO_STREAM(GetDevices, "Check that the stream device == the one it was opened with", + areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") + : testGetDevices(stream.get(), address.device)) + +static void testSetDevices(IStream* stream, const DeviceAddress& address) { + DeviceAddress otherAddress = address; + otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER + : AudioDevice::IN_BUILTIN_MIC; + EXPECT_OK(stream->setDevices({otherAddress})); + + ASSERT_OK(stream->setDevices({address})); // Go back to the original value +} + +TEST_IO_STREAM(SetDevices, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC", + areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") + : testSetDevices(stream.get(), address)) + +static void checkGetHwAVSync(IDevice* device) { + Result res; + AudioHwSync sync; + ASSERT_OK(device->getHwAvSync(returnIn(res, sync))); + if (res == Result::NOT_SUPPORTED) { + return doc::partialTest("getHwAvSync is not supported"); + } + ASSERT_OK(res); +} +TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get())); + +TEST_P(InputStreamTest, updateSinkMetadata) { + doc::test("The HAL should not crash on metadata change"); + + hidl_enum_range<AudioSource> range; + // Test all possible track configuration + for (AudioSource source : range) { + for (float volume : {0.0, 0.5, 1.0}) { + const SinkMetadata metadata = {{{.source = source, .gain = volume}}}; + ASSERT_OK(stream->updateSinkMetadata(metadata)) + << "source=" << toString(source) << ", volume=" << volume; + } + } + + // Do not test concurrent capture as this is not officially supported + + // Set no metadata as if all stream track had stopped + ASSERT_OK(stream->updateSinkMetadata({})); + + // Restore initial + ASSERT_OK(stream->updateSinkMetadata(initMetadata)); +} + +TEST_P(OutputStreamTest, SelectPresentation) { + doc::test("Verify that presentation selection does not crash"); + ASSERT_RESULT(okOrNotSupported, stream->selectPresentation(0, 0)); +} + +TEST_P(OutputStreamTest, updateSourceMetadata) { + doc::test("The HAL should not crash on metadata change"); + + hidl_enum_range<AudioUsage> usageRange; + hidl_enum_range<AudioContentType> contentRange; + // Test all possible track configuration + for (auto usage : usageRange) { + for (auto content : contentRange) { + for (float volume : {0.0, 0.5, 1.0}) { + const SourceMetadata metadata = {{{usage, content, volume}}}; + ASSERT_OK(stream->updateSourceMetadata(metadata)) + << "usage=" << toString(usage) << ", content=" << toString(content) + << ", volume=" << volume; + } + } + } + + // Set many track of different configuration + ASSERT_OK(stream->updateSourceMetadata( + {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 0.1}, + {AudioUsage::VOICE_COMMUNICATION, AudioContentType::SPEECH, 1.0}, + {AudioUsage::ALARM, AudioContentType::SONIFICATION, 0.0}, + {AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}})); + + // Set no metadata as if all stream track had stopped + ASSERT_OK(stream->updateSourceMetadata({})); + + // Restore initial + ASSERT_OK(stream->updateSourceMetadata(initMetadata)); +} + +TEST_F(AudioPrimaryHidlTest, setMode) { + doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise"); + // Test Invalid values + for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) { + ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode))) + << "mode=" << mode; + } + // Test valid values + for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE, + AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { + ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode); + } +} + +TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) { + doc::test( + "Make sure setBtHfpSampleRate either succeeds or " + "indicates that it is not supported at all, or that the provided value is invalid"); + for (auto samplingRate : {8000, 16000, 22050, 24000}) { + ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate)); + } +} + +TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) { + doc::test( + "Make sure setBtHfpVolume is either not supported or " + "only succeed if volume is in [0,1]"); + auto ret = device->setBtHfpVolume(0.0); + ASSERT_TRUE(ret.isOk()); + if (ret == Result::NOT_SUPPORTED) { + doc::partialTest("setBtHfpVolume is not supported"); + return; + } + testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); }); +} + +TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) { + doc::test( + "Make sure setBtScoHeadsetDebugName either succeeds or " + "indicates that it is not supported"); + ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test")); +} + +TEST_F(AudioPrimaryHidlTest, updateRotation) { + doc::test("Check that the hal can receive the current rotation"); + for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180, + Rotation::DEG_270, Rotation::DEG_0}) { + ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation)); + } +} + +TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) { + doc::test("Query and set the BT HFP state"); + testAccessors<OPTIONAL>("BtHfpEnabled", Initial{false, OPTIONAL}, {true}, + &IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled); +} diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h new file mode 100644 index 0000000000..8415053ffc --- /dev/null +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h @@ -0,0 +1,88 @@ +/* + * 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 PATH(android/hardware/audio/FILE_VERSION/IStream.h) +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) +#include <hidl/HidlSupport.h> + +using ::android::hardware::hidl_bitfield; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::audio::common::CPP_VERSION::AudioChannelMask; +using ::android::hardware::audio::common::CPP_VERSION::AudioFormat; +using ::android::hardware::audio::CPP_VERSION::IStream; +using ::android::hardware::audio::CPP_VERSION::ParameterValue; +using ::android::hardware::audio::CPP_VERSION::Result; + +using namespace ::android::hardware::audio::common::test::utility; + +using Rotation = ::android::hardware::audio::CPP_VERSION::IPrimaryDevice::Rotation; +using ::android::hardware::audio::common::CPP_VERSION::AudioContentType; +using ::android::hardware::audio::common::CPP_VERSION::AudioUsage; +using ::android::hardware::audio::CPP_VERSION::MicrophoneInfo; +#if MAJOR_VERSION < 5 +using ::android::hardware::audio::CPP_VERSION::SinkMetadata; +using ::android::hardware::audio::CPP_VERSION::SourceMetadata; +#else +using ::android::hardware::audio::common::CPP_VERSION::SinkMetadata; +using ::android::hardware::audio::common::CPP_VERSION::SourceMetadata; +#endif + +struct Parameters { + template <class T, class ReturnIn> + static auto get(T t, hidl_vec<hidl_string> keys, ReturnIn returnIn) { + hidl_vec<ParameterValue> context; + return t->getParameters(context, keys, returnIn); + } + template <class T> + static auto set(T t, hidl_vec<ParameterValue> values) { + hidl_vec<ParameterValue> context; + return t->setParameters(context, values); + } +}; + +struct GetSupported { + static auto getFormat(IStream* stream) { + auto ret = stream->getFormat(); + EXPECT_TRUE(ret.isOk()); + return ret.withDefault({}); + } + static Result sampleRates(IStream* stream, hidl_vec<uint32_t>& rates) { + Result res; + EXPECT_OK(stream->getSupportedSampleRates(getFormat(stream), returnIn(res, rates))); + return res; + } + + static Result channelMasks(IStream* stream, + hidl_vec<hidl_bitfield<AudioChannelMask>>& channels) { + Result res; + EXPECT_OK(stream->getSupportedChannelMasks(getFormat(stream), returnIn(res, channels))); + return res; + } + + static Result formats(IStream* stream, hidl_vec<AudioFormat>& capabilities) { + EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities))); + // TODO: this should be an optional function + return Result::OK; + } +}; + +template <class T> +auto dump(T t, hidl_handle handle) { + return t->debug(handle, {/* options */}); +} diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp new file mode 100644 index 0000000000..6498289dd4 --- /dev/null +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -0,0 +1,88 @@ +// +// 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. +// + +cc_defaults { + name: "VtsHalAudioTargetTest_defaults", + defaults: ["VtsHalTargetTestDefaults"], + static_libs: [ + "android.hardware.audio.common.test.utility", + "libaudiopolicycomponents", + "libicuuc", + "libicuuc_stubdata", + "libandroidicu", + "libmedia_helper", + "libxml2", + ], + shared_libs: [ + "libfmq", + ], + header_libs: [ + "android.hardware.audio.common.util@all-versions", + ], + test_suites: ["general-tests"], +} + +cc_test { + name: "VtsHalAudioV2_0TargetTest", + defaults: ["VtsHalAudioTargetTest_defaults"], + srcs: [ + "2.0/AudioPrimaryHidlHalTest.cpp", + ], + static_libs: [ + "android.hardware.audio@2.0", + "android.hardware.audio.common@2.0", + ], + cflags: [ + "-DMAJOR_VERSION=2", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_test { + name: "VtsHalAudioV4_0TargetTest", + defaults: ["VtsHalAudioTargetTest_defaults"], + srcs: [ + "4.0/AudioPrimaryHidlHalTest.cpp", + ], + static_libs: [ + "android.hardware.audio@4.0", + "android.hardware.audio.common@4.0", + ], + cflags: [ + "-DMAJOR_VERSION=4", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_test { + name: "VtsHalAudioV5_0TargetTest", + defaults: ["VtsHalAudioTargetTest_defaults"], + srcs: [ + // for now the tests are the same as V4 + "4.0/AudioPrimaryHidlHalTest.cpp", + ], + static_libs: [ + "android.hardware.audio@5.0", + "android.hardware.audio.common@5.0", + ], + cflags: [ + "-DMAJOR_VERSION=5", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} diff --git a/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index a08a2d62bb..a22cc1cfc5 100644 --- a/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "VtsHalAudioV2_0TargetTest" +#define LOG_TAG "VtsHalAudioVTargetTest" #include <algorithm> #include <cmath> @@ -22,71 +22,86 @@ #include <cstdio> #include <initializer_list> #include <limits> +#include <list> #include <string> #include <vector> #include <fcntl.h> #include <unistd.h> +#include <hwbinder/IPCThreadState.h> + #include <VtsHalHidlTargetTestBase.h> #include <android-base/logging.h> -#include <android/hardware/audio/2.0/IDevice.h> -#include <android/hardware/audio/2.0/IDevicesFactory.h> -#include <android/hardware/audio/2.0/IPrimaryDevice.h> -#include <android/hardware/audio/2.0/types.h> -#include <android/hardware/audio/common/2.0/types.h> +#include PATH(android/hardware/audio/FILE_VERSION/IDevice.h) +#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h) +#include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h) +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) + +#include <Serializer.h> +#include <fmq/EventFlag.h> +#include <fmq/MessageQueue.h> + +#include <common/all-versions/VersionUtils.h> #include "utility/AssertOk.h" #include "utility/Documentation.h" #include "utility/EnvironmentTearDown.h" -#define AUDIO_HAL_VERSION V2_0 #include "utility/PrettyPrintAudioTypes.h" #include "utility/ReturnIn.h" +#include "utility/ValidateXml.h" + +/** Provide version specific functions that are used in the generic tests */ +#if MAJOR_VERSION == 2 +#include "2.0/AudioPrimaryHidlHalUtils.h" +#elif MAJOR_VERSION >= 4 +#include "4.0/AudioPrimaryHidlHalUtils.h" +#endif using std::initializer_list; +using std::list; using std::string; using std::to_string; using std::vector; +using ::android::AudioPolicyConfig; +using ::android::HwModule; +using ::android::NO_INIT; +using ::android::OK; using ::android::sp; -using ::android::hardware::Return; +using ::android::status_t; +using ::android::hardware::EventFlag; +using ::android::hardware::hidl_bitfield; +using ::android::hardware::hidl_enum_range; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; +using ::android::hardware::IPCThreadState; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; using ::android::hardware::MQDescriptorSync; -using ::android::hardware::audio::V2_0::AudioDrain; -using ::android::hardware::audio::V2_0::DeviceAddress; -using ::android::hardware::audio::V2_0::IDevice; -using ::android::hardware::audio::V2_0::IPrimaryDevice; -using TtyMode = ::android::hardware::audio::V2_0::IPrimaryDevice::TtyMode; -using ::android::hardware::audio::V2_0::IDevicesFactory; -using ::android::hardware::audio::V2_0::IStream; -using ::android::hardware::audio::V2_0::IStreamIn; -using ::android::hardware::audio::V2_0::TimeSpec; -using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters; -using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus; -using ::android::hardware::audio::V2_0::IStreamOut; -using ::android::hardware::audio::V2_0::IStreamOutCallback; -using ::android::hardware::audio::V2_0::MmapBufferInfo; -using ::android::hardware::audio::V2_0::MmapPosition; -using ::android::hardware::audio::V2_0::ParameterValue; -using ::android::hardware::audio::V2_0::Result; -using ::android::hardware::audio::common::V2_0::AudioChannelMask; -using ::android::hardware::audio::common::V2_0::AudioConfig; -using ::android::hardware::audio::common::V2_0::AudioDevice; -using ::android::hardware::audio::common::V2_0::AudioFormat; -using ::android::hardware::audio::common::V2_0::AudioHandleConsts; -using ::android::hardware::audio::common::V2_0::AudioInputFlag; -using ::android::hardware::audio::common::V2_0::AudioIoHandle; -using ::android::hardware::audio::common::V2_0::AudioMode; -using ::android::hardware::audio::common::V2_0::AudioOffloadInfo; -using ::android::hardware::audio::common::V2_0::AudioOutputFlag; -using ::android::hardware::audio::common::V2_0::AudioSource; -using ::android::hardware::audio::common::V2_0::ThreadInfo; +using ::android::hardware::Return; +using ::android::hardware::audio::common::utils::mkEnumBitfield; +using namespace ::android::hardware::audio::common::CPP_VERSION; using namespace ::android::hardware::audio::common::test::utility; +using namespace ::android::hardware::audio::CPP_VERSION; + +// Typical accepted results from interface methods +static auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED}; +static auto okOrNotSupportedOrInvalidArgs = {Result::OK, Result::NOT_SUPPORTED, + Result::INVALID_ARGUMENTS}; +static auto okOrInvalidStateOrNotSupported = {Result::OK, Result::INVALID_STATE, + Result::NOT_SUPPORTED}; +static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED}; +static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED}; + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////////// Environment ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////// class AudioHidlTestEnvironment : public ::Environment { public: @@ -103,11 +118,103 @@ class HidlTest : public ::testing::VtsHalHidlTargetTestBase { }; ////////////////////////////////////////////////////////////////////////////// +////////////////////////// Audio policy configuration //////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static const std::vector<const char*> kConfigLocations = {"/odm/etc", "/vendor/etc", "/system/etc"}; +static constexpr char kConfigFileName[] = "audio_policy_configuration.xml"; + +// Stringify the argument. +#define QUOTE(x) #x +#define STRINGIFY(x) QUOTE(x) + +TEST(CheckConfig, audioPolicyConfigurationValidation) { + RecordProperty("description", + "Verify that the audio policy configuration file " + "is valid according to the schema"); + + const char* xsd = "/data/local/tmp/audio_policy_configuration_" STRINGIFY(CPP_VERSION) ".xsd"; + EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(kConfigFileName, kConfigLocations, xsd); +} + +struct PolicyConfigData { + android::HwModuleCollection hwModules; + android::DeviceVector availableOutputDevices; + android::DeviceVector availableInputDevices; + sp<android::DeviceDescriptor> defaultOutputDevice; + android::VolumeCurvesCollection volumes; +}; + +class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { + public: + PolicyConfig() + : AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices, + defaultOutputDevice, &volumes) { + for (const char* location : kConfigLocations) { + std::string path = std::string(location) + '/' + kConfigFileName; + if (access(path.c_str(), F_OK) == 0) { + mFilePath = path; + break; + } + } + mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this); + if (mStatus == OK) { + mPrimaryModule = getHwModules().getModuleFromName("primary"); + } + } + status_t getStatus() const { return mStatus; } + std::string getError() const { + if (mFilePath.empty()) { + return std::string{"Could not find "} + kConfigFileName + + " file in: " + testing::PrintToString(kConfigLocations); + } else { + return "Invalid config file: " + mFilePath; + } + } + const std::string& getFilePath() const { return mFilePath; } + sp<const HwModule> getPrimaryModule() const { return mPrimaryModule; } + + private: + status_t mStatus = NO_INIT; + std::string mFilePath; + sp<HwModule> mPrimaryModule = nullptr; +}; + +// Cached policy config after parsing for faster test startup +const PolicyConfig& getCachedPolicyConfig() { + static std::unique_ptr<PolicyConfig> policyConfig = [] { + auto config = std::make_unique<PolicyConfig>(); + environment->registerTearDown([] { policyConfig.reset(); }); + return config; + }(); + return *policyConfig; +} + +class AudioPolicyConfigTest : public HidlTest { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base + + auto& policyConfig = getCachedPolicyConfig(); + ASSERT_EQ(0, policyConfig.getStatus()) << policyConfig.getError(); + + mPrimaryConfig = policyConfig.getPrimaryModule(); + ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: " + << policyConfig.getFilePath(); + } + sp<const HwModule> mPrimaryConfig = nullptr; +}; + +TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) { + doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)"); +} + +////////////////////////////////////////////////////////////////////////////// ////////////////////// getService audio_devices_factory ////////////////////// ////////////////////////////////////////////////////////////////////////////// // Test all audio devices -class AudioHidlTest : public HidlTest { +class AudioHidlTest : public AudioPolicyConfigTest { public: void SetUp() override { ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base @@ -127,15 +234,20 @@ class AudioHidlTest : public HidlTest { sp<IDevicesFactory> AudioHidlTest::devicesFactory; TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) { - doc::test("test the getService (called in SetUp)"); + doc::test("Test the getService (called in SetUp)"); } TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) { - doc::test("test passing an invalid parameter to openDevice"); - IDevicesFactory::Result result; + doc::test("Test passing an invalid parameter to openDevice"); + Result result; sp<IDevice> device; - ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device(-1), returnIn(result, device))); - ASSERT_EQ(IDevicesFactory::Result::INVALID_ARGUMENTS, result); +#if MAJOR_VERSION == 2 + auto invalidDevice = IDevicesFactory::Device(-1); +#elif MAJOR_VERSION >= 4 + auto invalidDevice = "Non existing device"; +#endif + ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device))); + ASSERT_EQ(Result::INVALID_ARGUMENTS, result); ASSERT_TRUE(device == nullptr); } @@ -151,22 +263,32 @@ class AudioPrimaryHidlTest : public AudioHidlTest { ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base if (device == nullptr) { - IDevicesFactory::Result result; - sp<IDevice> baseDevice; - ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY, - returnIn(result, baseDevice))); - ASSERT_OK(result); - ASSERT_TRUE(baseDevice != nullptr); - - environment->registerTearDown([] { device.clear(); }); - device = IPrimaryDevice::castFrom(baseDevice); + initPrimaryDevice(); ASSERT_TRUE(device != nullptr); + environment->registerTearDown([] { device.clear(); }); } } protected: // Cache the device opening to speed up each test by ~0.5s static sp<IPrimaryDevice> device; + + private: + void initPrimaryDevice() { + Result result; +#if MAJOR_VERSION == 2 + sp<IDevice> baseDevice; + ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY, + returnIn(result, baseDevice))); + ASSERT_OK(result); + ASSERT_TRUE(baseDevice != nullptr); + + device = IPrimaryDevice::castFrom(baseDevice); +#elif MAJOR_VERSION >= 4 + ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device))); + ASSERT_OK(result); +#endif + } }; sp<IPrimaryDevice> AudioPrimaryHidlTest::device; @@ -186,53 +308,59 @@ TEST_F(AudioPrimaryHidlTest, Init) { template <class Property> class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { protected: - /** Test a property getter and setter. */ - template <class Getter, class Setter> - void testAccessors(const string& propertyName, const vector<Property>& valuesToTest, - Setter setter, Getter getter, const vector<Property>& invalidValues = {}) { - Property initialValue; // Save initial value to restore it at the end - // of the test + enum Optionality { REQUIRED, OPTIONAL }; + struct Initial { // Initial property value + Initial(Property value, Optionality check = REQUIRED) : value(value), check(check) {} + Property value; + Optionality check; // If this initial value should be checked + }; + /** Test a property getter and setter. + * The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL. + */ + template <Optionality optionality = REQUIRED, class Getter, class Setter> + void testAccessors(const string& propertyName, const Initial expectedInitial, + list<Property> valuesToTest, Setter setter, Getter getter, + const vector<Property>& invalidValues = {}) { + const auto expectedResults = {Result::OK, + optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK}; + + Property initialValue = expectedInitial.value; ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue))); - ASSERT_OK(res); + ASSERT_RESULT(expectedResults, res); + if (res == Result::OK && expectedInitial.check == REQUIRED) { + EXPECT_EQ(expectedInitial.value, initialValue); + } + valuesToTest.push_front(expectedInitial.value); + valuesToTest.push_back(initialValue); for (Property setValue : valuesToTest) { SCOPED_TRACE("Test " + propertyName + " getter and setter for " + testing::PrintToString(setValue)); - ASSERT_OK((device.get()->*setter)(setValue)); + auto ret = (device.get()->*setter)(setValue); + ASSERT_RESULT(expectedResults, ret); + if (ret == Result::NOT_SUPPORTED) { + doc::partialTest(propertyName + " setter is not supported"); + break; + } Property getValue; // Make sure the getter returns the same value just set ASSERT_OK((device.get()->*getter)(returnIn(res, getValue))); - ASSERT_OK(res); + ASSERT_RESULT(expectedResults, res); + if (res == Result::NOT_SUPPORTED) { + doc::partialTest(propertyName + " getter is not supported"); + continue; + } EXPECT_EQ(setValue, getValue); } for (Property invalidValue : invalidValues) { SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " + testing::PrintToString(invalidValue)); - EXPECT_RESULT(Result::INVALID_ARGUMENTS, (device.get()->*setter)(invalidValue)); + EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue)); } - ASSERT_OK((device.get()->*setter)(initialValue)); // restore initial value - } - - /** Test the getter and setter of an optional feature. */ - template <class Getter, class Setter> - void testOptionalAccessors(const string& propertyName, const vector<Property>& valuesToTest, - Setter setter, Getter getter, - const vector<Property>& invalidValues = {}) { - doc::test("Test the optional " + propertyName + " getters and setter"); - { - SCOPED_TRACE("Test feature support by calling the getter"); - Property initialValue; - ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue))); - if (res == Result::NOT_SUPPORTED) { - doc::partialTest(propertyName + " getter is not supported"); - return; - } - ASSERT_OK(res); // If it is supported it must succeed - } - // The feature is supported, test it - testAccessors(propertyName, valuesToTest, setter, getter, invalidValues); + // Restore initial value + EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue)); } }; @@ -240,24 +368,22 @@ using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>; TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) { doc::test("Check that the mic can be muted and unmuted"); - testAccessors("mic mute", {true, false, true}, &IDevice::setMicMute, &IDevice::getMicMute); + testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute); // TODO: check that the mic is really muted (all sample are 0) } TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) { - doc::test( - "If master mute is supported, try to mute and unmute the master " - "output"); - testOptionalAccessors("master mute", {true, false, true}, &IDevice::setMasterMute, - &IDevice::getMasterMute); + doc::test("If master mute is supported, try to mute and unmute the master output"); + testAccessors<OPTIONAL>("master mute", Initial{false}, {true}, &IDevice::setMasterMute, + &IDevice::getMasterMute); // TODO: check that the master volume is really muted } using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>; TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { doc::test("Test the master volume if supported"); - testOptionalAccessors( - "master volume", {0, 0.5, 1}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, + testAccessors<OPTIONAL>( + "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()}); // TODO: check that the master volume is really changed } @@ -295,6 +421,21 @@ TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { public: + // for retro compatibility only test the primary device IN_BUILTIN_MIC + // FIXME: in the next audio HAL version, test all available devices + static bool primaryHasMic() { + auto& policyConfig = getCachedPolicyConfig(); + if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) { + return true; // Could not get the information, run all tests + } + auto getMic = [](auto& devs) { return devs.getDevice( + AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT); }; + auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices()); + auto availableMic = getMic(policyConfig.getAvailableInputDevices()); + + return primaryMic != nullptr && primaryMic->equals(availableMic); + } + // Cache result ? static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() { return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, @@ -314,10 +455,12 @@ class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { } static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() { + if (!primaryHasMic()) return {}; return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100}, {AudioFormat::PCM_16_BIT}); } static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() { + if (!primaryHasMic()) return {}; return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000}, {AudioFormat::PCM_16_BIT}); } @@ -337,7 +480,7 @@ class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { for (auto format : formats) { AudioConfig config{}; // leave offloadInfo to 0 - config.channelMask = channelMask; + config.channelMask = mkEnumBitfield(channelMask); config.sampleRateHz = sampleRate; config.format = format; // FIXME: leave frameCount to 0 ? @@ -358,10 +501,10 @@ static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) const AudioConfig& config = info.param; return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" + // "MONO" is more clear than "FRONT_LEFT" - ((config.channelMask == AudioChannelMask::OUT_MONO || - config.channelMask == AudioChannelMask::IN_MONO) + ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) || + config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO)) ? "MONO" - : toString(config.channelMask)); + : ::testing::PrintToString(config.channelMask)); } ////////////////////////////////////////////////////////////////////////////// @@ -433,11 +576,7 @@ INSTANTIATE_TEST_CASE_P( TEST_F(AudioPrimaryHidlTest, setScreenState) { doc::test("Check that the hal can receive the screen state"); for (bool turnedOn : {false, true, true, false, false}) { - auto ret = device->setScreenState(turnedOn); - ASSERT_IS_OK(ret); - Result result = ret; - auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED}; - ASSERT_RESULT(okOrNotSupported, result); + ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn)); } } @@ -447,12 +586,13 @@ TEST_F(AudioPrimaryHidlTest, setScreenState) { TEST_F(AudioPrimaryHidlTest, getParameters) { doc::test("Check that the hal can set and get parameters"); + hidl_vec<ParameterValue> context; hidl_vec<hidl_string> keys; hidl_vec<ParameterValue> values; - ASSERT_OK(device->getParameters(keys, returnIn(res, values))); - ASSERT_OK(device->setParameters(values)); + ASSERT_OK(Parameters::get(device, keys, returnIn(res, values))); + ASSERT_OK(Parameters::set(device, values)); values.resize(0); - ASSERT_OK(device->setParameters(values)); + ASSERT_OK(Parameters::set(device, values)); } ////////////////////////////////////////////////////////////////////////////// @@ -495,12 +635,12 @@ static void testDebugDump(DebugDump debugDump) { TEST_F(AudioPrimaryHidlTest, DebugDump) { doc::test("Check that the hal can dump its state without error"); - testDebugDump([](const auto& handle) { return device->debugDump(handle); }); + testDebugDump([](const auto& handle) { return dump(device, handle); }); } TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { doc::test("Check that the hal dump doesn't crash on invalid arguments"); - ASSERT_OK(device->debugDump(hidl_handle())); + ASSERT_OK(dump(device, hidl_handle())); } ////////////////////////////////////////////////////////////////////////////// @@ -569,13 +709,26 @@ class OutputStreamTest : public OpenStreamTest<IStreamOut> { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base address.device = AudioDevice::OUT_DEFAULT; const AudioConfig& config = GetParam(); - AudioOutputFlag flags = AudioOutputFlag::NONE; // TODO: test all flag combination + // TODO: test all flag combination + auto flags = mkEnumBitfield(AudioOutputFlag::NONE); testOpen( [&](AudioIoHandle handle, AudioConfig config, auto cb) { +#if MAJOR_VERSION == 2 return device->openOutputStream(handle, address, config, flags, cb); +#elif MAJOR_VERSION >= 4 + return device->openOutputStream(handle, address, config, flags, initMetadata, cb); +#endif }, config); } +#if MAJOR_VERSION >= 4 + + protected: + const SourceMetadata initMetadata = { + { { AudioUsage::MEDIA, + AudioContentType::MUSIC, + 1 /* gain */ } }}; +#endif }; TEST_P(OutputStreamTest, OpenOutputStreamTest) { doc::test( @@ -604,14 +757,21 @@ class InputStreamTest : public OpenStreamTest<IStreamIn> { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base address.device = AudioDevice::IN_DEFAULT; const AudioConfig& config = GetParam(); - AudioInputFlag flags = AudioInputFlag::NONE; // TODO: test all flag combination - AudioSource source = AudioSource::DEFAULT; // TODO: test all flag combination + // TODO: test all supported flags and source + auto flags = mkEnumBitfield(AudioInputFlag::NONE); testOpen( [&](AudioIoHandle handle, AudioConfig config, auto cb) { - return device->openInputStream(handle, address, config, flags, source, cb); + return device->openInputStream(handle, address, config, flags, initMetadata, cb); }, config); } + + protected: +#if MAJOR_VERSION == 2 + const AudioSource initMetadata = AudioSource::DEFAULT; +#elif MAJOR_VERSION >= 4 + const SinkMetadata initMetadata = {{{.source = AudioSource::DEFAULT, .gain = 1}}}; +#endif }; TEST_P(InputStreamTest, OpenInputStreamTest) { @@ -682,27 +842,26 @@ TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it wa template <class Property, class CapabilityGetter> static void testCapabilityGetter(const string& name, IStream* stream, - CapabilityGetter capablityGetter, + CapabilityGetter capabilityGetter, Return<Property> (IStream::*getter)(), Return<Result> (IStream::*setter)(Property), bool currentMustBeSupported = true) { hidl_vec<Property> capabilities; - ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities))); - if (capabilities.size() == 0) { - // The default hal should probably return a NOT_SUPPORTED if the hal - // does not expose - // capability retrieval. For now it returns an empty list if not - // implemented + auto ret = capabilityGetter(stream, capabilities); + ASSERT_RESULT(okOrNotSupported, ret); + bool notSupported = ret == Result::NOT_SUPPORTED; + if (notSupported) { doc::partialTest(name + " is not supported"); return; }; if (currentMustBeSupported) { + ASSERT_NE(0U, capabilities.size()) << name << " must not return an empty list"; Property currentValue = extract((stream->*getter)()); - EXPECT_NE(std::find(capabilities.begin(), capabilities.end(), currentValue), - capabilities.end()) - << "current " << name << " is not in the list of the supported ones " - << toString(capabilities); + EXPECT_TRUE(std::find(capabilities.begin(), capabilities.end(), currentValue) != + capabilities.end()) + << "value returned by " << name << "() = " << testing::PrintToString(currentValue) + << " is not in the list of the supported ones " << toString(capabilities); } // Check that all declared supported values are indeed supported @@ -720,7 +879,7 @@ static void testCapabilityGetter(const string& name, IStream* stream, TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported", testCapabilityGetter("getSupportedSampleRate", stream.get(), - &IStream::getSupportedSampleRates, &IStream::getSampleRate, + &GetSupported::sampleRates, &IStream::getSampleRate, &IStream::setSampleRate, // getSupportedSampleRate returns the native sampling rates, // (the sampling rates that can be played without resampling) @@ -729,46 +888,16 @@ TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declar TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported", testCapabilityGetter("getSupportedChannelMask", stream.get(), - &IStream::getSupportedChannelMasks, &IStream::getChannelMask, + &GetSupported::channelMasks, &IStream::getChannelMask, &IStream::setChannelMask)) TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported", - testCapabilityGetter("getSupportedFormat", stream.get(), - &IStream::getSupportedFormats, &IStream::getFormat, - &IStream::setFormat)) - -static void testGetDevice(IStream* stream, AudioDevice expectedDevice) { - // Unfortunately the interface does not allow the implementation to return - // NOT_SUPPORTED - // Thus allow NONE as signaling that the call is not supported. - auto ret = stream->getDevice(); - ASSERT_IS_OK(ret); - AudioDevice device = ret; - ASSERT_TRUE(device == expectedDevice || device == AudioDevice::NONE) - << "Expected: " << ::testing::PrintToString(expectedDevice) - << "\n Actual: " << ::testing::PrintToString(device); -} - -TEST_IO_STREAM(GetDevice, "Check that the stream device == the one it was opened with", - areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") - : testGetDevice(stream.get(), address.device)) - -static void testSetDevice(IStream* stream, const DeviceAddress& address) { - DeviceAddress otherAddress = address; - otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER - : AudioDevice::IN_BUILTIN_MIC; - EXPECT_OK(stream->setDevice(otherAddress)); - - ASSERT_OK(stream->setDevice(address)); // Go back to the original value -} - -TEST_IO_STREAM(SetDevice, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC", - areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") - : testSetDevice(stream.get(), address)) + testCapabilityGetter("getSupportedFormat", stream.get(), &GetSupported::formats, + &IStream::getFormat, &IStream::setFormat)) static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) { uint32_t sampleRateHz; - AudioChannelMask mask; + auto mask = mkEnumBitfield<AudioChannelMask>({}); AudioFormat format; stream->getAudioProperties(returnIn(sampleRateHz, mask, format)); @@ -784,33 +913,14 @@ TEST_IO_STREAM(GetAudioProperties, "Check that the stream audio properties == the ones it was opened with", testGetAudioProperties(stream.get(), audioConfig)) -static void testConnectedState(IStream* stream) { - DeviceAddress address = {}; - using AD = AudioDevice; - for (auto device : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { - address.device = device; - - ASSERT_OK(stream->setConnectedState(address, true)); - ASSERT_OK(stream->setConnectedState(address, false)); - } -} -TEST_IO_STREAM(SetConnectedState, - "Check that the stream can be notified of device connection and " - "deconnection", - testConnectedState(stream.get())) - -static auto invalidArgsOrNotSupportedOrOK = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED, - Result::OK}; TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value", - ASSERT_RESULT(invalidArgsOrNotSupportedOrOK, stream->setHwAvSync(666))) - -TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync())); + ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, stream->setHwAvSync(666))) static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys, initializer_list<Result> expectedResults) { hidl_vec<ParameterValue> parameters; Result res; - ASSERT_OK(stream->getParameters(keys, returnIn(res, parameters))); + ASSERT_OK(Parameters::get(stream, keys, returnIn(res, parameters))); ASSERT_RESULT(expectedResults, res); if (res == Result::OK) { for (auto& parameter : parameters) { @@ -831,22 +941,22 @@ TEST_IO_STREAM(getNonExistingParameter, "Retrieve the values of an non existing {Result::NOT_SUPPORTED})) TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters", - ASSERT_RESULT(Result::OK, stream->setParameters({}))) + ASSERT_RESULT(Result::OK, Parameters::set(stream, {}))) TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter", // Unfortunately, the set_parameter legacy interface did not return any // error code when a key is not supported. // To allow implementation to just wrapped the legacy one, consider OK as a // valid result for setting a non existing parameter. - ASSERT_RESULT(invalidArgsOrNotSupportedOrOK, - stream->setParameters({{"non existing key", "0"}}))) + ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, + Parameters::set(stream, {{"non existing key", "0"}}))) TEST_IO_STREAM(DebugDump, "Check that a stream can dump its state without error", - testDebugDump([this](const auto& handle) { return stream->debugDump(handle); })) + testDebugDump([this](const auto& handle) { return dump(stream, handle); })) TEST_IO_STREAM(DebugDumpInvalidArguments, "Check that the stream dump doesn't crash on invalid arguments", - ASSERT_OK(stream->debugDump(hidl_handle()))) + ASSERT_OK(dump(stream, hidl_handle()))) ////////////////////////////////////////////////////////////////////////////// ////////////////////////////// addRemoveEffect /////////////////////////////// @@ -866,8 +976,6 @@ TEST_IO_STREAM(RemoveNonExistingEffect, "Removing a non existing effect should f TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby", ASSERT_OK(stream->standby())) // can not fail -static constexpr auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED}; - TEST_IO_STREAM(startNoMmap, "Starting a mmaped stream before mapping it should fail", ASSERT_RESULT(invalidStateOrNotSupported, stream->start())) @@ -881,7 +989,6 @@ TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream( TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", ASSERT_OK(closeStream()); ASSERT_RESULT(Result::INVALID_STATE, closeStream())) -static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED}; static void testCreateTooBigMmapBuffer(IStream* stream) { MmapBufferInfo info; Result res; @@ -988,15 +1095,19 @@ TEST_P(InputStreamTest, GetInputFramesLost) { TEST_P(InputStreamTest, getCapturePosition) { doc::test( "The capture position of a non prepared stream should not be " - "retrievable"); + "retrievable or 0"); uint64_t frames; uint64_t time; ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time))); - ASSERT_RESULT(invalidStateOrNotSupported, res); + ASSERT_RESULT(okOrInvalidStateOrNotSupported, res); + if (res == Result::OK) { + ASSERT_EQ(0U, frames); + ASSERT_LE(0U, time); + } } ////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// StreamIn /////////////////////////////////// +///////////////////////////////// StreamOut ////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// TEST_P(OutputStreamTest, getLatency) { @@ -1103,7 +1214,6 @@ static bool isAsyncModeSupported(IStreamOut* stream) { auto res = stream->setCallback(new MockOutCallbacks); stream->clearCallback(); // try to restore the no callback state, ignore // any error - auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED}; EXPECT_RESULT(okOrNotSupported, res); return res.isOk() ? res == Result::OK : false; } @@ -1152,7 +1262,7 @@ TEST_P(OutputStreamTest, Pause) { doc::partialTest("The output stream does not support pause"); return; } - ASSERT_RESULT(Result::INVALID_STATE, stream->resume()); + ASSERT_RESULT(Result::INVALID_STATE, stream->pause()); } static void testDrain(IStreamOut* stream, AudioDrain type) { @@ -1222,48 +1332,33 @@ TEST_F(AudioPrimaryHidlTest, setVoiceVolume) { testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); }); } -TEST_F(AudioPrimaryHidlTest, setMode) { - doc::test( - "Make sure setMode always succeeds if mode is valid " - "and fails otherwise"); - // Test Invalid values - for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) { - SCOPED_TRACE("mode=" + toString(mode)); - ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode)); - } - // Test valid values - for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE, - AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { - SCOPED_TRACE("mode=" + toString(mode)); - ASSERT_OK(device->setMode(mode)); - } -} - TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) { doc::test("Query and set the BT SCO NR&EC state"); - testOptionalAccessors("BtScoNrecEnabled", {true, false, true}, - &IPrimaryDevice::setBtScoNrecEnabled, - &IPrimaryDevice::getBtScoNrecEnabled); + testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true}, + &IPrimaryDevice::setBtScoNrecEnabled, + &IPrimaryDevice::getBtScoNrecEnabled); } TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { doc::test("Query and set the SCO whideband state"); - testOptionalAccessors("BtScoWideband", {true, false, true}, - &IPrimaryDevice::setBtScoWidebandEnabled, - &IPrimaryDevice::getBtScoWidebandEnabled); + testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true}, + &IPrimaryDevice::setBtScoWidebandEnabled, + &IPrimaryDevice::getBtScoWidebandEnabled); } -using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<TtyMode>; +using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<IPrimaryDevice::TtyMode>; TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { doc::test("Query and set the TTY mode state"); - testOptionalAccessors("TTY mode", {TtyMode::OFF, TtyMode::HCO, TtyMode::VCO, TtyMode::FULL}, - &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode); + testAccessors<OPTIONAL>( + "TTY mode", Initial{IPrimaryDevice::TtyMode::OFF}, + {IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL}, + &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode); } TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) { doc::test("Query and set the HAC state"); - testOptionalAccessors("HAC", {true, false, true}, &IPrimaryDevice::setHacEnabled, - &IPrimaryDevice::getHacEnabled); + testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled, + &IPrimaryDevice::getHacEnabled); } ////////////////////////////////////////////////////////////////////////////// diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp deleted file mode 100644 index cadc2f1b43..0000000000 --- a/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "AEC_Effect_HAL" - -#include "AcousticEchoCancelerEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/AcousticEchoCancelerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.h b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h deleted file mode 100644 index d36335c7b3..0000000000 --- a/audio/effect/2.0/default/AcousticEchoCancelerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H - -#include <android/hardware/audio/effect/2.0/IAcousticEchoCancelerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/AcousticEchoCancelerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H diff --git a/audio/effect/2.0/default/Android.bp b/audio/effect/2.0/default/Android.bp deleted file mode 100644 index db0098849c..0000000000 --- a/audio/effect/2.0/default/Android.bp +++ /dev/null @@ -1,50 +0,0 @@ -cc_library_shared { - name: "android.hardware.audio.effect@2.0-impl", - defaults: ["hidl_defaults"], - vendor: true, - relative_install_path: "hw", - srcs: [ - "AcousticEchoCancelerEffect.cpp", - "AudioBufferManager.cpp", - "AutomaticGainControlEffect.cpp", - "BassBoostEffect.cpp", - "Conversions.cpp", - "DownmixEffect.cpp", - "Effect.cpp", - "EffectsFactory.cpp", - "EnvironmentalReverbEffect.cpp", - "EqualizerEffect.cpp", - "LoudnessEnhancerEffect.cpp", - "NoiseSuppressionEffect.cpp", - "PresetReverbEffect.cpp", - "VirtualizerEffect.cpp", - "VisualizerEffect.cpp", - ], - - shared_libs: [ - "libbase", - "libcutils", - "libeffects", - "libfmq", - "libhidlbase", - "libhidlmemory", - "libhidltransport", - "liblog", - "libutils", - "android.hardware.audio.common-util", - "android.hardware.audio.common@2.0", - "android.hardware.audio.common@2.0-util", - "android.hardware.audio.effect@2.0", - "android.hidl.memory@1.0", - ], - - header_libs: [ - "android.hardware.audio.common.util@all-versions", - "android.hardware.audio.effect@all-versions-impl", - "libaudio_system_headers", - "libaudioclient_headers", - "libeffects_headers", - "libhardware_headers", - "libmedia_headers", - ], -} diff --git a/audio/effect/2.0/default/AudioBufferManager.cpp b/audio/effect/2.0/default/AudioBufferManager.cpp deleted file mode 100644 index 39918dd1c7..0000000000 --- a/audio/effect/2.0/default/AudioBufferManager.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 "AudioBufferManager.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/AudioBufferManager.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/AudioBufferManager.h b/audio/effect/2.0/default/AudioBufferManager.h deleted file mode 100644 index 789fbd1c8f..0000000000 --- a/audio/effect/2.0/default/AudioBufferManager.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUDIO_BUFFER_MANAGER_H_ -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUDIO_BUFFER_MANAGER_H_ - -#include <android/hardware/audio/effect/2.0/types.h> - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/AudioBufferManager.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUDIO_BUFFER_MANAGER_H_ diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.cpp b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp deleted file mode 100644 index 7e00a8065f..0000000000 --- a/audio/effect/2.0/default/AutomaticGainControlEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "AGC_Effect_HAL" - -#include "AutomaticGainControlEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/AutomaticGainControlEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.h b/audio/effect/2.0/default/AutomaticGainControlEffect.h deleted file mode 100644 index ef440d2e40..0000000000 --- a/audio/effect/2.0/default/AutomaticGainControlEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H - -#include <android/hardware/audio/effect/2.0/IAutomaticGainControlEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/AutomaticGainControlEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H diff --git a/audio/effect/2.0/default/BassBoostEffect.cpp b/audio/effect/2.0/default/BassBoostEffect.cpp deleted file mode 100644 index df9e892d60..0000000000 --- a/audio/effect/2.0/default/BassBoostEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "BassBoost_HAL" - -#include "BassBoostEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/BassBoostEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/BassBoostEffect.h b/audio/effect/2.0/default/BassBoostEffect.h deleted file mode 100644 index 83179e28ef..0000000000 --- a/audio/effect/2.0/default/BassBoostEffect.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H - -#include <android/hardware/audio/effect/2.0/IBassBoostEffect.h> - -#include <hidl/MQDescriptor.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/BassBoostEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H diff --git a/audio/effect/2.0/default/Conversions.cpp b/audio/effect/2.0/default/Conversions.cpp deleted file mode 100644 index b59752c982..0000000000 --- a/audio/effect/2.0/default/Conversions.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 "Conversions.h" -#include "HidlUtils.h" - -using ::android::hardware::audio::common::V2_0::HidlUtils; - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/Conversions.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/Conversions.h b/audio/effect/2.0/default/Conversions.h deleted file mode 100644 index 94c7f66ea6..0000000000 --- a/audio/effect/2.0/default/Conversions.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_CONVERSIONS_H_ -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_CONVERSIONS_H_ - -#include <android/hardware/audio/effect/2.0/types.h> - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/Conversions.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_CONVERSIONS_H_ diff --git a/audio/effect/2.0/default/DownmixEffect.cpp b/audio/effect/2.0/default/DownmixEffect.cpp deleted file mode 100644 index 1a51e13641..0000000000 --- a/audio/effect/2.0/default/DownmixEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "Downmix_HAL" - -#include "DownmixEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/DownmixEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/DownmixEffect.h b/audio/effect/2.0/default/DownmixEffect.h deleted file mode 100644 index 6dbbb32836..0000000000 --- a/audio/effect/2.0/default/DownmixEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H - -#include <android/hardware/audio/effect/2.0/IDownmixEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/DownmixEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H diff --git a/audio/effect/2.0/default/Effect.cpp b/audio/effect/2.0/default/Effect.cpp deleted file mode 100644 index e234e520b8..0000000000 --- a/audio/effect/2.0/default/Effect.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 <memory.h> - -#define LOG_TAG "EffectHAL" -#define ATRACE_TAG ATRACE_TAG_AUDIO - -#include "Conversions.h" -#include "Effect.h" -#include "common/all-versions/default/EffectMap.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/Effect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/Effect.h b/audio/effect/2.0/default/Effect.h deleted file mode 100644 index a4d194dab9..0000000000 --- a/audio/effect/2.0/default/Effect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H - -#include <android/hardware/audio/effect/2.0/IEffect.h> - -#include "AudioBufferManager.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/Effect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H diff --git a/audio/effect/2.0/default/EffectsFactory.cpp b/audio/effect/2.0/default/EffectsFactory.cpp deleted file mode 100644 index a48a85f7c2..0000000000 --- a/audio/effect/2.0/default/EffectsFactory.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "EffectFactoryHAL" -#include "EffectsFactory.h" -#include "AcousticEchoCancelerEffect.h" -#include "AutomaticGainControlEffect.h" -#include "BassBoostEffect.h" -#include "Conversions.h" -#include "DownmixEffect.h" -#include "Effect.h" -#include "EnvironmentalReverbEffect.h" -#include "EqualizerEffect.h" -#include "HidlUtils.h" -#include "LoudnessEnhancerEffect.h" -#include "NoiseSuppressionEffect.h" -#include "PresetReverbEffect.h" -#include "VirtualizerEffect.h" -#include "VisualizerEffect.h" -#include "common/all-versions/default/EffectMap.h" - -using ::android::hardware::audio::common::V2_0::HidlUtils; - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/EffectsFactory.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/EffectsFactory.h b/audio/effect/2.0/default/EffectsFactory.h deleted file mode 100644 index f1bfbcff4c..0000000000 --- a/audio/effect/2.0/default/EffectsFactory.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H - -#include <system/audio_effect.h> - -#include <android/hardware/audio/effect/2.0/IEffectsFactory.h> - -#include <hidl/MQDescriptor.h> -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/EffectsFactory.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp deleted file mode 100644 index 017dd1f4cb..0000000000 --- a/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "EnvReverb_HAL" -#include <android/log.h> - -#include "EnvironmentalReverbEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/EnvironmentalReverbEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.h b/audio/effect/2.0/default/EnvironmentalReverbEffect.h deleted file mode 100644 index d93a53f42f..0000000000 --- a/audio/effect/2.0/default/EnvironmentalReverbEffect.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H - -#include <system/audio_effects/effect_environmentalreverb.h> - -#include <android/hardware/audio/effect/2.0/IEnvironmentalReverbEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/EnvironmentalReverbEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H diff --git a/audio/effect/2.0/default/EqualizerEffect.cpp b/audio/effect/2.0/default/EqualizerEffect.cpp deleted file mode 100644 index d6e056c421..0000000000 --- a/audio/effect/2.0/default/EqualizerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "Equalizer_HAL" - -#include "EqualizerEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/EqualizerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/EqualizerEffect.h b/audio/effect/2.0/default/EqualizerEffect.h deleted file mode 100644 index 54cdd50e13..0000000000 --- a/audio/effect/2.0/default/EqualizerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H - -#include <android/hardware/audio/effect/2.0/IEqualizerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/EqualizerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp deleted file mode 100644 index 2dca0f4c39..0000000000 --- a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "LoudnessEnhancer_HAL" - -#include "LoudnessEnhancerEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/LoudnessEnhancerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.h b/audio/effect/2.0/default/LoudnessEnhancerEffect.h deleted file mode 100644 index 992e238ef1..0000000000 --- a/audio/effect/2.0/default/LoudnessEnhancerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H - -#include <android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/LoudnessEnhancerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.cpp b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp deleted file mode 100644 index 089e811e09..0000000000 --- a/audio/effect/2.0/default/NoiseSuppressionEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "NS_Effect_HAL" - -#include "NoiseSuppressionEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/NoiseSuppressionEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.h b/audio/effect/2.0/default/NoiseSuppressionEffect.h deleted file mode 100644 index 0eee4b51b2..0000000000 --- a/audio/effect/2.0/default/NoiseSuppressionEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H - -#include <android/hardware/audio/effect/2.0/INoiseSuppressionEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/NoiseSuppressionEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H diff --git a/audio/effect/2.0/default/OWNERS b/audio/effect/2.0/default/OWNERS deleted file mode 100644 index 6fdc97ca29..0000000000 --- a/audio/effect/2.0/default/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -elaurent@google.com -krocard@google.com -mnaganov@google.com diff --git a/audio/effect/2.0/default/PresetReverbEffect.cpp b/audio/effect/2.0/default/PresetReverbEffect.cpp deleted file mode 100644 index 0648f6a8eb..0000000000 --- a/audio/effect/2.0/default/PresetReverbEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "PresetReverb_HAL" - -#include "PresetReverbEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/PresetReverbEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/PresetReverbEffect.h b/audio/effect/2.0/default/PresetReverbEffect.h deleted file mode 100644 index 1ea1626ffa..0000000000 --- a/audio/effect/2.0/default/PresetReverbEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H - -#include <android/hardware/audio/effect/2.0/IPresetReverbEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/PresetReverbEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H diff --git a/audio/effect/2.0/default/VirtualizerEffect.cpp b/audio/effect/2.0/default/VirtualizerEffect.cpp deleted file mode 100644 index 63d3eb925f..0000000000 --- a/audio/effect/2.0/default/VirtualizerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "Virtualizer_HAL" - -#include "VirtualizerEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/VirtualizerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/VirtualizerEffect.h b/audio/effect/2.0/default/VirtualizerEffect.h deleted file mode 100644 index 04f93c4c72..0000000000 --- a/audio/effect/2.0/default/VirtualizerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H - -#include <android/hardware/audio/effect/2.0/IVirtualizerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/VirtualizerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H diff --git a/audio/effect/2.0/default/VisualizerEffect.cpp b/audio/effect/2.0/default/VisualizerEffect.cpp deleted file mode 100644 index 523552466d..0000000000 --- a/audio/effect/2.0/default/VisualizerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "Visualizer_HAL" - -#include "VisualizerEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/VisualizerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/2.0/default/VisualizerEffect.h b/audio/effect/2.0/default/VisualizerEffect.h deleted file mode 100644 index 940f15de9b..0000000000 --- a/audio/effect/2.0/default/VisualizerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H - -#include <android/hardware/audio/effect/2.0/IVisualizerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <effect/all-versions/default/VisualizerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H diff --git a/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp b/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp deleted file mode 100644 index c90c4fab2e..0000000000 --- a/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp +++ /dev/null @@ -1,849 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "AudioEffectHidlHalTest" -#include <android-base/logging.h> -#include <system/audio.h> - -#include <android/hardware/audio/effect/2.0/IEffect.h> -#include <android/hardware/audio/effect/2.0/IEffectsFactory.h> -#include <android/hardware/audio/effect/2.0/IEqualizerEffect.h> -#include <android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h> -#include <android/hardware/audio/effect/2.0/types.h> -#include <android/hidl/allocator/1.0/IAllocator.h> -#include <android/hidl/memory/1.0/IMemory.h> - -#include <VtsHalHidlTargetTestBase.h> -#include <VtsHalHidlTargetTestEnvBase.h> - -using android::hardware::audio::common::V2_0::AudioDevice; -using android::hardware::audio::common::V2_0::AudioHandleConsts; -using android::hardware::audio::common::V2_0::AudioMode; -using android::hardware::audio::common::V2_0::AudioSource; -using android::hardware::audio::common::V2_0::Uuid; -using android::hardware::audio::effect::V2_0::AudioBuffer; -using android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; -using android::hardware::audio::effect::V2_0::EffectBufferConfig; -using android::hardware::audio::effect::V2_0::EffectConfig; -using android::hardware::audio::effect::V2_0::EffectDescriptor; -using android::hardware::audio::effect::V2_0::EffectOffloadParameter; -using android::hardware::audio::effect::V2_0::IEffect; -using android::hardware::audio::effect::V2_0::IEffectsFactory; -using android::hardware::audio::effect::V2_0::IEqualizerEffect; -using android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect; -using android::hardware::audio::effect::V2_0::Result; -using android::hardware::MQDescriptorSync; -using android::hardware::Return; -using android::hardware::Void; -using android::hardware::hidl_handle; -using android::hardware::hidl_memory; -using android::hardware::hidl_string; -using android::hardware::hidl_vec; -using android::hidl::allocator::V1_0::IAllocator; -using android::hidl::memory::V1_0::IMemory; -using android::sp; - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) -#endif - -// Test environment for Audio Effects Factory HIDL HAL. -class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static AudioEffectsFactoryHidlEnvironment* Instance() { - static AudioEffectsFactoryHidlEnvironment* instance = - new AudioEffectsFactoryHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService<IEffectsFactory>(); } -}; - -// The main test class for Audio Effects Factory HIDL HAL. -class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - void SetUp() override { - effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>( - AudioEffectsFactoryHidlEnvironment::Instance()->getServiceName<IEffectsFactory>()); - ASSERT_NE(effectsFactory, nullptr); - } - - void TearDown() override { effectsFactory.clear(); } - - protected: - static void description(const std::string& description) { - RecordProperty("description", description); - } - - sp<IEffectsFactory> effectsFactory; -}; - -TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { - description("Verify that EnumerateEffects returns at least one effect"); - Result retval = Result::NOT_INITIALIZED; - size_t effectCount = 0; - Return<void> ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec<EffectDescriptor>& result) { - retval = r; - effectCount = result.size(); - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_GT(effectCount, 0u); -} - -TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) { - description("Verify that an effect can be created via CreateEffect"); - bool gotEffect = false; - Uuid effectUuid; - Return<void> ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec<EffectDescriptor>& result) { - if (r == Result::OK && result.size() > 0) { - gotEffect = true; - effectUuid = result[0].uuid; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(gotEffect); - Result retval = Result::NOT_INITIALIZED; - sp<IEffect> effect; - ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) { - retval = r; - if (r == Result::OK) { - effect = result; - } - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_NE(nullptr, effect.get()); -} - -TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) { - description( - "Verify that effects factory can provide an effect descriptor via " - "GetDescriptor"); - hidl_vec<EffectDescriptor> allDescriptors; - Return<void> ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec<EffectDescriptor>& result) { - if (r == Result::OK) { - allDescriptors = result; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_GT(allDescriptors.size(), 0u); - for (size_t i = 0; i < allDescriptors.size(); ++i) { - ret = effectsFactory->getDescriptor( - allDescriptors[i].uuid, [&](Result r, const EffectDescriptor& result) { - EXPECT_EQ(r, Result::OK); - EXPECT_EQ(result, allDescriptors[i]); - }); - } - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) { - description("Verify that debugDump doesn't crash on invalid arguments"); - Return<void> ret = effectsFactory->debugDump(hidl_handle()); - ASSERT_TRUE(ret.isOk()); -} - -// Equalizer effect is required by CDD, but only the type is fixed. -// This is the same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java. -static const Uuid EQUALIZER_EFFECT_TYPE = { - 0x0bed4300, 0xddd6, 0x11db, 0x8f34, - std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}}; -// Loudness Enhancer effect is required by CDD, but only the type is fixed. -// This is the same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java. -static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = { - 0xfe3199be, 0xaed0, 0x413f, 0x87bb, - std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}}; - -// The main test class for Audio Effect HIDL HAL. -class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - void SetUp() override { - effectsFactory = - ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>(); - ASSERT_NE(nullptr, effectsFactory.get()); - - findAndCreateEffect(getEffectType()); - ASSERT_NE(nullptr, effect.get()); - - Return<Result> ret = effect->init(); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, ret); - } - - void TearDown() override { - effect.clear(); - effectsFactory.clear(); - } - - protected: - static void description(const std::string& description) { - RecordProperty("description", description); - } - - virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; } - - void findAndCreateEffect(const Uuid& type); - void findEffectInstance(const Uuid& type, Uuid* uuid); - void getChannelCount(uint32_t* channelCount); - - sp<IEffectsFactory> effectsFactory; - sp<IEffect> effect; -}; - -void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) { - Uuid effectUuid; - findEffectInstance(type, &effectUuid); - Return<void> ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) { - if (r == Result::OK) { - effect = result; - } - }); - ASSERT_TRUE(ret.isOk()); -} - -void AudioEffectHidlTest::findEffectInstance(const Uuid& type, Uuid* uuid) { - bool effectFound = false; - Return<void> ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec<EffectDescriptor>& result) { - if (r == Result::OK) { - for (const auto& desc : result) { - if (desc.type == type) { - effectFound = true; - *uuid = desc.uuid; - break; - } - } - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(effectFound); -} - -void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) { - Result retval; - EffectConfig currentConfig; - Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { - retval = r; - if (r == Result::OK) { - currentConfig = conf; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); - ASSERT_TRUE(audio_channel_mask_is_valid( - static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels))); - *channelCount = audio_channel_count_from_out_mask( - static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)); -} - -TEST_F(AudioEffectHidlTest, Close) { - description("Verify that an effect can be closed"); - Return<Result> ret = effect->close(); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, GetDescriptor) { - description( - "Verify that an effect can return its own descriptor via GetDescriptor"); - Result retval = Result::NOT_INITIALIZED; - Uuid actualType; - Return<void> ret = - effect->getDescriptor([&](Result r, const EffectDescriptor& desc) { - retval = r; - if (r == Result::OK) { - actualType = desc.type; - } - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(getEffectType(), actualType); -} - -TEST_F(AudioEffectHidlTest, GetSetConfig) { - description( - "Verify that it is possible to manipulate effect config via Get / " - "SetConfig"); - Result retval = Result::NOT_INITIALIZED; - EffectConfig currentConfig; - Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { - retval = r; - if (r == Result::OK) { - currentConfig = conf; - } - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - Return<Result> ret2 = effect->setConfig(currentConfig, nullptr, nullptr); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, ret2); -} - -TEST_F(AudioEffectHidlTest, GetConfigReverse) { - description("Verify that GetConfigReverse does not crash"); - Return<void> ret = - effect->getConfigReverse([&](Result, const EffectConfig&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { - description("Verify that GetSupportedAuxChannelsConfigs does not crash"); - Return<void> ret = effect->getSupportedAuxChannelsConfigs( - 0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) { - description("Verify that GetAuxChannelsConfig does not crash"); - Return<void> ret = effect->getAuxChannelsConfig( - [&](Result, const EffectAuxChannelsConfig&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) { - description("Verify that SetAuxChannelsConfig does not crash"); - Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig()); - EXPECT_TRUE(ret.isOk()); -} - -// Not generated automatically because AudioBuffer contains -// instances of hidl_memory which can't be compared properly -// in general case due to presence of handles. -// -// However, in this particular case, handles must not present -// thus comparison is possible. -// -// operator== must be defined in the same namespace as the structures. -namespace android { -namespace hardware { -namespace audio { -namespace effect { -namespace V2_0 { -inline bool operator==(const AudioBuffer& lhs, const AudioBuffer& rhs) { - return lhs.id == rhs.id && lhs.frameCount == rhs.frameCount && - lhs.data.handle() == nullptr && rhs.data.handle() == nullptr; -} - -inline bool operator==(const EffectBufferConfig& lhs, - const EffectBufferConfig& rhs) { - return lhs.buffer == rhs.buffer && lhs.samplingRateHz == rhs.samplingRateHz && - lhs.channels == rhs.channels && lhs.format == rhs.format && - lhs.accessMode == rhs.accessMode && lhs.mask == rhs.mask; -} - -inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) { - return lhs.inputCfg == rhs.inputCfg && lhs.outputCfg == rhs.outputCfg; -} -} // namespace V2_0 -} // namespace effect -} // namespace audio -} // namespace hardware -} // namespace android - -TEST_F(AudioEffectHidlTest, Reset) { - description("Verify that Reset preserves effect configuration"); - Result retval = Result::NOT_INITIALIZED; - EffectConfig originalConfig; - Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { - retval = r; - if (r == Result::OK) { - originalConfig = conf; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); - Return<Result> ret2 = effect->reset(); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, ret2); - EffectConfig configAfterReset; - ret = effect->getConfig([&](Result r, const EffectConfig& conf) { - retval = r; - if (r == Result::OK) { - configAfterReset = conf; - } - }); - EXPECT_EQ(originalConfig, configAfterReset); -} - -TEST_F(AudioEffectHidlTest, DisableEnableDisable) { - description("Verify Disable -> Enable -> Disable sequence for an effect"); - Return<Result> ret = effect->disable(); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::INVALID_ARGUMENTS, ret); - ret = effect->enable(); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - ret = effect->disable(); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, SetDevice) { - description("Verify that SetDevice works for an output chain effect"); - Return<Result> ret = effect->setDevice(AudioDevice::OUT_SPEAKER); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, SetAndGetVolume) { - description("Verify that SetAndGetVolume method works for an effect"); - uint32_t channelCount; - getChannelCount(&channelCount); - hidl_vec<uint32_t> volumes; - volumes.resize(channelCount); - for (uint32_t i = 0; i < channelCount; ++i) { - volumes[i] = 0; - } - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = effect->setAndGetVolume( - volumes, [&](Result r, const hidl_vec<uint32_t>&) { retval = r; }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); -} - -TEST_F(AudioEffectHidlTest, VolumeChangeNotification) { - description("Verify that effect accepts VolumeChangeNotification"); - uint32_t channelCount; - getChannelCount(&channelCount); - hidl_vec<uint32_t> volumes; - volumes.resize(channelCount); - for (uint32_t i = 0; i < channelCount; ++i) { - volumes[i] = 0; - } - Return<Result> ret = effect->volumeChangeNotification(volumes); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, SetAudioMode) { - description("Verify that SetAudioMode works for an effect"); - Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, SetConfigReverse) { - description("Verify that SetConfigReverse does not crash"); - Return<Result> ret = - effect->setConfigReverse(EffectConfig(), nullptr, nullptr); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetInputDevice) { - description("Verify that SetInputDevice does not crash"); - Return<Result> ret = effect->setInputDevice(AudioDevice::IN_BUILTIN_MIC); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetAudioSource) { - description("Verify that SetAudioSource does not crash"); - Return<Result> ret = effect->setAudioSource(AudioSource::MIC); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, Offload) { - description("Verify that calling Offload method does not crash"); - EffectOffloadParameter offloadParam; - offloadParam.isOffload = false; - offloadParam.ioHandle = - static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE); - Return<Result> ret = effect->offload(offloadParam); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, PrepareForProcessing) { - description("Verify that PrepareForProcessing method works for an effect"); - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = effect->prepareForProcessing( - [&](Result r, const MQDescriptorSync<Result>&) { retval = r; }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); -} - -TEST_F(AudioEffectHidlTest, SetProcessBuffers) { - description("Verify that SetProcessBuffers works for an effect"); - sp<IAllocator> ashmem = IAllocator::getService("ashmem"); - ASSERT_NE(nullptr, ashmem.get()); - bool success = false; - AudioBuffer buffer; - Return<void> ret = - ashmem->allocate(1024, [&](bool s, const hidl_memory& memory) { - success = s; - if (s) { - buffer.data = memory; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(success); - Return<Result> ret2 = effect->setProcessBuffers(buffer, buffer); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, ret2); -} - -TEST_F(AudioEffectHidlTest, Command) { - description("Verify that Command does not crash"); - Return<void> ret = effect->command(0, hidl_vec<uint8_t>(), 0, - [&](int32_t, const hidl_vec<uint8_t>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetParameter) { - description("Verify that SetParameter does not crash"); - Return<Result> ret = - effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>()); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetParameter) { - description("Verify that GetParameter does not crash"); - Return<void> ret = effect->getParameter( - hidl_vec<uint8_t>(), 0, [&](Result, const hidl_vec<uint8_t>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) { - description("Verify that GetSupportedConfigsForFeature does not crash"); - Return<void> ret = effect->getSupportedConfigsForFeature( - 0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) { - description("Verify that GetCurrentConfigForFeature does not crash"); - Return<void> ret = effect->getCurrentConfigForFeature( - 0, 0, [&](Result, const hidl_vec<uint8_t>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) { - description("Verify that SetCurrentConfigForFeature does not crash"); - Return<Result> ret = - effect->setCurrentConfigForFeature(0, hidl_vec<uint8_t>()); - EXPECT_TRUE(ret.isOk()); -} - - -// The main test class for Equalizer Audio Effect HIDL HAL. -class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest { - public: - void SetUp() override { - AudioEffectHidlTest::SetUp(); - equalizer = IEqualizerEffect::castFrom(effect); - ASSERT_NE(nullptr, equalizer.get()); - } - - protected: - Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; } - void getNumBands(uint16_t* numBands); - void getLevelRange(int16_t* minLevel, int16_t* maxLevel); - void getBandFrequencyRange(uint16_t band, uint32_t* minFreq, - uint32_t* centerFreq, uint32_t* maxFreq); - void getPresetCount(size_t* count); - - sp<IEqualizerEffect> equalizer; -}; - -void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) { - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = equalizer->getNumBands([&](Result r, uint16_t b) { - retval = r; - if (retval == Result::OK) { - *numBands = b; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); -} - -void EqualizerAudioEffectHidlTest::getLevelRange(int16_t* minLevel, - int16_t* maxLevel) { - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = - equalizer->getLevelRange([&](Result r, int16_t min, int16_t max) { - retval = r; - if (retval == Result::OK) { - *minLevel = min; - *maxLevel = max; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); -} - -void EqualizerAudioEffectHidlTest::getBandFrequencyRange(uint16_t band, - uint32_t* minFreq, - uint32_t* centerFreq, - uint32_t* maxFreq) { - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = equalizer->getBandFrequencyRange( - band, [&](Result r, uint32_t min, uint32_t max) { - retval = r; - if (retval == Result::OK) { - *minFreq = min; - *maxFreq = max; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); - ret = equalizer->getBandCenterFrequency(band, [&](Result r, uint32_t center) { - retval = r; - if (retval == Result::OK) { - *centerFreq = center; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); -} - -void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) { - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = equalizer->getPresetNames( - [&](Result r, const hidl_vec<hidl_string>& names) { - retval = r; - if (retval == Result::OK) { - *count = names.size(); - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); -} - -TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) { - description("Verify that Equalizer effect reports at least one band"); - uint16_t numBands = 0; - getNumBands(&numBands); - EXPECT_GT(numBands, 0); -} - -TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) { - description("Verify that Equalizer effect reports adequate band level range"); - int16_t minLevel = 0x7fff, maxLevel = 0; - getLevelRange(&minLevel, &maxLevel); - EXPECT_GT(maxLevel, minLevel); -} - -TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) { - description( - "Verify that manipulating band levels works for Equalizer effect"); - uint16_t numBands = 0; - getNumBands(&numBands); - ASSERT_GT(numBands, 0); - int16_t levels[3]{0x7fff, 0, 0}; - getLevelRange(&levels[0], &levels[2]); - ASSERT_GT(levels[2], levels[0]); - levels[1] = (levels[2] + levels[0]) / 2; - for (uint16_t i = 0; i < numBands; ++i) { - for (size_t j = 0; j < ARRAY_SIZE(levels); ++j) { - Return<Result> ret = equalizer->setBandLevel(i, levels[j]); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Result retval = Result::NOT_INITIALIZED; - int16_t actualLevel; - Return<void> ret2 = equalizer->getBandLevel(i, [&](Result r, int16_t l) { - retval = r; - if (retval == Result::OK) { - actualLevel = l; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(levels[j], actualLevel); - } - } -} - -TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { - description( - "Verify that Equalizer effect reports adequate band frequency range"); - uint16_t numBands = 0; - getNumBands(&numBands); - ASSERT_GT(numBands, 0); - for (uint16_t i = 0; i < numBands; ++i) { - uint32_t minFreq = 0xffffffff, centerFreq = 0xffffffff, - maxFreq = 0xffffffff; - getBandFrequencyRange(i, &minFreq, ¢erFreq, &maxFreq); - // Note: NXP legacy implementation reports "1" as upper bound for last band, - // so this check fails. - EXPECT_GE(maxFreq, centerFreq); - EXPECT_GE(centerFreq, minFreq); - } -} - -TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) { - description( - "Verify that Equalizer effect supports GetBandForFrequency correctly"); - uint16_t numBands = 0; - getNumBands(&numBands); - ASSERT_GT(numBands, 0); - for (uint16_t i = 0; i < numBands; ++i) { - uint32_t freqs[3]{0, 0, 0}; - getBandFrequencyRange(i, &freqs[0], &freqs[1], &freqs[2]); - // NXP legacy implementation reports "1" as upper bound for last band, some - // of the checks fail. - for (size_t j = 0; j < ARRAY_SIZE(freqs); ++j) { - if (j == 0) { - freqs[j]++; - } // Min frequency is an open interval. - Result retval = Result::NOT_INITIALIZED; - uint16_t actualBand = numBands + 1; - Return<void> ret = - equalizer->getBandForFrequency(freqs[j], [&](Result r, uint16_t b) { - retval = r; - if (retval == Result::OK) { - actualBand = b; - } - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j]; - } - } -} - -TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) { - description("Verify that Equalizer effect reports at least one preset"); - size_t presetCount; - getPresetCount(&presetCount); - EXPECT_GT(presetCount, 0u); -} - -TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { - description( - "Verify that manipulating the current preset for Equalizer effect"); - size_t presetCount; - getPresetCount(&presetCount); - ASSERT_GT(presetCount, 0u); - for (uint16_t i = 0; i < presetCount; ++i) { - Return<Result> ret = equalizer->setCurrentPreset(i); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Result retval = Result::NOT_INITIALIZED; - uint16_t actualPreset = 0xffff; - Return<void> ret2 = equalizer->getCurrentPreset([&](Result r, uint16_t p) { - retval = r; - if (retval == Result::OK) { - actualPreset = p; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(i, actualPreset); - } -} - -TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) { - description( - "Verify that setting band levels and presets works via Get / " - "SetAllProperties for Equalizer effect"); - using AllProperties = - android::hardware::audio::effect::V2_0::IEqualizerEffect::AllProperties; - uint16_t numBands = 0; - getNumBands(&numBands); - ASSERT_GT(numBands, 0); - AllProperties props; - props.bandLevels.resize(numBands); - for (size_t i = 0; i < numBands; ++i) { - props.bandLevels[i] = 0; - } - - AllProperties actualProps; - Result retval = Result::NOT_INITIALIZED; - - // Verify setting of the band levels via properties. - props.curPreset = -1; - Return<Result> ret = equalizer->setAllProperties(props); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Return<void> ret2 = - equalizer->getAllProperties([&](Result r, AllProperties p) { - retval = r; - if (retval == Result::OK) { - actualProps = p; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(props.bandLevels, actualProps.bandLevels); - - // Verify setting of the current preset via properties. - props.curPreset = 0; // Assuming there is at least one preset. - ret = equalizer->setAllProperties(props); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) { - retval = r; - if (retval == Result::OK) { - actualProps = p; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(props.curPreset, actualProps.curPreset); -} - -// The main test class for Equalizer Audio Effect HIDL HAL. -class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest { - public: - void SetUp() override { - AudioEffectHidlTest::SetUp(); - enhancer = ILoudnessEnhancerEffect::castFrom(effect); - ASSERT_NE(nullptr, enhancer.get()); - } - - protected: - Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; } - - sp<ILoudnessEnhancerEffect> enhancer; -}; - -TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { - description( - "Verify that manipulating the target gain works for Loudness Enhancer " - "effect"); - const int32_t gain = 100; - Return<Result> ret = enhancer->setTargetGain(gain); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - int32_t actualGain = 0; - Result retval; - Return<void> ret2 = enhancer->getTargetGain([&](Result r, int32_t g) { - retval = r; - if (retval == Result::OK) { - actualGain = g; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(gain, actualGain); -} - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - AudioEffectsFactoryHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} diff --git a/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd b/audio/effect/2.0/xml/audio_effects_conf.xsd index df281b32d1..b97b847a39 100644 --- a/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd +++ b/audio/effect/2.0/xml/audio_effects_conf.xsd @@ -39,6 +39,7 @@ <xs:enumeration value="voice_recognition"/> <xs:enumeration value="voice_communication"/> <xs:enumeration value="unprocessed"/> + <xs:enumeration value="voice_performance"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="streamOutputType"> diff --git a/audio/effect/4.0/default/Android.bp b/audio/effect/4.0/default/Android.bp deleted file mode 100644 index dcb2269a9b..0000000000 --- a/audio/effect/4.0/default/Android.bp +++ /dev/null @@ -1,50 +0,0 @@ -cc_library_shared { - name: "android.hardware.audio.effect@4.0-impl", - defaults: ["hidl_defaults"], - vendor: true, - relative_install_path: "hw", - srcs: [ - "AcousticEchoCancelerEffect.cpp", - "AudioBufferManager.cpp", - "AutomaticGainControlEffect.cpp", - "BassBoostEffect.cpp", - "Conversions.cpp", - "DownmixEffect.cpp", - "Effect.cpp", - "EffectsFactory.cpp", - "EnvironmentalReverbEffect.cpp", - "EqualizerEffect.cpp", - "LoudnessEnhancerEffect.cpp", - "NoiseSuppressionEffect.cpp", - "PresetReverbEffect.cpp", - "VirtualizerEffect.cpp", - "VisualizerEffect.cpp", - ], - - shared_libs: [ - "libbase", - "libcutils", - "libeffects", - "libfmq", - "libhidlbase", - "libhidlmemory", - "libhidltransport", - "liblog", - "libutils", - "android.hardware.audio.common-util", - "android.hardware.audio.common@4.0", - "android.hardware.audio.common@4.0-util", - "android.hardware.audio.effect@4.0", - "android.hidl.memory@1.0", - ], - - header_libs: [ - "android.hardware.audio.common.util@all-versions", - "android.hardware.audio.effect@all-versions-impl", - "libaudio_system_headers", - "libaudioclient_headers", - "libeffects_headers", - "libhardware_headers", - "libmedia_headers", - ], -} diff --git a/audio/effect/4.0/default/AudioBufferManager.cpp b/audio/effect/4.0/default/AudioBufferManager.cpp deleted file mode 100644 index 2d75f3fdbb..0000000000 --- a/audio/effect/4.0/default/AudioBufferManager.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 "AudioBufferManager.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/AudioBufferManager.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/AudioBufferManager.h b/audio/effect/4.0/default/AudioBufferManager.h deleted file mode 100644 index 1f151e6b99..0000000000 --- a/audio/effect/4.0/default/AudioBufferManager.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_AUDIO_BUFFER_MANAGER_H_ -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_AUDIO_BUFFER_MANAGER_H_ - -#include <android/hardware/audio/effect/4.0/types.h> - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/AudioBufferManager.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_AUDIO_BUFFER_MANAGER_H_ diff --git a/audio/effect/4.0/default/AutomaticGainControlEffect.cpp b/audio/effect/4.0/default/AutomaticGainControlEffect.cpp deleted file mode 100644 index 9d21c8ae6b..0000000000 --- a/audio/effect/4.0/default/AutomaticGainControlEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "AGC_Effect_HAL" - -#include "AutomaticGainControlEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/AutomaticGainControlEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/AutomaticGainControlEffect.h b/audio/effect/4.0/default/AutomaticGainControlEffect.h deleted file mode 100644 index 7f12007f8f..0000000000 --- a/audio/effect/4.0/default/AutomaticGainControlEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_AUTOMATICGAINCONTROLEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_AUTOMATICGAINCONTROLEFFECT_H - -#include <android/hardware/audio/effect/4.0/IAutomaticGainControlEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/AutomaticGainControlEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_AUTOMATICGAINCONTROLEFFECT_H diff --git a/audio/effect/4.0/default/BassBoostEffect.cpp b/audio/effect/4.0/default/BassBoostEffect.cpp deleted file mode 100644 index 74a626b79e..0000000000 --- a/audio/effect/4.0/default/BassBoostEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "BassBoost_HAL" - -#include "BassBoostEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/BassBoostEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/BassBoostEffect.h b/audio/effect/4.0/default/BassBoostEffect.h deleted file mode 100644 index 206a75fab4..0000000000 --- a/audio/effect/4.0/default/BassBoostEffect.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_BASSBOOSTEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_BASSBOOSTEFFECT_H - -#include <android/hardware/audio/effect/4.0/IBassBoostEffect.h> - -#include <hidl/MQDescriptor.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/BassBoostEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_BASSBOOSTEFFECT_H diff --git a/audio/effect/4.0/default/Conversions.cpp b/audio/effect/4.0/default/Conversions.cpp deleted file mode 100644 index 91285ae6b8..0000000000 --- a/audio/effect/4.0/default/Conversions.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 "Conversions.h" -#include "HidlUtils.h" - -using ::android::hardware::audio::common::V4_0::HidlUtils; - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/Conversions.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/Conversions.h b/audio/effect/4.0/default/Conversions.h deleted file mode 100644 index 50e380fe2e..0000000000 --- a/audio/effect/4.0/default/Conversions.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_CONVERSIONS_H_ -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_CONVERSIONS_H_ - -#include <android/hardware/audio/effect/4.0/types.h> - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/Conversions.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_CONVERSIONS_H_ diff --git a/audio/effect/4.0/default/DownmixEffect.cpp b/audio/effect/4.0/default/DownmixEffect.cpp deleted file mode 100644 index 07fcab2f1c..0000000000 --- a/audio/effect/4.0/default/DownmixEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "Downmix_HAL" - -#include "DownmixEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/DownmixEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/DownmixEffect.h b/audio/effect/4.0/default/DownmixEffect.h deleted file mode 100644 index 5ae820b76f..0000000000 --- a/audio/effect/4.0/default/DownmixEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_DOWNMIXEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_DOWNMIXEFFECT_H - -#include <android/hardware/audio/effect/4.0/IDownmixEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/DownmixEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_DOWNMIXEFFECT_H diff --git a/audio/effect/4.0/default/Effect.cpp b/audio/effect/4.0/default/Effect.cpp deleted file mode 100644 index 707044bff0..0000000000 --- a/audio/effect/4.0/default/Effect.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 <memory.h> - -#define LOG_TAG "EffectHAL" -#define ATRACE_TAG ATRACE_TAG_AUDIO - -#include "Conversions.h" -#include "Effect.h" -#include "common/all-versions/default/EffectMap.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/Effect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/Effect.h b/audio/effect/4.0/default/Effect.h deleted file mode 100644 index 9ca79c4596..0000000000 --- a/audio/effect/4.0/default/Effect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EFFECT_H - -#include <android/hardware/audio/effect/4.0/IEffect.h> - -#include "AudioBufferManager.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/Effect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EFFECT_H diff --git a/audio/effect/4.0/default/EffectsFactory.cpp b/audio/effect/4.0/default/EffectsFactory.cpp deleted file mode 100644 index ee0413df8f..0000000000 --- a/audio/effect/4.0/default/EffectsFactory.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "EffectFactoryHAL" -#include "EffectsFactory.h" -#include "AcousticEchoCancelerEffect.h" -#include "AutomaticGainControlEffect.h" -#include "BassBoostEffect.h" -#include "Conversions.h" -#include "DownmixEffect.h" -#include "Effect.h" -#include "EnvironmentalReverbEffect.h" -#include "EqualizerEffect.h" -#include "HidlUtils.h" -#include "LoudnessEnhancerEffect.h" -#include "NoiseSuppressionEffect.h" -#include "PresetReverbEffect.h" -#include "VirtualizerEffect.h" -#include "VisualizerEffect.h" -#include "common/all-versions/default/EffectMap.h" - -using ::android::hardware::audio::common::V4_0::HidlUtils; - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/EffectsFactory.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/EffectsFactory.h b/audio/effect/4.0/default/EffectsFactory.h deleted file mode 100644 index 48e4b4cb9f..0000000000 --- a/audio/effect/4.0/default/EffectsFactory.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EFFECTSFACTORY_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EFFECTSFACTORY_H - -#include <system/audio_effect.h> - -#include <android/hardware/audio/effect/4.0/IEffectsFactory.h> - -#include <hidl/MQDescriptor.h> -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/EffectsFactory.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EFFECTSFACTORY_H diff --git a/audio/effect/4.0/default/EnvironmentalReverbEffect.cpp b/audio/effect/4.0/default/EnvironmentalReverbEffect.cpp deleted file mode 100644 index cc3102d1f8..0000000000 --- a/audio/effect/4.0/default/EnvironmentalReverbEffect.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "EnvReverb_HAL" -#include <android/log.h> - -#include "EnvironmentalReverbEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/EnvironmentalReverbEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/EqualizerEffect.cpp b/audio/effect/4.0/default/EqualizerEffect.cpp deleted file mode 100644 index d0a40bc3cd..0000000000 --- a/audio/effect/4.0/default/EqualizerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "Equalizer_HAL" - -#include "EqualizerEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/EqualizerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/EqualizerEffect.h b/audio/effect/4.0/default/EqualizerEffect.h deleted file mode 100644 index 7c9463b01e..0000000000 --- a/audio/effect/4.0/default/EqualizerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EQUALIZEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EQUALIZEREFFECT_H - -#include <android/hardware/audio/effect/4.0/IEqualizerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/EqualizerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EQUALIZEREFFECT_H diff --git a/audio/effect/4.0/default/LoudnessEnhancerEffect.cpp b/audio/effect/4.0/default/LoudnessEnhancerEffect.cpp deleted file mode 100644 index e3c5184225..0000000000 --- a/audio/effect/4.0/default/LoudnessEnhancerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "LoudnessEnhancer_HAL" - -#include "LoudnessEnhancerEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/LoudnessEnhancerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/LoudnessEnhancerEffect.h b/audio/effect/4.0/default/LoudnessEnhancerEffect.h deleted file mode 100644 index 64fa26add8..0000000000 --- a/audio/effect/4.0/default/LoudnessEnhancerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_LOUDNESSENHANCEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_LOUDNESSENHANCEREFFECT_H - -#include <android/hardware/audio/effect/4.0/ILoudnessEnhancerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/LoudnessEnhancerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_LOUDNESSENHANCEREFFECT_H diff --git a/audio/effect/4.0/default/NoiseSuppressionEffect.cpp b/audio/effect/4.0/default/NoiseSuppressionEffect.cpp deleted file mode 100644 index e83a8e3373..0000000000 --- a/audio/effect/4.0/default/NoiseSuppressionEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "NS_Effect_HAL" - -#include "NoiseSuppressionEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/NoiseSuppressionEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/NoiseSuppressionEffect.h b/audio/effect/4.0/default/NoiseSuppressionEffect.h deleted file mode 100644 index 36d45afaf7..0000000000 --- a/audio/effect/4.0/default/NoiseSuppressionEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_NOISESUPPRESSIONEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_NOISESUPPRESSIONEFFECT_H - -#include <android/hardware/audio/effect/4.0/INoiseSuppressionEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/NoiseSuppressionEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_NOISESUPPRESSIONEFFECT_H diff --git a/audio/effect/4.0/default/OWNERS b/audio/effect/4.0/default/OWNERS deleted file mode 100644 index 6fdc97ca29..0000000000 --- a/audio/effect/4.0/default/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -elaurent@google.com -krocard@google.com -mnaganov@google.com diff --git a/audio/effect/4.0/default/PresetReverbEffect.cpp b/audio/effect/4.0/default/PresetReverbEffect.cpp deleted file mode 100644 index 0c23be73af..0000000000 --- a/audio/effect/4.0/default/PresetReverbEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "PresetReverb_HAL" - -#include "PresetReverbEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/PresetReverbEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/PresetReverbEffect.h b/audio/effect/4.0/default/PresetReverbEffect.h deleted file mode 100644 index 3eeae0a04b..0000000000 --- a/audio/effect/4.0/default/PresetReverbEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_PRESETREVERBEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_PRESETREVERBEFFECT_H - -#include <android/hardware/audio/effect/4.0/IPresetReverbEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/PresetReverbEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_PRESETREVERBEFFECT_H diff --git a/audio/effect/4.0/default/VirtualizerEffect.cpp b/audio/effect/4.0/default/VirtualizerEffect.cpp deleted file mode 100644 index f50e8adb7b..0000000000 --- a/audio/effect/4.0/default/VirtualizerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "Virtualizer_HAL" - -#include "VirtualizerEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/VirtualizerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/VirtualizerEffect.h b/audio/effect/4.0/default/VirtualizerEffect.h deleted file mode 100644 index 8e7114e569..0000000000 --- a/audio/effect/4.0/default/VirtualizerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_VIRTUALIZEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_VIRTUALIZEREFFECT_H - -#include <android/hardware/audio/effect/4.0/IVirtualizerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/VirtualizerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_VIRTUALIZEREFFECT_H diff --git a/audio/effect/4.0/default/VisualizerEffect.cpp b/audio/effect/4.0/default/VisualizerEffect.cpp deleted file mode 100644 index 8d4f100ced..0000000000 --- a/audio/effect/4.0/default/VisualizerEffect.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "Visualizer_HAL" - -#include "VisualizerEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/VisualizerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/audio/effect/4.0/default/VisualizerEffect.h b/audio/effect/4.0/default/VisualizerEffect.h deleted file mode 100644 index 6b5ab9c393..0000000000 --- a/audio/effect/4.0/default/VisualizerEffect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_VISUALIZEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_VISUALIZEREFFECT_H - -#include <android/hardware/audio/effect/4.0/IVisualizerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/VisualizerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_VISUALIZEREFFECT_H diff --git a/audio/effect/4.0/vts/OWNERS b/audio/effect/4.0/vts/OWNERS deleted file mode 100644 index 8711a9ff6a..0000000000 --- a/audio/effect/4.0/vts/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -elaurent@google.com -krocard@google.com -mnaganov@google.com -yim@google.com -zhuoyao@google.com
\ No newline at end of file diff --git a/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp deleted file mode 100644 index 6338563c2e..0000000000 --- a/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 <unistd.h> -#include <iterator> - -#include <media/EffectsConfig.h> - -#include "utility/ValidateXml.h" - -TEST(CheckConfig, audioEffectsConfigurationValidation) { - RecordProperty("description", - "Verify that the effects configuration file is valid according to the schema"); - using namespace android::effectsConfig; - - std::vector<const char*> locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS)); - EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations, - "/data/local/tmp/audio_effects_conf_V4_0.xsd"); -} diff --git a/audio/effect/4.0/vts/functional/VtsHalAudioEffectV4_0TargetTest.cpp b/audio/effect/4.0/vts/functional/VtsHalAudioEffectV4_0TargetTest.cpp deleted file mode 100644 index ec783c4bfa..0000000000 --- a/audio/effect/4.0/vts/functional/VtsHalAudioEffectV4_0TargetTest.cpp +++ /dev/null @@ -1,852 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "AudioEffectHidlHalTest" -#include <android-base/logging.h> -#include <system/audio.h> - -#include <android/hardware/audio/effect/4.0/IEffect.h> -#include <android/hardware/audio/effect/4.0/IEffectsFactory.h> -#include <android/hardware/audio/effect/4.0/IEqualizerEffect.h> -#include <android/hardware/audio/effect/4.0/ILoudnessEnhancerEffect.h> -#include <android/hardware/audio/effect/4.0/types.h> -#include <android/hidl/allocator/1.0/IAllocator.h> -#include <android/hidl/memory/1.0/IMemory.h> - -#include <common/all-versions/VersionUtils.h> - -#include <VtsHalHidlTargetTestBase.h> -#include <VtsHalHidlTargetTestEnvBase.h> - -using android::hardware::audio::common::V4_0::AudioDevice; -using android::hardware::audio::common::V4_0::AudioHandleConsts; -using android::hardware::audio::common::V4_0::AudioMode; -using android::hardware::audio::common::V4_0::AudioSource; -using android::hardware::audio::common::V4_0::Uuid; -using android::hardware::audio::common::utils::mkBitfield; -using android::hardware::audio::effect::V4_0::AudioBuffer; -using android::hardware::audio::effect::V4_0::EffectAuxChannelsConfig; -using android::hardware::audio::effect::V4_0::EffectBufferConfig; -using android::hardware::audio::effect::V4_0::EffectConfig; -using android::hardware::audio::effect::V4_0::EffectDescriptor; -using android::hardware::audio::effect::V4_0::EffectOffloadParameter; -using android::hardware::audio::effect::V4_0::IEffect; -using android::hardware::audio::effect::V4_0::IEffectsFactory; -using android::hardware::audio::effect::V4_0::IEqualizerEffect; -using android::hardware::audio::effect::V4_0::ILoudnessEnhancerEffect; -using android::hardware::audio::effect::V4_0::Result; -using android::hardware::MQDescriptorSync; -using android::hardware::Return; -using android::hardware::Void; -using android::hardware::hidl_handle; -using android::hardware::hidl_memory; -using android::hardware::hidl_string; -using android::hardware::hidl_vec; -using android::hidl::allocator::V1_0::IAllocator; -using android::hidl::memory::V1_0::IMemory; -using android::sp; - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) -#endif - -// Test environment for Audio Effects Factory HIDL HAL. -class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static AudioEffectsFactoryHidlEnvironment* Instance() { - static AudioEffectsFactoryHidlEnvironment* instance = - new AudioEffectsFactoryHidlEnvironment; - return instance; - } - - virtual void registerTestServices() override { registerTestService<IEffectsFactory>(); } -}; - -// The main test class for Audio Effects Factory HIDL HAL. -class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - void SetUp() override { - effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>( - AudioEffectsFactoryHidlEnvironment::Instance()->getServiceName<IEffectsFactory>()); - ASSERT_NE(effectsFactory, nullptr); - } - - void TearDown() override { effectsFactory.clear(); } - - protected: - static void description(const std::string& description) { - RecordProperty("description", description); - } - - sp<IEffectsFactory> effectsFactory; -}; - -TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { - description("Verify that EnumerateEffects returns at least one effect"); - Result retval = Result::NOT_INITIALIZED; - size_t effectCount = 0; - Return<void> ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec<EffectDescriptor>& result) { - retval = r; - effectCount = result.size(); - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_GT(effectCount, 0u); -} - -TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) { - description("Verify that an effect can be created via CreateEffect"); - bool gotEffect = false; - Uuid effectUuid; - Return<void> ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec<EffectDescriptor>& result) { - if (r == Result::OK && result.size() > 0) { - gotEffect = true; - effectUuid = result[0].uuid; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(gotEffect); - Result retval = Result::NOT_INITIALIZED; - sp<IEffect> effect; - ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) { - retval = r; - if (r == Result::OK) { - effect = result; - } - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_NE(nullptr, effect.get()); -} - -TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) { - description( - "Verify that effects factory can provide an effect descriptor via " - "GetDescriptor"); - hidl_vec<EffectDescriptor> allDescriptors; - Return<void> ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec<EffectDescriptor>& result) { - if (r == Result::OK) { - allDescriptors = result; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_GT(allDescriptors.size(), 0u); - for (size_t i = 0; i < allDescriptors.size(); ++i) { - ret = effectsFactory->getDescriptor( - allDescriptors[i].uuid, [&](Result r, const EffectDescriptor& result) { - EXPECT_EQ(r, Result::OK); - EXPECT_EQ(result, allDescriptors[i]); - }); - } - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) { - description("Verify that debugDump doesn't crash on invalid arguments"); - Return<void> ret = effectsFactory->debug(hidl_handle(), {}); - ASSERT_TRUE(ret.isOk()); -} - -// Equalizer effect is required by CDD, but only the type is fixed. -// This is the same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java. -static const Uuid EQUALIZER_EFFECT_TYPE = { - 0x0bed4300, 0xddd6, 0x11db, 0x8f34, - std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}}; -// Loudness Enhancer effect is required by CDD, but only the type is fixed. -// This is the same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java. -static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = { - 0xfe3199be, 0xaed0, 0x413f, 0x87bb, - std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}}; - -// The main test class for Audio Effect HIDL HAL. -class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - void SetUp() override { - effectsFactory = - ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>(); - ASSERT_NE(nullptr, effectsFactory.get()); - - findAndCreateEffect(getEffectType()); - ASSERT_NE(nullptr, effect.get()); - - Return<Result> ret = effect->init(); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, ret); - } - - void TearDown() override { - effect.clear(); - effectsFactory.clear(); - } - - protected: - static void description(const std::string& description) { - RecordProperty("description", description); - } - - virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; } - - void findAndCreateEffect(const Uuid& type); - void findEffectInstance(const Uuid& type, Uuid* uuid); - void getChannelCount(uint32_t* channelCount); - - sp<IEffectsFactory> effectsFactory; - sp<IEffect> effect; -}; - -void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) { - Uuid effectUuid; - findEffectInstance(type, &effectUuid); - Return<void> ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) { - if (r == Result::OK) { - effect = result; - } - }); - ASSERT_TRUE(ret.isOk()); -} - -void AudioEffectHidlTest::findEffectInstance(const Uuid& type, Uuid* uuid) { - bool effectFound = false; - Return<void> ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec<EffectDescriptor>& result) { - if (r == Result::OK) { - for (const auto& desc : result) { - if (desc.type == type) { - effectFound = true; - *uuid = desc.uuid; - break; - } - } - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(effectFound); -} - -void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) { - Result retval; - EffectConfig currentConfig; - Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { - retval = r; - if (r == Result::OK) { - currentConfig = conf; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); - ASSERT_TRUE(audio_channel_mask_is_valid( - static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels))); - *channelCount = audio_channel_count_from_out_mask( - static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)); -} - -TEST_F(AudioEffectHidlTest, Close) { - description("Verify that an effect can be closed"); - Return<Result> ret = effect->close(); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, GetDescriptor) { - description( - "Verify that an effect can return its own descriptor via GetDescriptor"); - Result retval = Result::NOT_INITIALIZED; - Uuid actualType; - Return<void> ret = - effect->getDescriptor([&](Result r, const EffectDescriptor& desc) { - retval = r; - if (r == Result::OK) { - actualType = desc.type; - } - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(getEffectType(), actualType); -} - -TEST_F(AudioEffectHidlTest, GetSetConfig) { - description( - "Verify that it is possible to manipulate effect config via Get / " - "SetConfig"); - Result retval = Result::NOT_INITIALIZED; - EffectConfig currentConfig; - Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { - retval = r; - if (r == Result::OK) { - currentConfig = conf; - } - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - Return<Result> ret2 = effect->setConfig(currentConfig, nullptr, nullptr); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, ret2); -} - -TEST_F(AudioEffectHidlTest, GetConfigReverse) { - description("Verify that GetConfigReverse does not crash"); - Return<void> ret = - effect->getConfigReverse([&](Result, const EffectConfig&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { - description("Verify that GetSupportedAuxChannelsConfigs does not crash"); - Return<void> ret = effect->getSupportedAuxChannelsConfigs( - 0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) { - description("Verify that GetAuxChannelsConfig does not crash"); - Return<void> ret = effect->getAuxChannelsConfig( - [&](Result, const EffectAuxChannelsConfig&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) { - description("Verify that SetAuxChannelsConfig does not crash"); - Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig()); - EXPECT_TRUE(ret.isOk()); -} - -// Not generated automatically because AudioBuffer contains -// instances of hidl_memory which can't be compared properly -// in general case due to presence of handles. -// -// However, in this particular case, handles must not present -// thus comparison is possible. -// -// operator== must be defined in the same namespace as the structures. -namespace android { -namespace hardware { -namespace audio { -namespace effect { -namespace V4_0 { -inline bool operator==(const AudioBuffer& lhs, const AudioBuffer& rhs) { - return lhs.id == rhs.id && lhs.frameCount == rhs.frameCount && - lhs.data.handle() == nullptr && rhs.data.handle() == nullptr; -} - -inline bool operator==(const EffectBufferConfig& lhs, - const EffectBufferConfig& rhs) { - return lhs.buffer == rhs.buffer && lhs.samplingRateHz == rhs.samplingRateHz && - lhs.channels == rhs.channels && lhs.format == rhs.format && - lhs.accessMode == rhs.accessMode && lhs.mask == rhs.mask; -} - -inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) { - return lhs.inputCfg == rhs.inputCfg && lhs.outputCfg == rhs.outputCfg; -} -} // namespace V4_0 -} // namespace effect -} // namespace audio -} // namespace hardware -} // namespace android - -TEST_F(AudioEffectHidlTest, Reset) { - description("Verify that Reset preserves effect configuration"); - Result retval = Result::NOT_INITIALIZED; - EffectConfig originalConfig; - Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { - retval = r; - if (r == Result::OK) { - originalConfig = conf; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); - Return<Result> ret2 = effect->reset(); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, ret2); - EffectConfig configAfterReset; - ret = effect->getConfig([&](Result r, const EffectConfig& conf) { - retval = r; - if (r == Result::OK) { - configAfterReset = conf; - } - }); - EXPECT_EQ(originalConfig, configAfterReset); -} - -TEST_F(AudioEffectHidlTest, DisableEnableDisable) { - description("Verify Disable -> Enable -> Disable sequence for an effect"); - Return<Result> ret = effect->disable(); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::INVALID_ARGUMENTS, ret); - ret = effect->enable(); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - ret = effect->disable(); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, SetDevice) { - description("Verify that SetDevice works for an output chain effect"); - Return<Result> ret = effect->setDevice(mkBitfield(AudioDevice::OUT_SPEAKER)); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, SetAndGetVolume) { - description("Verify that SetAndGetVolume method works for an effect"); - uint32_t channelCount; - getChannelCount(&channelCount); - hidl_vec<uint32_t> volumes; - volumes.resize(channelCount); - for (uint32_t i = 0; i < channelCount; ++i) { - volumes[i] = 0; - } - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = effect->setAndGetVolume( - volumes, [&](Result r, const hidl_vec<uint32_t>&) { retval = r; }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); -} - -TEST_F(AudioEffectHidlTest, VolumeChangeNotification) { - description("Verify that effect accepts VolumeChangeNotification"); - uint32_t channelCount; - getChannelCount(&channelCount); - hidl_vec<uint32_t> volumes; - volumes.resize(channelCount); - for (uint32_t i = 0; i < channelCount; ++i) { - volumes[i] = 0; - } - Return<Result> ret = effect->volumeChangeNotification(volumes); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, SetAudioMode) { - description("Verify that SetAudioMode works for an effect"); - Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); -} - -TEST_F(AudioEffectHidlTest, SetConfigReverse) { - description("Verify that SetConfigReverse does not crash"); - Return<Result> ret = - effect->setConfigReverse(EffectConfig(), nullptr, nullptr); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetInputDevice) { - description("Verify that SetInputDevice does not crash"); - Return<Result> ret = effect->setInputDevice(mkBitfield(AudioDevice::IN_BUILTIN_MIC)); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetAudioSource) { - description("Verify that SetAudioSource does not crash"); - Return<Result> ret = effect->setAudioSource(AudioSource::MIC); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, Offload) { - description("Verify that calling Offload method does not crash"); - EffectOffloadParameter offloadParam; - offloadParam.isOffload = false; - offloadParam.ioHandle = - static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE); - Return<Result> ret = effect->offload(offloadParam); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, PrepareForProcessing) { - description("Verify that PrepareForProcessing method works for an effect"); - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = effect->prepareForProcessing( - [&](Result r, const MQDescriptorSync<Result>&) { retval = r; }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); -} - -TEST_F(AudioEffectHidlTest, SetProcessBuffers) { - description("Verify that SetProcessBuffers works for an effect"); - sp<IAllocator> ashmem = IAllocator::getService("ashmem"); - ASSERT_NE(nullptr, ashmem.get()); - bool success = false; - AudioBuffer buffer; - Return<void> ret = - ashmem->allocate(1024, [&](bool s, const hidl_memory& memory) { - success = s; - if (s) { - buffer.data = memory; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(success); - Return<Result> ret2 = effect->setProcessBuffers(buffer, buffer); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, ret2); -} - -TEST_F(AudioEffectHidlTest, Command) { - description("Verify that Command does not crash"); - Return<void> ret = effect->command(0, hidl_vec<uint8_t>(), 0, - [&](int32_t, const hidl_vec<uint8_t>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetParameter) { - description("Verify that SetParameter does not crash"); - Return<Result> ret = - effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>()); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetParameter) { - description("Verify that GetParameter does not crash"); - Return<void> ret = effect->getParameter( - hidl_vec<uint8_t>(), 0, [&](Result, const hidl_vec<uint8_t>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) { - description("Verify that GetSupportedConfigsForFeature does not crash"); - Return<void> ret = effect->getSupportedConfigsForFeature( - 0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) { - description("Verify that GetCurrentConfigForFeature does not crash"); - Return<void> ret = effect->getCurrentConfigForFeature( - 0, 0, [&](Result, const hidl_vec<uint8_t>&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) { - description("Verify that SetCurrentConfigForFeature does not crash"); - Return<Result> ret = - effect->setCurrentConfigForFeature(0, hidl_vec<uint8_t>()); - EXPECT_TRUE(ret.isOk()); -} - - -// The main test class for Equalizer Audio Effect HIDL HAL. -class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest { - public: - void SetUp() override { - AudioEffectHidlTest::SetUp(); - equalizer = IEqualizerEffect::castFrom(effect); - ASSERT_NE(nullptr, equalizer.get()); - } - - protected: - Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; } - void getNumBands(uint16_t* numBands); - void getLevelRange(int16_t* minLevel, int16_t* maxLevel); - void getBandFrequencyRange(uint16_t band, uint32_t* minFreq, - uint32_t* centerFreq, uint32_t* maxFreq); - void getPresetCount(size_t* count); - - sp<IEqualizerEffect> equalizer; -}; - -void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) { - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = equalizer->getNumBands([&](Result r, uint16_t b) { - retval = r; - if (retval == Result::OK) { - *numBands = b; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); -} - -void EqualizerAudioEffectHidlTest::getLevelRange(int16_t* minLevel, - int16_t* maxLevel) { - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = - equalizer->getLevelRange([&](Result r, int16_t min, int16_t max) { - retval = r; - if (retval == Result::OK) { - *minLevel = min; - *maxLevel = max; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); -} - -void EqualizerAudioEffectHidlTest::getBandFrequencyRange(uint16_t band, - uint32_t* minFreq, - uint32_t* centerFreq, - uint32_t* maxFreq) { - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = equalizer->getBandFrequencyRange( - band, [&](Result r, uint32_t min, uint32_t max) { - retval = r; - if (retval == Result::OK) { - *minFreq = min; - *maxFreq = max; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); - ret = equalizer->getBandCenterFrequency(band, [&](Result r, uint32_t center) { - retval = r; - if (retval == Result::OK) { - *centerFreq = center; - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); -} - -void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) { - Result retval = Result::NOT_INITIALIZED; - Return<void> ret = equalizer->getPresetNames( - [&](Result r, const hidl_vec<hidl_string>& names) { - retval = r; - if (retval == Result::OK) { - *count = names.size(); - } - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(Result::OK, retval); -} - -TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) { - description("Verify that Equalizer effect reports at least one band"); - uint16_t numBands = 0; - getNumBands(&numBands); - EXPECT_GT(numBands, 0); -} - -TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) { - description("Verify that Equalizer effect reports adequate band level range"); - int16_t minLevel = 0x7fff, maxLevel = 0; - getLevelRange(&minLevel, &maxLevel); - EXPECT_GT(maxLevel, minLevel); -} - -TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) { - description( - "Verify that manipulating band levels works for Equalizer effect"); - uint16_t numBands = 0; - getNumBands(&numBands); - ASSERT_GT(numBands, 0); - int16_t levels[3]{0x7fff, 0, 0}; - getLevelRange(&levels[0], &levels[2]); - ASSERT_GT(levels[2], levels[0]); - levels[1] = (levels[2] + levels[0]) / 2; - for (uint16_t i = 0; i < numBands; ++i) { - for (size_t j = 0; j < ARRAY_SIZE(levels); ++j) { - Return<Result> ret = equalizer->setBandLevel(i, levels[j]); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Result retval = Result::NOT_INITIALIZED; - int16_t actualLevel; - Return<void> ret2 = equalizer->getBandLevel(i, [&](Result r, int16_t l) { - retval = r; - if (retval == Result::OK) { - actualLevel = l; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(levels[j], actualLevel); - } - } -} - -TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { - description( - "Verify that Equalizer effect reports adequate band frequency range"); - uint16_t numBands = 0; - getNumBands(&numBands); - ASSERT_GT(numBands, 0); - for (uint16_t i = 0; i < numBands; ++i) { - uint32_t minFreq = 0xffffffff, centerFreq = 0xffffffff, - maxFreq = 0xffffffff; - getBandFrequencyRange(i, &minFreq, ¢erFreq, &maxFreq); - // Note: NXP legacy implementation reports "1" as upper bound for last band, - // so this check fails. - EXPECT_GE(maxFreq, centerFreq); - EXPECT_GE(centerFreq, minFreq); - } -} - -TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) { - description( - "Verify that Equalizer effect supports GetBandForFrequency correctly"); - uint16_t numBands = 0; - getNumBands(&numBands); - ASSERT_GT(numBands, 0); - for (uint16_t i = 0; i < numBands; ++i) { - uint32_t freqs[3]{0, 0, 0}; - getBandFrequencyRange(i, &freqs[0], &freqs[1], &freqs[2]); - // NXP legacy implementation reports "1" as upper bound for last band, some - // of the checks fail. - for (size_t j = 0; j < ARRAY_SIZE(freqs); ++j) { - if (j == 0) { - freqs[j]++; - } // Min frequency is an open interval. - Result retval = Result::NOT_INITIALIZED; - uint16_t actualBand = numBands + 1; - Return<void> ret = - equalizer->getBandForFrequency(freqs[j], [&](Result r, uint16_t b) { - retval = r; - if (retval == Result::OK) { - actualBand = b; - } - }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j]; - } - } -} - -TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) { - description("Verify that Equalizer effect reports at least one preset"); - size_t presetCount; - getPresetCount(&presetCount); - EXPECT_GT(presetCount, 0u); -} - -TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { - description( - "Verify that manipulating the current preset for Equalizer effect"); - size_t presetCount; - getPresetCount(&presetCount); - ASSERT_GT(presetCount, 0u); - for (uint16_t i = 0; i < presetCount; ++i) { - Return<Result> ret = equalizer->setCurrentPreset(i); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Result retval = Result::NOT_INITIALIZED; - uint16_t actualPreset = 0xffff; - Return<void> ret2 = equalizer->getCurrentPreset([&](Result r, uint16_t p) { - retval = r; - if (retval == Result::OK) { - actualPreset = p; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(i, actualPreset); - } -} - -TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) { - description( - "Verify that setting band levels and presets works via Get / " - "SetAllProperties for Equalizer effect"); - using AllProperties = - android::hardware::audio::effect::V4_0::IEqualizerEffect::AllProperties; - uint16_t numBands = 0; - getNumBands(&numBands); - ASSERT_GT(numBands, 0); - AllProperties props; - props.bandLevels.resize(numBands); - for (size_t i = 0; i < numBands; ++i) { - props.bandLevels[i] = 0; - } - - AllProperties actualProps; - Result retval = Result::NOT_INITIALIZED; - - // Verify setting of the band levels via properties. - props.curPreset = -1; - Return<Result> ret = equalizer->setAllProperties(props); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Return<void> ret2 = - equalizer->getAllProperties([&](Result r, AllProperties p) { - retval = r; - if (retval == Result::OK) { - actualProps = p; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(props.bandLevels, actualProps.bandLevels); - - // Verify setting of the current preset via properties. - props.curPreset = 0; // Assuming there is at least one preset. - ret = equalizer->setAllProperties(props); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) { - retval = r; - if (retval == Result::OK) { - actualProps = p; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(props.curPreset, actualProps.curPreset); -} - -// The main test class for Equalizer Audio Effect HIDL HAL. -class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest { - public: - void SetUp() override { - AudioEffectHidlTest::SetUp(); - enhancer = ILoudnessEnhancerEffect::castFrom(effect); - ASSERT_NE(nullptr, enhancer.get()); - } - - protected: - Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; } - - sp<ILoudnessEnhancerEffect> enhancer; -}; - -TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { - description( - "Verify that manipulating the target gain works for Loudness Enhancer " - "effect"); - const int32_t gain = 100; - Return<Result> ret = enhancer->setTargetGain(gain); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - int32_t actualGain = 0; - Result retval; - Return<void> ret2 = enhancer->getTargetGain([&](Result r, int32_t g) { - retval = r; - if (retval == Result::OK) { - actualGain = g; - } - }); - EXPECT_TRUE(ret2.isOk()); - EXPECT_EQ(Result::OK, retval); - EXPECT_EQ(gain, actualGain); -} - -int main(int argc, char** argv) { - ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - AudioEffectsFactoryHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; -} diff --git a/audio/effect/4.0/xml/audio_effects_conf.xsd b/audio/effect/4.0/xml/audio_effects_conf.xsd new file mode 120000 index 0000000000..9d85fa7c68 --- /dev/null +++ b/audio/effect/4.0/xml/audio_effects_conf.xsd @@ -0,0 +1 @@ +../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file diff --git a/audio/effect/4.0/xml/audio_effects_conf_V4_0.xsd b/audio/effect/4.0/xml/audio_effects_conf_V4_0.xsd deleted file mode 120000 index 82d569a783..0000000000 --- a/audio/effect/4.0/xml/audio_effects_conf_V4_0.xsd +++ /dev/null @@ -1 +0,0 @@ -../../2.0/xml/audio_effects_conf_V2_0.xsd
\ No newline at end of file diff --git a/audio/effect/5.0/Android.bp b/audio/effect/5.0/Android.bp index d60d94aa9e..78b950ea86 100644 --- a/audio/effect/5.0/Android.bp +++ b/audio/effect/5.0/Android.bp @@ -26,6 +26,7 @@ hidl_interface { interfaces: [ "android.hardware.audio.common@5.0", "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", ], types: [ "AudioBuffer", diff --git a/audio/effect/5.0/types.hal b/audio/effect/5.0/types.hal index 84e11086b4..4b6c196b81 100644 --- a/audio/effect/5.0/types.hal +++ b/audio/effect/5.0/types.hal @@ -53,6 +53,7 @@ enum Result : int32_t { * | Volume | 6..8 | 0 none * | management | | 1 implements volume control * | | | 2 requires volume indication + * | | | 3 monitors requested volume * | | | 4 reserved * +----------------+--------+-------------------------------------------------- * | Device | 9..11 | 0 none @@ -136,6 +137,7 @@ enum EffectFlags : int32_t { VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT, VOLUME_CTRL = 1 << VOLUME_SHIFT, VOLUME_IND = 2 << VOLUME_SHIFT, + VOLUME_MONITOR = 3 << VOLUME_SHIFT, VOLUME_NONE = 0 << VOLUME_SHIFT, // Device indication diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp new file mode 100644 index 0000000000..967135ce51 --- /dev/null +++ b/audio/effect/5.0/xml/Android.bp @@ -0,0 +1,6 @@ + +xsd_config { + name: "audio_effects_conf", + srcs: ["audio_effects_conf.xsd"], + package_name: "audio.effects.V5_0", +} diff --git a/audio/effect/5.0/xml/api/current.txt b/audio/effect/5.0/xml/api/current.txt new file mode 100644 index 0000000000..473bb10358 --- /dev/null +++ b/audio/effect/5.0/xml/api/current.txt @@ -0,0 +1,132 @@ +// Signature format: 2.0 +package audio.effects.V5_0 { + + public class Audioeffectsconf { + ctor public Audioeffectsconf(); + method public audio.effects.V5_0.EffectsType getEffects(); + method public audio.effects.V5_0.LibrariesType getLibraries(); + method public audio.effects.V5_0.Audioeffectsconf.Postprocess getPostprocess(); + method public audio.effects.V5_0.Audioeffectsconf.Preprocess getPreprocess(); + method public audio.effects.V5_0.VersionType getVersion(); + method public void setEffects(audio.effects.V5_0.EffectsType); + method public void setLibraries(audio.effects.V5_0.LibrariesType); + method public void setPostprocess(audio.effects.V5_0.Audioeffectsconf.Postprocess); + method public void setPreprocess(audio.effects.V5_0.Audioeffectsconf.Preprocess); + method public void setVersion(audio.effects.V5_0.VersionType); + } + + public static class Audioeffectsconf.Postprocess { + ctor public Audioeffectsconf.Postprocess(); + method public java.util.List<audio.effects.V5_0.StreamPostprocessType> getStream(); + } + + public static class Audioeffectsconf.Preprocess { + ctor public Audioeffectsconf.Preprocess(); + method public java.util.List<audio.effects.V5_0.StreamPreprocessType> getStream(); + } + + public class EffectImplType { + ctor public EffectImplType(); + method public String getLibrary(); + method public String getUuid(); + method public void setLibrary(String); + method public void setUuid(String); + } + + public class EffectProxyType extends audio.effects.V5_0.EffectType { + ctor public EffectProxyType(); + method public audio.effects.V5_0.EffectImplType getLibhw(); + method public audio.effects.V5_0.EffectImplType getLibsw(); + method public void setLibhw(audio.effects.V5_0.EffectImplType); + method public void setLibsw(audio.effects.V5_0.EffectImplType); + } + + public class EffectType extends audio.effects.V5_0.EffectImplType { + ctor public EffectType(); + method public String getName(); + method public void setName(String); + } + + public class EffectsType { + ctor public EffectsType(); + method public java.util.List<audio.effects.V5_0.EffectProxyType> getEffectProxy_optional(); + method public java.util.List<audio.effects.V5_0.EffectType> getEffect_optional(); + } + + public class LibrariesType { + ctor public LibrariesType(); + method public java.util.List<audio.effects.V5_0.LibrariesType.Library> getLibrary(); + } + + public static class LibrariesType.Library { + ctor public LibrariesType.Library(); + method public String getName(); + method public String getPath(); + method public void setName(String); + method public void setPath(String); + } + + public enum StreamInputType { + method public String getRawName(); + enum_constant public static final audio.effects.V5_0.StreamInputType camcorder; + enum_constant public static final audio.effects.V5_0.StreamInputType mic; + enum_constant public static final audio.effects.V5_0.StreamInputType unprocessed; + enum_constant public static final audio.effects.V5_0.StreamInputType voice_call; + enum_constant public static final audio.effects.V5_0.StreamInputType voice_communication; + enum_constant public static final audio.effects.V5_0.StreamInputType voice_downlink; + enum_constant public static final audio.effects.V5_0.StreamInputType voice_performance; + enum_constant public static final audio.effects.V5_0.StreamInputType voice_recognition; + enum_constant public static final audio.effects.V5_0.StreamInputType voice_uplink; + } + + public enum StreamOutputType { + method public String getRawName(); + enum_constant public static final audio.effects.V5_0.StreamOutputType alarm; + enum_constant public static final audio.effects.V5_0.StreamOutputType bluetooth_sco; + enum_constant public static final audio.effects.V5_0.StreamOutputType dtmf; + enum_constant public static final audio.effects.V5_0.StreamOutputType enforced_audible; + enum_constant public static final audio.effects.V5_0.StreamOutputType music; + enum_constant public static final audio.effects.V5_0.StreamOutputType notification; + enum_constant public static final audio.effects.V5_0.StreamOutputType ring; + enum_constant public static final audio.effects.V5_0.StreamOutputType system; + enum_constant public static final audio.effects.V5_0.StreamOutputType tts; + enum_constant public static final audio.effects.V5_0.StreamOutputType voice_call; + } + + public class StreamPostprocessType extends audio.effects.V5_0.StreamProcessingType { + ctor public StreamPostprocessType(); + method public audio.effects.V5_0.StreamOutputType getType(); + method public void setType(audio.effects.V5_0.StreamOutputType); + } + + public class StreamPreprocessType extends audio.effects.V5_0.StreamProcessingType { + ctor public StreamPreprocessType(); + method public audio.effects.V5_0.StreamInputType getType(); + method public void setType(audio.effects.V5_0.StreamInputType); + } + + public class StreamProcessingType { + ctor public StreamProcessingType(); + method public java.util.List<audio.effects.V5_0.StreamProcessingType.Apply> getApply(); + } + + public static class StreamProcessingType.Apply { + ctor public StreamProcessingType.Apply(); + method public String getEffect(); + method public void setEffect(String); + } + + public enum VersionType { + method public String getRawName(); + enum_constant public static final audio.effects.V5_0.VersionType _2_0; + } + + public class XmlParser { + ctor public XmlParser(); + method public static audio.effects.V5_0.Audioeffectsconf read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/audio/effect/5.0/xml/api/last_current.txt b/audio/effect/5.0/xml/api/last_current.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/audio/effect/5.0/xml/api/last_current.txt diff --git a/audio/effect/5.0/xml/api/last_removed.txt b/audio/effect/5.0/xml/api/last_removed.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/audio/effect/5.0/xml/api/last_removed.txt diff --git a/audio/effect/5.0/xml/api/removed.txt b/audio/effect/5.0/xml/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/audio/effect/5.0/xml/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/audio/effect/all-versions/OWNERS b/audio/effect/all-versions/OWNERS deleted file mode 100644 index 6fdc97ca29..0000000000 --- a/audio/effect/all-versions/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -elaurent@google.com -krocard@google.com -mnaganov@google.com diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.impl.h b/audio/effect/all-versions/default/AcousticEchoCancelerEffect.cpp index 8ad80a22a0..0b60622c05 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.impl.h +++ b/audio/effect/all-versions/default/AcousticEchoCancelerEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "AEC_Effect_HAL" + +#include "AcousticEchoCancelerEffect.h" #include <android/log.h> #include <system/audio_effects/effect_aec.h> @@ -25,7 +27,7 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { AcousticEchoCancelerEffect::AcousticEchoCancelerEffect(effect_handle_t handle) @@ -33,7 +35,7 @@ AcousticEchoCancelerEffect::AcousticEchoCancelerEffect(effect_handle_t handle) AcousticEchoCancelerEffect::~AcousticEchoCancelerEffect() {} -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> AcousticEchoCancelerEffect::init() { return mEffect->init(); } @@ -163,7 +165,7 @@ Return<Result> AcousticEchoCancelerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAcousticEchoCancelerEffect +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IAcousticEchoCancelerEffect // follow. Return<Result> AcousticEchoCancelerEffect::setEchoDelay(uint32_t echoDelayMs) { return mEffect->setParam(AEC_PARAM_ECHO_DELAY, echoDelayMs); @@ -174,7 +176,7 @@ Return<void> AcousticEchoCancelerEffect::getEchoDelay(getEchoDelay_cb _hidl_cb) } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.h b/audio/effect/all-versions/default/AcousticEchoCancelerEffect.h index 852cb3fd15..c18f88b276 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.h +++ b/audio/effect/all-versions/default/AcousticEchoCancelerEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_ACOUSTICECHOCANCELEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_ACOUSTICECHOCANCELEREFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IAcousticEchoCancelerEffect.h) + +#include "Effect.h" #include <hidl/Status.h> @@ -26,21 +31,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAcousticEchoCancelerEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using ::android::hardware::audio::effect::CPP_VERSION::IAcousticEchoCancelerEffect; +using ::android::hardware::audio::effect::CPP_VERSION::Result; struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect { explicit AcousticEchoCancelerEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -85,7 +90,7 @@ struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect { Return<Result> close() override; // Methods from - // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAcousticEchoCancelerEffect follow. + // ::android::hardware::audio::effect::CPP_VERSION::IAcousticEchoCancelerEffect follow. Return<Result> setEchoDelay(uint32_t echoDelayMs) override; Return<void> getEchoDelay(getEchoDelay_cb _hidl_cb) override; @@ -96,8 +101,10 @@ struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_ACOUSTICECHOCANCELEREFFECT_H diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp index ed2a093050..f23a463bc5 100644 --- a/audio/effect/all-versions/default/Android.bp +++ b/audio/effect/all-versions/default/Android.bp @@ -1,10 +1,25 @@ -cc_library_headers { - name: "android.hardware.audio.effect@all-versions-impl", +cc_defaults { + name: "android.hardware.audio.effect-impl_default", defaults: ["hidl_defaults"], vendor: true, relative_install_path: "hw", - - export_include_dirs: ["include"], + srcs: [ + "AcousticEchoCancelerEffect.cpp", + "AudioBufferManager.cpp", + "AutomaticGainControlEffect.cpp", + "BassBoostEffect.cpp", + "Conversions.cpp", + "DownmixEffect.cpp", + "Effect.cpp", + "EffectsFactory.cpp", + "EnvironmentalReverbEffect.cpp", + "EqualizerEffect.cpp", + "LoudnessEnhancerEffect.cpp", + "NoiseSuppressionEffect.cpp", + "PresetReverbEffect.cpp", + "VirtualizerEffect.cpp", + "VisualizerEffect.cpp", + ], shared_libs: [ "libbase", @@ -21,11 +36,59 @@ cc_library_headers { ], header_libs: [ + "android.hardware.audio.common.util@all-versions", "libaudio_system_headers", "libaudioclient_headers", "libeffects_headers", "libhardware_headers", "libmedia_headers", - "android.hardware.audio.common.util@all-versions", ], } + +cc_library_shared { + name: "android.hardware.audio.effect@2.0-impl", + defaults: ["android.hardware.audio.effect-impl_default"], + shared_libs: [ + "android.hardware.audio.common@2.0", + "android.hardware.audio.common@2.0-util", + "android.hardware.audio.effect@2.0", + ], + + cflags: [ + "-DMAJOR_VERSION=2", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_library_shared { + name: "android.hardware.audio.effect@4.0-impl", + defaults: ["android.hardware.audio.effect-impl_default"], + shared_libs: [ + "android.hardware.audio.common@4.0", + "android.hardware.audio.common@4.0-util", + "android.hardware.audio.effect@4.0", + ], + + cflags: [ + "-DMAJOR_VERSION=4", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_library_shared { + name: "android.hardware.audio.effect@5.0-impl", + defaults: ["android.hardware.audio.effect-impl_default"], + shared_libs: [ + "android.hardware.audio.common@5.0", + "android.hardware.audio.common@5.0-util", + "android.hardware.audio.effect@5.0", + ], + + cflags: [ + "-DMAJOR_VERSION=5", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.impl.h b/audio/effect/all-versions/default/AudioBufferManager.cpp index 71ccd2d520..9a638fda2c 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.impl.h +++ b/audio/effect/all-versions/default/AudioBufferManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#include "AudioBufferManager.h" #include <atomic> @@ -53,7 +53,7 @@ void AudioBufferManager::removeEntry(uint64_t id) { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { AudioBufferWrapper::AudioBufferWrapper(const AudioBuffer& buffer) @@ -83,7 +83,7 @@ bool AudioBufferWrapper::init() { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.h b/audio/effect/all-versions/default/AudioBufferManager.h index 34dea2d03b..8b956cdb9b 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.h +++ b/audio/effect/all-versions/default/AudioBufferManager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -14,7 +14,10 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_AUDIO_BUFFER_MANAGER_H_ +#define ANDROID_HARDWARE_AUDIO_EFFECT_AUDIO_BUFFER_MANAGER_H_ + +#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h) #include <mutex> @@ -24,14 +27,14 @@ #include <utils/RefBase.h> #include <utils/Singleton.h> -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; +using ::android::hardware::audio::effect::CPP_VERSION::AudioBuffer; using ::android::hidl::memory::V1_0::IMemory; namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { class AudioBufferWrapper : public RefBase { @@ -51,13 +54,13 @@ class AudioBufferWrapper : public RefBase { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::implementation::AudioBufferWrapper; +using ::android::hardware::audio::effect::CPP_VERSION::implementation::AudioBufferWrapper; namespace android { @@ -67,7 +70,7 @@ class AudioBufferManager : public Singleton<AudioBufferManager> { bool wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper); private: - friend class hardware::audio::effect::AUDIO_HAL_VERSION::implementation::AudioBufferWrapper; + friend class hardware::audio::effect::CPP_VERSION::implementation::AudioBufferWrapper; // Called by AudioBufferWrapper. void removeEntry(uint64_t id); @@ -77,3 +80,5 @@ class AudioBufferManager : public Singleton<AudioBufferManager> { }; } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_AUDIO_BUFFER_MANAGER_H_ diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.impl.h b/audio/effect/all-versions/default/AutomaticGainControlEffect.cpp index e2e751e86b..651dd1b228 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.impl.h +++ b/audio/effect/all-versions/default/AutomaticGainControlEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "AGC_Effect_HAL" + +#include "AutomaticGainControlEffect.h" #include <android/log.h> @@ -24,7 +26,7 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { AutomaticGainControlEffect::AutomaticGainControlEffect(effect_handle_t handle) @@ -46,7 +48,7 @@ void AutomaticGainControlEffect::propertiesToHal( halProperties->limiterEnabled = properties.limiterEnabled; } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> AutomaticGainControlEffect::init() { return mEffect->init(); } @@ -176,7 +178,7 @@ Return<Result> AutomaticGainControlEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAutomaticGainControlEffect +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IAutomaticGainControlEffect // follow. Return<Result> AutomaticGainControlEffect::setTargetLevel(int16_t targetLevelMb) { return mEffect->setParam(AGC_PARAM_TARGET_LEVEL, targetLevelMb); @@ -219,7 +221,7 @@ Return<void> AutomaticGainControlEffect::getAllProperties(getAllProperties_cb _h } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.h b/audio/effect/all-versions/default/AutomaticGainControlEffect.h index 5ac43eb9bc..a281b1ddcd 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.h +++ b/audio/effect/all-versions/default/AutomaticGainControlEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_AUTOMATICGAINCONTROLEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_AUTOMATICGAINCONTROLEFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IAutomaticGainControlEffect.h) + +#include "Effect.h" #include <system/audio_effects/effect_agc.h> @@ -28,21 +33,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAutomaticGainControlEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using ::android::hardware::audio::effect::CPP_VERSION::IAutomaticGainControlEffect; +using ::android::hardware::audio::effect::CPP_VERSION::Result; struct AutomaticGainControlEffect : public IAutomaticGainControlEffect { explicit AutomaticGainControlEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -87,7 +92,7 @@ struct AutomaticGainControlEffect : public IAutomaticGainControlEffect { Return<Result> close() override; // Methods from - // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAutomaticGainControlEffect follow. + // ::android::hardware::audio::effect::CPP_VERSION::IAutomaticGainControlEffect follow. Return<Result> setTargetLevel(int16_t targetLevelMb) override; Return<void> getTargetLevel(getTargetLevel_cb _hidl_cb) override; Return<Result> setCompGain(int16_t compGainMb) override; @@ -110,8 +115,10 @@ struct AutomaticGainControlEffect : public IAutomaticGainControlEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_AUTOMATICGAINCONTROLEFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.impl.h b/audio/effect/all-versions/default/BassBoostEffect.cpp index 7bcb4a3497..6f7763db8e 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.impl.h +++ b/audio/effect/all-versions/default/BassBoostEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "BassBoost_HAL" + +#include "BassBoostEffect.h" #include <android/log.h> #include <system/audio_effects/effect_bassboost.h> @@ -25,14 +27,14 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { BassBoostEffect::BassBoostEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {} BassBoostEffect::~BassBoostEffect() {} -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> BassBoostEffect::init() { return mEffect->init(); } @@ -159,7 +161,7 @@ Return<Result> BassBoostEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IBassBoostEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IBassBoostEffect follow. Return<void> BassBoostEffect::isStrengthSupported(isStrengthSupported_cb _hidl_cb) { return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH_SUPPORTED, _hidl_cb); } @@ -173,7 +175,7 @@ Return<void> BassBoostEffect::getStrength(getStrength_cb _hidl_cb) { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.h b/audio/effect/all-versions/default/BassBoostEffect.h index 29173ddebe..a184ac2cc8 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.h +++ b/audio/effect/all-versions/default/BassBoostEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,14 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_BASSBOOSTEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_BASSBOOSTEFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IBassBoostEffect.h) + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" #include <hidl/Status.h> @@ -26,21 +33,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IBassBoostEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using ::android::hardware::audio::effect::CPP_VERSION::IBassBoostEffect; +using ::android::hardware::audio::effect::CPP_VERSION::Result; struct BassBoostEffect : public IBassBoostEffect { explicit BassBoostEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -84,7 +91,7 @@ struct BassBoostEffect : public IBassBoostEffect { const hidl_vec<uint8_t>& configData) override; Return<Result> close() override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IBassBoostEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IBassBoostEffect follow. Return<void> isStrengthSupported(isStrengthSupported_cb _hidl_cb) override; Return<Result> setStrength(uint16_t strength) override; Return<void> getStrength(getStrength_cb _hidl_cb) override; @@ -96,8 +103,10 @@ struct BassBoostEffect : public IBassBoostEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_BASSBOOSTEFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h b/audio/effect/all-versions/default/Conversions.cpp index de67d89dda..b1c0b0dc13 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h +++ b/audio/effect/all-versions/default/Conversions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,28 +14,30 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#include "Conversions.h" +#include "HidlUtils.h" #include <memory.h> #include <stdio.h> #include <common/all-versions/VersionUtils.h> -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::HidlUtils; -using ::android::hardware::audio::common::utils::mkEnumConverter; +using ::android::hardware::audio::common::utils::EnumBitfield; namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { +using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; + void effectDescriptorFromHal(const effect_descriptor_t& halDescriptor, EffectDescriptor* descriptor) { HidlUtils::uuidFromHal(halDescriptor.type, &descriptor->type); HidlUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid); - descriptor->flags = mkEnumConverter<EffectFlags>(halDescriptor.flags); + descriptor->flags = EnumBitfield<EffectFlags>(halDescriptor.flags); descriptor->cpuLoad = halDescriptor.cpuLoad; descriptor->memoryUsage = halDescriptor.memoryUsage; memcpy(descriptor->name.data(), halDescriptor.name, descriptor->name.size()); @@ -52,7 +54,7 @@ std::string uuidToString(const effect_uuid_t& halUuid) { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.h b/audio/effect/all-versions/default/Conversions.h index 3f9317f763..75aab24efe 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.h +++ b/audio/effect/all-versions/default/Conversions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,10 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_CONVERSIONS_H_ +#define ANDROID_HARDWARE_AUDIO_EFFECT_CONVERSIONS_H_ + +#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h) #include <string> @@ -24,18 +27,20 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; +using ::android::hardware::audio::effect::CPP_VERSION::EffectDescriptor; void effectDescriptorFromHal(const effect_descriptor_t& halDescriptor, EffectDescriptor* descriptor); std::string uuidToString(const effect_uuid_t& halUuid); } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_CONVERSIONS_H_ diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.impl.h b/audio/effect/all-versions/default/DownmixEffect.cpp index abef10ea09..94da70e0df 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.impl.h +++ b/audio/effect/all-versions/default/DownmixEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "Downmix_HAL" + +#include "DownmixEffect.h" #include <android/log.h> #include <system/audio_effects/effect_downmix.h> @@ -25,14 +27,14 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { DownmixEffect::DownmixEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {} DownmixEffect::~DownmixEffect() {} -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> DownmixEffect::init() { return mEffect->init(); } @@ -159,7 +161,7 @@ Return<Result> DownmixEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IDownmixEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IDownmixEffect follow. Return<Result> DownmixEffect::setType(IDownmixEffect::Type preset) { return mEffect->setParam(DOWNMIX_PARAM_TYPE, static_cast<downmix_type_t>(preset)); } @@ -172,7 +174,7 @@ Return<void> DownmixEffect::getType(getType_cb _hidl_cb) { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.h b/audio/effect/all-versions/default/DownmixEffect.h index 3e3aa78477..6d34c28dd2 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.h +++ b/audio/effect/all-versions/default/DownmixEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_DOWNMIXEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_DOWNMIXEFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IDownmixEffect.h) + +#include "Effect.h" #include <hidl/Status.h> @@ -26,21 +31,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IDownmixEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using ::android::hardware::audio::effect::CPP_VERSION::IDownmixEffect; +using ::android::hardware::audio::effect::CPP_VERSION::Result; struct DownmixEffect : public IDownmixEffect { explicit DownmixEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -84,7 +89,7 @@ struct DownmixEffect : public IDownmixEffect { const hidl_vec<uint8_t>& configData) override; Return<Result> close() override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IDownmixEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IDownmixEffect follow. Return<Result> setType(IDownmixEffect::Type preset) override; Return<void> getType(getType_cb _hidl_cb) override; @@ -95,8 +100,10 @@ struct DownmixEffect : public IDownmixEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_DOWNMIXEFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.impl.h b/audio/effect/all-versions/default/Effect.cpp index 61c9805663..84608b6065 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.impl.h +++ b/audio/effect/all-versions/default/Effect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,14 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#include <memory.h> + +#define LOG_TAG "EffectHAL" +#define ATRACE_TAG ATRACE_TAG_AUDIO + +#include "Conversions.h" +#include "Effect.h" +#include "common/all-versions/default/EffectMap.h" #include <memory.h> @@ -30,13 +37,10 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::implementation::AudioChannelBitfield; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::MessageQueueFlagBits; +using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioChannelBitfield; namespace { @@ -479,7 +483,7 @@ Result Effect::setParameterImpl(uint32_t paramSize, const void* paramData, uint3 &halParamBuffer[0]); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> Effect::init() { return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT"); } @@ -707,7 +711,7 @@ Return<Result> Effect::close() { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.h b/audio/effect/all-versions/default/Effect.h index b546e0eb32..1a2b0393ad 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.h +++ b/audio/effect/all-versions/default/Effect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_EFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_EFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffect.h) + +#include "AudioBufferManager.h" #include <atomic> #include <memory> @@ -34,28 +39,17 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::Uuid; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::implementation::AudioDeviceBitfield; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectFeature; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioDeviceBitfield; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct Effect : public IEffect { typedef MessageQueue<Result, kSynchronizedReadWrite> StatusMQ; @@ -64,7 +58,7 @@ struct Effect : public IEffect { explicit Effect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -234,8 +228,10 @@ struct Effect : public IEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_EFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h b/audio/effect/all-versions/default/EffectsFactory.cpp index b0351c968f..6283e7bc13 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h +++ b/audio/effect/all-versions/default/EffectsFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,23 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "EffectFactoryHAL" +#include "EffectsFactory.h" +#include "AcousticEchoCancelerEffect.h" +#include "AutomaticGainControlEffect.h" +#include "BassBoostEffect.h" +#include "Conversions.h" +#include "DownmixEffect.h" +#include "Effect.h" +#include "EnvironmentalReverbEffect.h" +#include "EqualizerEffect.h" +#include "HidlUtils.h" +#include "LoudnessEnhancerEffect.h" +#include "NoiseSuppressionEffect.h" +#include "PresetReverbEffect.h" +#include "VirtualizerEffect.h" +#include "VisualizerEffect.h" +#include "common/all-versions/default/EffectMap.h" #include <android/log.h> #include <media/EffectsFactoryApi.h> @@ -30,15 +46,15 @@ #include <system/audio_effects/effect_virtualizer.h> #include <system/audio_effects/effect_visualizer.h> -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::HidlUtils; - namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { +using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; + // static sp<IEffect> EffectsFactory::dispatchEffectInstanceCreation(const effect_descriptor_t& halDescriptor, effect_handle_t handle) { @@ -69,7 +85,7 @@ sp<IEffect> EffectsFactory::dispatchEffectInstanceCreation(const effect_descript return new Effect(handle); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectsFactory follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory follow. Return<void> EffectsFactory::getAllDescriptors(getAllDescriptors_cb _hidl_cb) { Result retval(Result::OK); hidl_vec<EffectDescriptor> result; @@ -184,12 +200,12 @@ Return<void> EffectsFactory::debug(const hidl_handle& fd, return Void(); } -IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* /* name */) { - return new EffectsFactory(); +IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name) { + return strcmp(name, "default") == 0 ? new EffectsFactory() : nullptr; } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.h b/audio/effect/all-versions/default/EffectsFactory.h index 526abbb89a..f0d09ec3a4 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.h +++ b/audio/effect/all-versions/default/EffectsFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,14 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_EFFECTSFACTORY_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_EFFECTSFACTORY_H + +#include <system/audio_effect.h> + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h) + +#include <hidl/MQDescriptor.h> #include <hardware/audio_effect.h> #include <system/audio_effect.h> @@ -26,27 +33,25 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::Uuid; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectsFactory; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct EffectsFactory : public IEffectsFactory { - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectsFactory follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory follow. Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb) override; Return<void> getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) override; Return<void> createEffect(const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb) override; - Return<void> debugDump(const hidl_handle& fd); //< in V2_0::IEffectsFactory only, alias of debug + Return<void> debugDump( + const hidl_handle& fd); //< in CPP_VERSION::IEffectsFactory only, alias of debug Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; private: @@ -57,8 +62,10 @@ struct EffectsFactory : public IEffectsFactory { extern "C" IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name); } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_EFFECTSFACTORY_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.impl.h b/audio/effect/all-versions/default/EnvironmentalReverbEffect.cpp index 39a4092e8c..1ade7b810b 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.impl.h +++ b/audio/effect/all-versions/default/EnvironmentalReverbEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,10 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "EnvReverb_HAL" +#include <android/log.h> + +#include "EnvironmentalReverbEffect.h" #include <android/log.h> @@ -24,7 +27,7 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { EnvironmentalReverbEffect::EnvironmentalReverbEffect(effect_handle_t handle) @@ -60,7 +63,7 @@ void EnvironmentalReverbEffect::propertiesToHal( halProperties->density = properties.density; } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> EnvironmentalReverbEffect::init() { return mEffect->init(); } @@ -190,7 +193,7 @@ Return<Result> EnvironmentalReverbEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEnvironmentalReverbEffect +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEnvironmentalReverbEffect // follow. Return<Result> EnvironmentalReverbEffect::setBypass(bool bypass) { return mEffect->setParam(REVERB_PARAM_BYPASS, bypass); @@ -297,7 +300,7 @@ Return<void> EnvironmentalReverbEffect::getAllProperties(getAllProperties_cb _hi } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.h b/audio/effect/all-versions/default/EnvironmentalReverbEffect.h index d2f8cc3a84..d06c3fc77b 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.h +++ b/audio/effect/all-versions/default/EnvironmentalReverbEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,14 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_ENVIRONMENTALREVERBEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_ENVIRONMENTALREVERBEFFECT_H + +#include <system/audio_effects/effect_environmentalreverb.h> + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEnvironmentalReverbEffect.h) + +#include "Effect.h" #include <system/audio_effects/effect_environmentalreverb.h> @@ -28,31 +35,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEnvironmentalReverbEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct EnvironmentalReverbEffect : public IEnvironmentalReverbEffect { explicit EnvironmentalReverbEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -97,7 +94,7 @@ struct EnvironmentalReverbEffect : public IEnvironmentalReverbEffect { Return<Result> close() override; // Methods from - // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEnvironmentalReverbEffect follow. + // ::android::hardware::audio::effect::CPP_VERSION::IEnvironmentalReverbEffect follow. Return<Result> setBypass(bool bypass) override; Return<void> getBypass(getBypass_cb _hidl_cb) override; Return<Result> setRoomLevel(int16_t roomLevel) override; @@ -136,8 +133,10 @@ struct EnvironmentalReverbEffect : public IEnvironmentalReverbEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_ENVIRONMENTALREVERBEFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.impl.h b/audio/effect/all-versions/default/EqualizerEffect.cpp index db6bed8d2e..f6177b79b4 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.impl.h +++ b/audio/effect/all-versions/default/EqualizerEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "Equalizer_HAL" + +#include "EqualizerEffect.h" #include <memory.h> @@ -26,7 +28,7 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { EqualizerEffect::EqualizerEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {} @@ -55,7 +57,7 @@ std::vector<uint8_t> EqualizerEffect::propertiesToHal( return halBuffer; } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> EqualizerEffect::init() { return mEffect->init(); } @@ -182,7 +184,7 @@ Return<Result> EqualizerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEqualizerEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEqualizerEffect follow. Return<void> EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb) { return mEffect->getIntegerParam(EQ_PARAM_NUM_BANDS, _hidl_cb); } @@ -285,7 +287,7 @@ Return<void> EqualizerEffect::getAllProperties(getAllProperties_cb _hidl_cb) { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.h b/audio/effect/all-versions/default/EqualizerEffect.h index de520521fa..318c0dbfd0 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.h +++ b/audio/effect/all-versions/default/EqualizerEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_EQUALIZEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_EQUALIZEREFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEqualizerEffect.h) + +#include "Effect.h" #include <vector> @@ -30,31 +35,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEqualizerEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct EqualizerEffect : public IEqualizerEffect { explicit EqualizerEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -98,7 +93,7 @@ struct EqualizerEffect : public IEqualizerEffect { const hidl_vec<uint8_t>& configData) override; Return<Result> close() override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEqualizerEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEqualizerEffect follow. Return<void> getNumBands(getNumBands_cb _hidl_cb) override; Return<void> getLevelRange(getLevelRange_cb _hidl_cb) override; Return<Result> setBandLevel(uint16_t band, int16_t level) override; @@ -124,8 +119,10 @@ struct EqualizerEffect : public IEqualizerEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_EQUALIZEREFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.impl.h b/audio/effect/all-versions/default/LoudnessEnhancerEffect.cpp index 88210e954b..6918bdf533 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.impl.h +++ b/audio/effect/all-versions/default/LoudnessEnhancerEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "LoudnessEnhancer_HAL" + +#include "LoudnessEnhancerEffect.h" #include <system/audio_effects/effect_loudnessenhancer.h> @@ -27,7 +29,7 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { LoudnessEnhancerEffect::LoudnessEnhancerEffect(effect_handle_t handle) @@ -35,7 +37,7 @@ LoudnessEnhancerEffect::LoudnessEnhancerEffect(effect_handle_t handle) LoudnessEnhancerEffect::~LoudnessEnhancerEffect() {} -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> LoudnessEnhancerEffect::init() { return mEffect->init(); } @@ -162,7 +164,7 @@ Return<Result> LoudnessEnhancerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::ILoudnessEnhancerEffect +// Methods from ::android::hardware::audio::effect::CPP_VERSION::ILoudnessEnhancerEffect // follow. Return<Result> LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb) { return mEffect->setParam(LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB, targetGainMb); @@ -182,7 +184,7 @@ Return<void> LoudnessEnhancerEffect::getTargetGain(getTargetGain_cb _hidl_cb) { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.h b/audio/effect/all-versions/default/LoudnessEnhancerEffect.h index b59b077e76..06c521ca82 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.h +++ b/audio/effect/all-versions/default/LoudnessEnhancerEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_LOUDNESSENHANCEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_LOUDNESSENHANCEREFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/ILoudnessEnhancerEffect.h) + +#include "Effect.h" #include <hidl/Status.h> @@ -26,31 +31,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::ILoudnessEnhancerEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct LoudnessEnhancerEffect : public ILoudnessEnhancerEffect { explicit LoudnessEnhancerEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -94,7 +89,7 @@ struct LoudnessEnhancerEffect : public ILoudnessEnhancerEffect { const hidl_vec<uint8_t>& configData) override; Return<Result> close() override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::ILoudnessEnhancerEffect + // Methods from ::android::hardware::audio::effect::CPP_VERSION::ILoudnessEnhancerEffect // follow. Return<Result> setTargetGain(int32_t targetGainMb) override; Return<void> getTargetGain(getTargetGain_cb _hidl_cb) override; @@ -106,8 +101,10 @@ struct LoudnessEnhancerEffect : public ILoudnessEnhancerEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_LOUDNESSENHANCEREFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.impl.h b/audio/effect/all-versions/default/NoiseSuppressionEffect.cpp index f32399c51c..4756719661 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.impl.h +++ b/audio/effect/all-versions/default/NoiseSuppressionEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "NS_Effect_HAL" + +#include "NoiseSuppressionEffect.h" #include <android/log.h> @@ -24,7 +26,7 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { NoiseSuppressionEffect::NoiseSuppressionEffect(effect_handle_t handle) @@ -44,7 +46,7 @@ void NoiseSuppressionEffect::propertiesToHal( halProperties->type = static_cast<uint32_t>(properties.type); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> NoiseSuppressionEffect::init() { return mEffect->init(); } @@ -171,7 +173,7 @@ Return<Result> NoiseSuppressionEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::INoiseSuppressionEffect +// Methods from ::android::hardware::audio::effect::CPP_VERSION::INoiseSuppressionEffect // follow. Return<Result> NoiseSuppressionEffect::setSuppressionLevel(INoiseSuppressionEffect::Level level) { return mEffect->setParam(NS_PARAM_LEVEL, static_cast<int32_t>(level)); @@ -212,7 +214,7 @@ Return<void> NoiseSuppressionEffect::getAllProperties(getAllProperties_cb _hidl_ } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.h b/audio/effect/all-versions/default/NoiseSuppressionEffect.h index af1635b717..f31ba3b923 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.h +++ b/audio/effect/all-versions/default/NoiseSuppressionEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_NOISESUPPRESSIONEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_NOISESUPPRESSIONEFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/INoiseSuppressionEffect.h) + +#include "Effect.h" #include <system/audio_effects/effect_ns.h> @@ -28,31 +33,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::INoiseSuppressionEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct NoiseSuppressionEffect : public INoiseSuppressionEffect { explicit NoiseSuppressionEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -96,7 +91,7 @@ struct NoiseSuppressionEffect : public INoiseSuppressionEffect { const hidl_vec<uint8_t>& configData) override; Return<Result> close() override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::INoiseSuppressionEffect + // Methods from ::android::hardware::audio::effect::CPP_VERSION::INoiseSuppressionEffect // follow. Return<Result> setSuppressionLevel(INoiseSuppressionEffect::Level level) override; Return<void> getSuppressionLevel(getSuppressionLevel_cb _hidl_cb) override; @@ -118,8 +113,10 @@ struct NoiseSuppressionEffect : public INoiseSuppressionEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_NOISESUPPRESSIONEFFECT_H diff --git a/audio/core/2.0/default/OWNERS b/audio/effect/all-versions/default/OWNERS index 6fdc97ca29..6fdc97ca29 100644 --- a/audio/core/2.0/default/OWNERS +++ b/audio/effect/all-versions/default/OWNERS diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.impl.h b/audio/effect/all-versions/default/PresetReverbEffect.cpp index eab68fb703..97723f5fbb 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.impl.h +++ b/audio/effect/all-versions/default/PresetReverbEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "PresetReverb_HAL" + +#include "PresetReverbEffect.h" #include <android/log.h> #include <system/audio_effects/effect_presetreverb.h> @@ -25,14 +27,14 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { PresetReverbEffect::PresetReverbEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {} PresetReverbEffect::~PresetReverbEffect() {} -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> PresetReverbEffect::init() { return mEffect->init(); } @@ -159,7 +161,7 @@ Return<Result> PresetReverbEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IPresetReverbEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IPresetReverbEffect follow. Return<Result> PresetReverbEffect::setPreset(IPresetReverbEffect::Preset preset) { return mEffect->setParam(REVERB_PARAM_PRESET, static_cast<t_reverb_presets>(preset)); } @@ -172,7 +174,7 @@ Return<void> PresetReverbEffect::getPreset(getPreset_cb _hidl_cb) { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.h b/audio/effect/all-versions/default/PresetReverbEffect.h index 1a91ab49b2..8971976825 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.h +++ b/audio/effect/all-versions/default/PresetReverbEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_PRESETREVERBEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_PRESETREVERBEFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IPresetReverbEffect.h) + +#include "Effect.h" #include <hidl/Status.h> @@ -26,31 +31,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IPresetReverbEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct PresetReverbEffect : public IPresetReverbEffect { explicit PresetReverbEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -94,7 +89,7 @@ struct PresetReverbEffect : public IPresetReverbEffect { const hidl_vec<uint8_t>& configData) override; Return<Result> close() override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IPresetReverbEffect + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IPresetReverbEffect // follow. Return<Result> setPreset(IPresetReverbEffect::Preset preset) override; Return<void> getPreset(getPreset_cb _hidl_cb) override; @@ -106,8 +101,10 @@ struct PresetReverbEffect : public IPresetReverbEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_PRESETREVERBEFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.impl.h b/audio/effect/all-versions/default/VirtualizerEffect.cpp index 23b09a89dd..4d597c76e8 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.impl.h +++ b/audio/effect/all-versions/default/VirtualizerEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "Virtualizer_HAL" + +#include "VirtualizerEffect.h" #include <memory.h> @@ -27,7 +29,7 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { VirtualizerEffect::VirtualizerEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {} @@ -44,7 +46,7 @@ void VirtualizerEffect::speakerAnglesFromHal(const int32_t* halAngles, uint32_t } } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> VirtualizerEffect::init() { return mEffect->init(); } @@ -171,7 +173,7 @@ Return<Result> VirtualizerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVirtualizerEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IVirtualizerEffect follow. Return<bool> VirtualizerEffect::isStrengthSupported() { bool halSupported = false; mEffect->getParam(VIRTUALIZER_PARAM_STRENGTH_SUPPORTED, halSupported); @@ -224,7 +226,7 @@ Return<void> VirtualizerEffect::getVirtualizationMode(getVirtualizationMode_cb _ } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.h b/audio/effect/all-versions/default/VirtualizerEffect.h index c0d5a0034d..e7302f9f8b 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.h +++ b/audio/effect/all-versions/default/VirtualizerEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_VIRTUALIZEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_VIRTUALIZEREFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IVirtualizerEffect.h) + +#include "Effect.h" #include <hidl/Status.h> @@ -26,33 +31,22 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::implementation::AudioChannelBitfield; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVirtualizerEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioChannelBitfield; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct VirtualizerEffect : public IVirtualizerEffect { explicit VirtualizerEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -96,7 +90,7 @@ struct VirtualizerEffect : public IVirtualizerEffect { const hidl_vec<uint8_t>& configData) override; Return<Result> close() override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVirtualizerEffect + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IVirtualizerEffect // follow. Return<bool> isStrengthSupported() override; Return<Result> setStrength(uint16_t strength) override; @@ -116,8 +110,10 @@ struct VirtualizerEffect : public IVirtualizerEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_VIRTUALIZEREFFECT_H diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.impl.h b/audio/effect/all-versions/default/VisualizerEffect.cpp index 9f2195b5cb..77bf46bcd3 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.impl.h +++ b/audio/effect/all-versions/default/VisualizerEffect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#define LOG_TAG "Visualizer_HAL" + +#include "VisualizerEffect.h" #include <android/log.h> #include <system/audio_effects/effect_visualizer.h> @@ -25,7 +27,7 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { VisualizerEffect::VisualizerEffect(effect_handle_t handle) @@ -33,7 +35,7 @@ VisualizerEffect::VisualizerEffect(effect_handle_t handle) VisualizerEffect::~VisualizerEffect() {} -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> VisualizerEffect::init() { return mEffect->init(); } @@ -160,7 +162,7 @@ Return<Result> VisualizerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVisualizerEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IVisualizerEffect follow. Return<Result> VisualizerEffect::setCaptureSize(uint16_t captureSize) { Result retval = mEffect->setParam(VISUALIZER_PARAM_CAPTURE_SIZE, captureSize); if (retval == Result::OK) { @@ -247,7 +249,7 @@ Return<void> VisualizerEffect::measure(measure_cb _hidl_cb) { } } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.h b/audio/effect/all-versions/default/VisualizerEffect.h index 114d3b7ae5..42c77a2103 100644 --- a/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.h +++ b/audio/effect/all-versions/default/VisualizerEffect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -14,7 +14,12 @@ * limitations under the License. */ -#include <common/all-versions/IncludeGuard.h> +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_VISUALIZEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_VISUALIZEREFFECT_H + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IVisualizerEffect.h) + +#include "Effect.h" #include <hidl/Status.h> @@ -26,31 +31,21 @@ namespace android { namespace hardware { namespace audio { namespace effect { -namespace AUDIO_HAL_VERSION { +namespace CPP_VERSION { namespace implementation { -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode; -using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVisualizerEffect; -using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result; +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; struct VisualizerEffect : public IVisualizerEffect { explicit VisualizerEffect(effect_handle_t handle); - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return<Result> init() override; Return<Result> setConfig( const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider, @@ -94,7 +89,7 @@ struct VisualizerEffect : public IVisualizerEffect { const hidl_vec<uint8_t>& configData) override; Return<Result> close() override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVisualizerEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IVisualizerEffect follow. Return<Result> setCaptureSize(uint16_t captureSize) override; Return<void> getCaptureSize(getCaptureSize_cb _hidl_cb) override; Return<Result> setScalingMode(IVisualizerEffect::ScalingMode scalingMode) override; @@ -115,8 +110,10 @@ struct VisualizerEffect : public IVisualizerEffect { }; } // namespace implementation -} // namespace AUDIO_HAL_VERSION +} // namespace CPP_VERSION } // namespace effect } // namespace audio } // namespace hardware } // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_VISUALIZEREFFECT_H diff --git a/audio/effect/2.0/vts/OWNERS b/audio/effect/all-versions/vts/OWNERS index 8711a9ff6a..0ea4666443 100644 --- a/audio/effect/2.0/vts/OWNERS +++ b/audio/effect/all-versions/vts/OWNERS @@ -2,4 +2,4 @@ elaurent@google.com krocard@google.com mnaganov@google.com yim@google.com -zhuoyao@google.com
\ No newline at end of file +zhuoyao@google.com diff --git a/audio/effect/4.0/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp index 886f92d36e..de6cad9ad0 100644 --- a/audio/effect/4.0/vts/functional/Android.bp +++ b/audio/effect/all-versions/vts/functional/Android.bp @@ -14,17 +14,15 @@ // limitations under the License. // -cc_test { - name: "VtsHalAudioEffectV4_0TargetTest", +cc_defaults { + name: "VtsHalAudioEffectTargetTest_default", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalAudioEffectV4_0TargetTest.cpp", + "VtsHalAudioEffectTargetTest.cpp", "ValidateAudioEffectsConfiguration.cpp" ], static_libs: [ "android.hardware.audio.common.test.utility", - "android.hardware.audio.common@4.0", - "android.hardware.audio.effect@4.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "libeffectsconfig", @@ -38,3 +36,46 @@ cc_test { ], test_suites: ["general-tests"], } + +cc_test { + name: "VtsHalAudioEffectV2_0TargetTest", + defaults: ["VtsHalAudioEffectTargetTest_default"], + static_libs: [ + "android.hardware.audio.common@2.0", + "android.hardware.audio.effect@2.0", + ], + cflags: [ + "-DMAJOR_VERSION=2", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_test { + name: "VtsHalAudioEffectV4_0TargetTest", + defaults: ["VtsHalAudioEffectTargetTest_default"], + static_libs: [ + "android.hardware.audio.common@4.0", + "android.hardware.audio.effect@4.0", + ], + cflags: [ + "-DMAJOR_VERSION=4", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + +cc_test { + name: "VtsHalAudioEffectV5_0TargetTest", + defaults: ["VtsHalAudioEffectTargetTest_default"], + static_libs: [ + "android.hardware.audio.common@5.0", + "android.hardware.audio.effect@5.0", + ], + cflags: [ + "-DMAJOR_VERSION=5", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ] +} + diff --git a/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp index bf080d3edc..f9e4aa30eb 100644 --- a/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp +++ b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -21,12 +21,22 @@ #include "utility/ValidateXml.h" +// Stringify the argument. +#define QUOTE(x) #x +#define STRINGIFY(x) QUOTE(x) + TEST(CheckConfig, audioEffectsConfigurationValidation) { RecordProperty("description", "Verify that the effects configuration file is valid according to the schema"); using namespace android::effectsConfig; std::vector<const char*> locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS)); - EXPECT_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations, - "/data/local/tmp/audio_effects_conf_V2_0.xsd"); + const char* xsd = "/data/local/tmp/audio_effects_conf_" STRINGIFY(CPP_VERSION) ".xsd"; +#if MAJOR_VERSION == 2 + // In V2, audio effect XML is not required. .conf is still allowed though deprecated + EXPECT_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations, xsd); +#elif MAJOR_VERSION >= 4 + // Starting with V4, audio effect XML is required + EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations, xsd); +#endif } diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp new file mode 100644 index 0000000000..c4c7f7ccc4 --- /dev/null +++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp @@ -0,0 +1,818 @@ +/* + * 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. + */ + +#define LOG_TAG "AudioEffectHidlHalTest" +#include <android-base/logging.h> +#include <system/audio.h> + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffect.h) +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h) +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEqualizerEffect.h) +#include PATH(android/hardware/audio/effect/FILE_VERSION/ILoudnessEnhancerEffect.h) +#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h) +#include <android/hidl/allocator/1.0/IAllocator.h> +#include <android/hidl/memory/1.0/IMemory.h> + +#include <common/all-versions/VersionUtils.h> + +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> + +using ::android::sp; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::audio::common::utils::mkEnumBitfield; +using ::android::hidl::allocator::V1_0::IAllocator; +using ::android::hidl::memory::V1_0::IMemory; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) +#endif + +// Test environment for Audio Effects Factory HIDL HAL. +class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static AudioEffectsFactoryHidlEnvironment* Instance() { + static AudioEffectsFactoryHidlEnvironment* instance = + new AudioEffectsFactoryHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<IEffectsFactory>(); } +}; + +// The main test class for Audio Effects Factory HIDL HAL. +class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + void SetUp() override { + effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>( + AudioEffectsFactoryHidlEnvironment::Instance()->getServiceName<IEffectsFactory>()); + ASSERT_NE(effectsFactory, nullptr); + } + + void TearDown() override { effectsFactory.clear(); } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp<IEffectsFactory> effectsFactory; +}; + +TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { + description("Verify that EnumerateEffects returns at least one effect"); + Result retval = Result::NOT_INITIALIZED; + size_t effectCount = 0; + Return<void> ret = + effectsFactory->getAllDescriptors([&](Result r, const hidl_vec<EffectDescriptor>& result) { + retval = r; + effectCount = result.size(); + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_GT(effectCount, 0u); +} + +TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) { + description("Verify that an effect can be created via CreateEffect"); + bool gotEffect = false; + Uuid effectUuid; + Return<void> ret = + effectsFactory->getAllDescriptors([&](Result r, const hidl_vec<EffectDescriptor>& result) { + if (r == Result::OK && result.size() > 0) { + gotEffect = true; + effectUuid = result[0].uuid; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(gotEffect); + Result retval = Result::NOT_INITIALIZED; + sp<IEffect> effect; + ret = effectsFactory->createEffect( + effectUuid, 1 /*session*/, 1 /*ioHandle*/, + [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) { + retval = r; + if (r == Result::OK) { + effect = result; + } + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_NE(nullptr, effect.get()); +} + +TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) { + description( + "Verify that effects factory can provide an effect descriptor via " + "GetDescriptor"); + hidl_vec<EffectDescriptor> allDescriptors; + Return<void> ret = + effectsFactory->getAllDescriptors([&](Result r, const hidl_vec<EffectDescriptor>& result) { + if (r == Result::OK) { + allDescriptors = result; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_GT(allDescriptors.size(), 0u); + for (size_t i = 0; i < allDescriptors.size(); ++i) { + ret = effectsFactory->getDescriptor(allDescriptors[i].uuid, + [&](Result r, const EffectDescriptor& result) { + EXPECT_EQ(r, Result::OK); + EXPECT_EQ(result, allDescriptors[i]); + }); + } + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) { + description("Verify that debugDump doesn't crash on invalid arguments"); +#if MAJOR_VERSION == 2 + Return<void> ret = effectsFactory->debugDump(hidl_handle()); +#elif MAJOR_VERSION >= 4 + Return<void> ret = effectsFactory->debug(hidl_handle(), {}); +#endif + ASSERT_TRUE(ret.isOk()); +} + +// Equalizer effect is required by CDD, but only the type is fixed. +// This is the same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java. +static const Uuid EQUALIZER_EFFECT_TYPE = { + 0x0bed4300, 0xddd6, 0x11db, 0x8f34, + std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}}; +// Loudness Enhancer effect is required by CDD, but only the type is fixed. +// This is the same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java. +static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = { + 0xfe3199be, 0xaed0, 0x413f, 0x87bb, + std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}}; + +// The main test class for Audio Effect HIDL HAL. +class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + void SetUp() override { + effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>(); + ASSERT_NE(nullptr, effectsFactory.get()); + + findAndCreateEffect(getEffectType()); + ASSERT_NE(nullptr, effect.get()); + + Return<Result> ret = effect->init(); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, ret); + } + + void TearDown() override { + effect.clear(); + effectsFactory.clear(); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; } + + void findAndCreateEffect(const Uuid& type); + void findEffectInstance(const Uuid& type, Uuid* uuid); + void getChannelCount(uint32_t* channelCount); + + sp<IEffectsFactory> effectsFactory; + sp<IEffect> effect; +}; + +void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) { + Uuid effectUuid; + findEffectInstance(type, &effectUuid); + Return<void> ret = effectsFactory->createEffect( + effectUuid, 1 /*session*/, 1 /*ioHandle*/, + [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) { + if (r == Result::OK) { + effect = result; + } + }); + ASSERT_TRUE(ret.isOk()); +} + +void AudioEffectHidlTest::findEffectInstance(const Uuid& type, Uuid* uuid) { + bool effectFound = false; + Return<void> ret = + effectsFactory->getAllDescriptors([&](Result r, const hidl_vec<EffectDescriptor>& result) { + if (r == Result::OK) { + for (const auto& desc : result) { + if (desc.type == type) { + effectFound = true; + *uuid = desc.uuid; + break; + } + } + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(effectFound); +} + +void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) { + Result retval; + EffectConfig currentConfig; + Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { + retval = r; + if (r == Result::OK) { + currentConfig = conf; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); + ASSERT_TRUE(audio_channel_mask_is_valid( + static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels))); + *channelCount = audio_channel_count_from_out_mask( + static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)); +} + +TEST_F(AudioEffectHidlTest, Close) { + description("Verify that an effect can be closed"); + Return<Result> ret = effect->close(); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, GetDescriptor) { + description("Verify that an effect can return its own descriptor via GetDescriptor"); + Result retval = Result::NOT_INITIALIZED; + Uuid actualType; + Return<void> ret = effect->getDescriptor([&](Result r, const EffectDescriptor& desc) { + retval = r; + if (r == Result::OK) { + actualType = desc.type; + } + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(getEffectType(), actualType); +} + +TEST_F(AudioEffectHidlTest, GetSetConfig) { + description( + "Verify that it is possible to manipulate effect config via Get / " + "SetConfig"); + Result retval = Result::NOT_INITIALIZED; + EffectConfig currentConfig; + Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { + retval = r; + if (r == Result::OK) { + currentConfig = conf; + } + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + Return<Result> ret2 = effect->setConfig(currentConfig, nullptr, nullptr); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, ret2); +} + +TEST_F(AudioEffectHidlTest, GetConfigReverse) { + description("Verify that GetConfigReverse does not crash"); + Return<void> ret = effect->getConfigReverse([&](Result, const EffectConfig&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { + description("Verify that GetSupportedAuxChannelsConfigs does not crash"); + Return<void> ret = effect->getSupportedAuxChannelsConfigs( + 0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) { + description("Verify that GetAuxChannelsConfig does not crash"); + Return<void> ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) { + description("Verify that SetAuxChannelsConfig does not crash"); + Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig()); + EXPECT_TRUE(ret.isOk()); +} + +// Not generated automatically because AudioBuffer contains +// instances of hidl_memory which can't be compared properly +// in general case due to presence of handles. +// +// However, in this particular case, handles must not present +// thus comparison is possible. +// +// operator== must be defined in the same namespace as the structures. +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace CPP_VERSION { +inline bool operator==(const AudioBuffer& lhs, const AudioBuffer& rhs) { + return lhs.id == rhs.id && lhs.frameCount == rhs.frameCount && lhs.data.handle() == nullptr && + rhs.data.handle() == nullptr; +} + +inline bool operator==(const EffectBufferConfig& lhs, const EffectBufferConfig& rhs) { + return lhs.buffer == rhs.buffer && lhs.samplingRateHz == rhs.samplingRateHz && + lhs.channels == rhs.channels && lhs.format == rhs.format && + lhs.accessMode == rhs.accessMode && lhs.mask == rhs.mask; +} + +inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) { + return lhs.inputCfg == rhs.inputCfg && lhs.outputCfg == rhs.outputCfg; +} +} // namespace CPP_VERSION +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +TEST_F(AudioEffectHidlTest, Reset) { + description("Verify that Reset preserves effect configuration"); + Result retval = Result::NOT_INITIALIZED; + EffectConfig originalConfig; + Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { + retval = r; + if (r == Result::OK) { + originalConfig = conf; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); + Return<Result> ret2 = effect->reset(); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, ret2); + EffectConfig configAfterReset; + ret = effect->getConfig([&](Result r, const EffectConfig& conf) { + retval = r; + if (r == Result::OK) { + configAfterReset = conf; + } + }); + EXPECT_EQ(originalConfig, configAfterReset); +} + +TEST_F(AudioEffectHidlTest, DisableEnableDisable) { + description("Verify Disable -> Enable -> Disable sequence for an effect"); + Return<Result> ret = effect->disable(); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::INVALID_ARGUMENTS, ret); + ret = effect->enable(); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + ret = effect->disable(); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, SetDevice) { + description("Verify that SetDevice works for an output chain effect"); + Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER)); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, SetAndGetVolume) { + description("Verify that SetAndGetVolume method works for an effect"); + uint32_t channelCount; + getChannelCount(&channelCount); + hidl_vec<uint32_t> volumes; + volumes.resize(channelCount); + for (uint32_t i = 0; i < channelCount; ++i) { + volumes[i] = 0; + } + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = + effect->setAndGetVolume(volumes, [&](Result r, const hidl_vec<uint32_t>&) { retval = r; }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); +} + +TEST_F(AudioEffectHidlTest, VolumeChangeNotification) { + description("Verify that effect accepts VolumeChangeNotification"); + uint32_t channelCount; + getChannelCount(&channelCount); + hidl_vec<uint32_t> volumes; + volumes.resize(channelCount); + for (uint32_t i = 0; i < channelCount; ++i) { + volumes[i] = 0; + } + Return<Result> ret = effect->volumeChangeNotification(volumes); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, SetAudioMode) { + description("Verify that SetAudioMode works for an effect"); + Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, SetConfigReverse) { + description("Verify that SetConfigReverse does not crash"); + Return<Result> ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetInputDevice) { + description("Verify that SetInputDevice does not crash"); + Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC)); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetAudioSource) { + description("Verify that SetAudioSource does not crash"); + Return<Result> ret = effect->setAudioSource(AudioSource::MIC); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, Offload) { + description("Verify that calling Offload method does not crash"); + EffectOffloadParameter offloadParam; + offloadParam.isOffload = false; + offloadParam.ioHandle = static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE); + Return<Result> ret = effect->offload(offloadParam); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, PrepareForProcessing) { + description("Verify that PrepareForProcessing method works for an effect"); + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = effect->prepareForProcessing( + [&](Result r, const MQDescriptorSync<Result>&) { retval = r; }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); +} + +TEST_F(AudioEffectHidlTest, SetProcessBuffers) { + description("Verify that SetProcessBuffers works for an effect"); + sp<IAllocator> ashmem = IAllocator::getService("ashmem"); + ASSERT_NE(nullptr, ashmem.get()); + bool success = false; + AudioBuffer buffer; + Return<void> ret = ashmem->allocate(1024, [&](bool s, const hidl_memory& memory) { + success = s; + if (s) { + buffer.data = memory; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(success); + Return<Result> ret2 = effect->setProcessBuffers(buffer, buffer); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, ret2); +} + +TEST_F(AudioEffectHidlTest, Command) { + description("Verify that Command does not crash"); + Return<void> ret = + effect->command(0, hidl_vec<uint8_t>(), 0, [&](int32_t, const hidl_vec<uint8_t>&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetParameter) { + description("Verify that SetParameter does not crash"); + Return<Result> ret = effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>()); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetParameter) { + description("Verify that GetParameter does not crash"); + Return<void> ret = + effect->getParameter(hidl_vec<uint8_t>(), 0, [&](Result, const hidl_vec<uint8_t>&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) { + description("Verify that GetSupportedConfigsForFeature does not crash"); + Return<void> ret = effect->getSupportedConfigsForFeature( + 0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) { + description("Verify that GetCurrentConfigForFeature does not crash"); + Return<void> ret = + effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec<uint8_t>&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) { + description("Verify that SetCurrentConfigForFeature does not crash"); + Return<Result> ret = effect->setCurrentConfigForFeature(0, hidl_vec<uint8_t>()); + EXPECT_TRUE(ret.isOk()); +} + +// The main test class for Equalizer Audio Effect HIDL HAL. +class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest { + public: + void SetUp() override { + AudioEffectHidlTest::SetUp(); + equalizer = IEqualizerEffect::castFrom(effect); + ASSERT_NE(nullptr, equalizer.get()); + } + + protected: + Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; } + void getNumBands(uint16_t* numBands); + void getLevelRange(int16_t* minLevel, int16_t* maxLevel); + void getBandFrequencyRange(uint16_t band, uint32_t* minFreq, uint32_t* centerFreq, + uint32_t* maxFreq); + void getPresetCount(size_t* count); + + sp<IEqualizerEffect> equalizer; +}; + +void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) { + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = equalizer->getNumBands([&](Result r, uint16_t b) { + retval = r; + if (retval == Result::OK) { + *numBands = b; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); +} + +void EqualizerAudioEffectHidlTest::getLevelRange(int16_t* minLevel, int16_t* maxLevel) { + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = equalizer->getLevelRange([&](Result r, int16_t min, int16_t max) { + retval = r; + if (retval == Result::OK) { + *minLevel = min; + *maxLevel = max; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); +} + +void EqualizerAudioEffectHidlTest::getBandFrequencyRange(uint16_t band, uint32_t* minFreq, + uint32_t* centerFreq, uint32_t* maxFreq) { + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = + equalizer->getBandFrequencyRange(band, [&](Result r, uint32_t min, uint32_t max) { + retval = r; + if (retval == Result::OK) { + *minFreq = min; + *maxFreq = max; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); + ret = equalizer->getBandCenterFrequency(band, [&](Result r, uint32_t center) { + retval = r; + if (retval == Result::OK) { + *centerFreq = center; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); +} + +void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) { + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = equalizer->getPresetNames([&](Result r, const hidl_vec<hidl_string>& names) { + retval = r; + if (retval == Result::OK) { + *count = names.size(); + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); +} + +TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) { + description("Verify that Equalizer effect reports at least one band"); + uint16_t numBands = 0; + getNumBands(&numBands); + EXPECT_GT(numBands, 0); +} + +TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) { + description("Verify that Equalizer effect reports adequate band level range"); + int16_t minLevel = 0x7fff, maxLevel = 0; + getLevelRange(&minLevel, &maxLevel); + EXPECT_GT(maxLevel, minLevel); +} + +TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) { + description("Verify that manipulating band levels works for Equalizer effect"); + uint16_t numBands = 0; + getNumBands(&numBands); + ASSERT_GT(numBands, 0); + int16_t levels[3]{0x7fff, 0, 0}; + getLevelRange(&levels[0], &levels[2]); + ASSERT_GT(levels[2], levels[0]); + levels[1] = (levels[2] + levels[0]) / 2; + for (uint16_t i = 0; i < numBands; ++i) { + for (size_t j = 0; j < ARRAY_SIZE(levels); ++j) { + Return<Result> ret = equalizer->setBandLevel(i, levels[j]); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Result retval = Result::NOT_INITIALIZED; + int16_t actualLevel; + Return<void> ret2 = equalizer->getBandLevel(i, [&](Result r, int16_t l) { + retval = r; + if (retval == Result::OK) { + actualLevel = l; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(levels[j], actualLevel); + } + } +} + +TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { + description("Verify that Equalizer effect reports adequate band frequency range"); + uint16_t numBands = 0; + getNumBands(&numBands); + ASSERT_GT(numBands, 0); + for (uint16_t i = 0; i < numBands; ++i) { + uint32_t minFreq = 0xffffffff, centerFreq = 0xffffffff, maxFreq = 0xffffffff; + getBandFrequencyRange(i, &minFreq, ¢erFreq, &maxFreq); + // Note: NXP legacy implementation reports "1" as upper bound for last band, + // so this check fails. + EXPECT_GE(maxFreq, centerFreq); + EXPECT_GE(centerFreq, minFreq); + } +} + +TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) { + description("Verify that Equalizer effect supports GetBandForFrequency correctly"); + uint16_t numBands = 0; + getNumBands(&numBands); + ASSERT_GT(numBands, 0); + for (uint16_t i = 0; i < numBands; ++i) { + uint32_t freqs[3]{0, 0, 0}; + getBandFrequencyRange(i, &freqs[0], &freqs[1], &freqs[2]); + // NXP legacy implementation reports "1" as upper bound for last band, some + // of the checks fail. + for (size_t j = 0; j < ARRAY_SIZE(freqs); ++j) { + if (j == 0) { + freqs[j]++; + } // Min frequency is an open interval. + Result retval = Result::NOT_INITIALIZED; + uint16_t actualBand = numBands + 1; + Return<void> ret = equalizer->getBandForFrequency(freqs[j], [&](Result r, uint16_t b) { + retval = r; + if (retval == Result::OK) { + actualBand = b; + } + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j]; + } + } +} + +TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) { + description("Verify that Equalizer effect reports at least one preset"); + size_t presetCount; + getPresetCount(&presetCount); + EXPECT_GT(presetCount, 0u); +} + +TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { + description("Verify that manipulating the current preset for Equalizer effect"); + size_t presetCount; + getPresetCount(&presetCount); + ASSERT_GT(presetCount, 0u); + for (uint16_t i = 0; i < presetCount; ++i) { + Return<Result> ret = equalizer->setCurrentPreset(i); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Result retval = Result::NOT_INITIALIZED; + uint16_t actualPreset = 0xffff; + Return<void> ret2 = equalizer->getCurrentPreset([&](Result r, uint16_t p) { + retval = r; + if (retval == Result::OK) { + actualPreset = p; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(i, actualPreset); + } +} + +TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) { + description( + "Verify that setting band levels and presets works via Get / " + "SetAllProperties for Equalizer effect"); + using AllProperties = + ::android::hardware::audio::effect::CPP_VERSION::IEqualizerEffect::AllProperties; + uint16_t numBands = 0; + getNumBands(&numBands); + ASSERT_GT(numBands, 0); + AllProperties props; + props.bandLevels.resize(numBands); + for (size_t i = 0; i < numBands; ++i) { + props.bandLevels[i] = 0; + } + + AllProperties actualProps; + Result retval = Result::NOT_INITIALIZED; + + // Verify setting of the band levels via properties. + props.curPreset = -1; + Return<Result> ret = equalizer->setAllProperties(props); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Return<void> ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) { + retval = r; + if (retval == Result::OK) { + actualProps = p; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(props.bandLevels, actualProps.bandLevels); + + // Verify setting of the current preset via properties. + props.curPreset = 0; // Assuming there is at least one preset. + ret = equalizer->setAllProperties(props); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) { + retval = r; + if (retval == Result::OK) { + actualProps = p; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(props.curPreset, actualProps.curPreset); +} + +// The main test class for Equalizer Audio Effect HIDL HAL. +class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest { + public: + void SetUp() override { + AudioEffectHidlTest::SetUp(); + enhancer = ILoudnessEnhancerEffect::castFrom(effect); + ASSERT_NE(nullptr, enhancer.get()); + } + + protected: + Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; } + + sp<ILoudnessEnhancerEffect> enhancer; +}; + +TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { + description( + "Verify that manipulating the target gain works for Loudness Enhancer " + "effect"); + const int32_t gain = 100; + Return<Result> ret = enhancer->setTargetGain(gain); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + int32_t actualGain = 0; + Result retval; + Return<void> ret2 = enhancer->getTargetGain([&](Result r, int32_t g) { + retval = r; + if (retval == Result::OK) { + actualGain = g; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(gain, actualGain); +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + AudioEffectsFactoryHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/automotive/OWNERS b/automotive/OWNERS new file mode 100644 index 0000000000..4a944944f6 --- /dev/null +++ b/automotive/OWNERS @@ -0,0 +1,3 @@ +randolphs@google.com +pirozzoj@google.com +twasilczyk@google.com diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp index 6af774e467..f64028c9ef 100644 --- a/automotive/vehicle/2.0/Android.bp +++ b/automotive/vehicle/2.0/Android.bp @@ -30,7 +30,6 @@ hidl_interface { "StatusCode", "SubscribeFlags", "SubscribeOptions", - "VehicleApPowerBootupReason", "VehicleApPowerStateConfigFlag", "VehicleApPowerStateReport", "VehicleApPowerStateReq", diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index 62a39df804..a11d45208e 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -58,12 +58,14 @@ cc_library_static { vendor: true, defaults: ["vhal_v2_0_defaults"], srcs: [ + "impl/vhal_v2_0/CommConn.cpp", "impl/vhal_v2_0/EmulatedVehicleHal.cpp", "impl/vhal_v2_0/VehicleEmulator.cpp", "impl/vhal_v2_0/PipeComm.cpp", "impl/vhal_v2_0/SocketComm.cpp", "impl/vhal_v2_0/LinearFakeValueGenerator.cpp", "impl/vhal_v2_0/JsonFakeValueGenerator.cpp", + "impl/vhal_v2_0/GeneratorHub.cpp", ], local_include_dirs: ["common/include/vhal_v2_0"], export_include_dirs: ["impl"], diff --git a/automotive/vehicle/2.0/default/OWNERS b/automotive/vehicle/2.0/default/OWNERS deleted file mode 100644 index d5d9d4c26a..0000000000 --- a/automotive/vehicle/2.0/default/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -egranata@google.com -pavelm@google.com -spaik@google.com diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp new file mode 100644 index 0000000000..bf1de8165a --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#define LOG_TAG "CommConn" + +#include <thread> + +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> +#include <log/log.h> + +#include "CommConn.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +void CommConn::start() { + mReadThread = std::make_unique<std::thread>(std::bind(&CommConn::readThread, this)); +} + +void CommConn::stop() { + if (mReadThread->joinable()) { + mReadThread->join(); + } +} + +void CommConn::sendMessage(emulator::EmulatorMessage const& msg) { + int numBytes = msg.ByteSize(); + std::vector<uint8_t> buffer(static_cast<size_t>(numBytes)); + if (!msg.SerializeToArray(buffer.data(), numBytes)) { + ALOGE("%s: SerializeToString failed!", __func__); + return; + } + + write(buffer); +} + +void CommConn::readThread() { + std::vector<uint8_t> buffer; + while (isOpen()) { + buffer = read(); + if (buffer.size() == 0) { + ALOGI("%s: Read returned empty message, exiting read loop.", __func__); + break; + } + + emulator::EmulatorMessage rxMsg; + if (rxMsg.ParseFromArray(buffer.data(), static_cast<int32_t>(buffer.size()))) { + emulator::EmulatorMessage respMsg; + mMessageProcessor->processMessage(rxMsg, respMsg); + + sendMessage(respMsg); + } + } +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h index 6832ad3398..87b0dfc17d 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h @@ -17,9 +17,13 @@ #ifndef android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_ #define android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_ +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> #include <string> +#include <thread> #include <vector> +#include "VehicleHalProto.pb.h" + namespace android { namespace hardware { namespace automotive { @@ -29,32 +33,45 @@ namespace V2_0 { namespace impl { /** - * This is the communications base class. It defines the interface used in DefaultVehicleHal to - * send and receive data to and from the emulator. + * MessageProcess is an interface implemented by VehicleEmulator to process messages received + * over a CommConn. */ -class CommBase { -public: - virtual ~CommBase() = default; +class MessageProcessor { + public: + virtual ~MessageProcessor() = default; /** - * Closes a connection if it is open. + * Process a single message received over a CommConn. Populate the given respMsg with the reply + * message we should send. */ - virtual void stop() {} + virtual void processMessage(emulator::EmulatorMessage const& rxMsg, + emulator::EmulatorMessage& respMsg) = 0; +}; + +/** + * This is the interface that both PipeComm and SocketComm use to represent a connection. The + * connection will listen for commands on a separate 'read' thread. + */ +class CommConn { + public: + CommConn(MessageProcessor* messageProcessor) : mMessageProcessor(messageProcessor) {} + + virtual ~CommConn() {} /** - * Creates a connection to the other side. - * - * @return int Returns fd or socket number if connection is successful. - * Otherwise, returns -1 if no connection is availble. + * Start the read thread reading messages from this connection. */ - virtual int connect() { return 0; } + virtual void start(); /** - * Opens the communications channel. - * - * @return int Returns 0 if channel is opened, else -errno if failed. + * Closes a connection if it is open. */ - virtual int open() = 0; + virtual void stop(); + + /** + * Returns true if the connection is open and available to send/receive. + */ + virtual bool isOpen() = 0; /** * Blocking call to read data from the connection. @@ -72,9 +89,24 @@ public: * @return int Number of bytes transmitted, or -1 if failed. */ virtual int write(const std::vector<uint8_t>& data) = 0; + + /** + * Serialized and send the given message to the other side. + */ + void sendMessage(emulator::EmulatorMessage const& msg); + + protected: + std::unique_ptr<std::thread> mReadThread; + MessageProcessor* mMessageProcessor; + + /** + * A thread that reads messages in a loop, and responds. You can stop this thread by calling + * stop(). + */ + void readThread(); }; -} // impl +} // namespace impl } // namespace V2_0 } // namespace vehicle @@ -82,5 +114,4 @@ public: } // namespace hardware } // namespace android - #endif // android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h index eb9d6605cf..7614cad1f7 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h @@ -34,6 +34,16 @@ constexpr int AP_POWER_STATE_REQ = (int)VehicleProperty::AP_POWER_STATE_REQ; constexpr int AP_POWER_STATE_REPORT = (int)VehicleProperty::AP_POWER_STATE_REPORT; constexpr int DOOR_1_LEFT = (int)VehicleAreaDoor::ROW_1_LEFT; constexpr int DOOR_1_RIGHT = (int)VehicleAreaDoor::ROW_1_RIGHT; +constexpr int DOOR_2_LEFT = (int)VehicleAreaDoor::ROW_2_LEFT; +constexpr int DOOR_2_RIGHT = (int)VehicleAreaDoor::ROW_2_RIGHT; +constexpr int DOOR_REAR = (int)VehicleAreaDoor::REAR; +constexpr int WINDOW_1_LEFT = (int)VehicleAreaWindow::ROW_1_LEFT; +constexpr int WINDOW_1_RIGHT = (int)VehicleAreaWindow::ROW_1_RIGHT; +constexpr int WINDOW_2_LEFT = (int)VehicleAreaWindow::ROW_2_LEFT; +constexpr int WINDOW_2_RIGHT = (int)VehicleAreaWindow::ROW_2_RIGHT; +constexpr int WINDOW_ROOF_TOP_1 = (int)VehicleAreaWindow::ROOF_TOP_1; +constexpr int FAN_DIRECTION_FACE = (int)VehicleHvacFanDirection::FACE; +constexpr int FAN_DIRECTION_FLOOR = (int)VehicleHvacFanDirection::FLOOR; constexpr int OBD2_LIVE_FRAME = (int)VehicleProperty::OBD2_LIVE_FRAME; constexpr int OBD2_FREEZE_FRAME = (int)VehicleProperty::OBD2_FREEZE_FRAME; constexpr int OBD2_FREEZE_FRAME_INFO = (int)VehicleProperty::OBD2_FREEZE_FRAME_INFO; @@ -44,10 +54,28 @@ constexpr int WHEEL_TICK = (int)VehicleProperty::WHEEL_TICK; constexpr int ALL_WHEELS = (int)(VehicleAreaWheel::LEFT_FRONT | VehicleAreaWheel::RIGHT_FRONT | VehicleAreaWheel::LEFT_REAR | VehicleAreaWheel::RIGHT_REAR); +constexpr int SEAT_1_LEFT = (int)(VehicleAreaSeat::ROW_1_LEFT); +constexpr int SEAT_1_RIGHT = (int)(VehicleAreaSeat::ROW_1_RIGHT); constexpr int HVAC_LEFT = (int)(VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER); constexpr int HVAC_RIGHT = (int)(VehicleAreaSeat::ROW_1_RIGHT | VehicleAreaSeat::ROW_2_RIGHT); constexpr int HVAC_ALL = HVAC_LEFT | HVAC_RIGHT; +constexpr int VENDOR_EXTENSION_BOOLEAN_PROPERTY = + (int)(0x101 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::BOOLEAN | VehicleArea::DOOR); +constexpr int VENDOR_EXTENSION_FLOAT_PROPERTY = + (int)(0x102 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::FLOAT | VehicleArea::SEAT); +constexpr int VENDOR_EXTENSION_INT_PROPERTY = + (int)(0x103 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::INT32 | VehicleArea::WINDOW); +constexpr int VENDOR_EXTENSION_STRING_PROPERTY = + (int)(0x104 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::STRING | VehicleArea::GLOBAL); +constexpr int FUEL_DOOR_REAR_LEFT = (int)PortLocationType::REAR_LEFT; +constexpr int CHARGE_PORT_FRONT_LEFT = (int)PortLocationType::FRONT_LEFT; +constexpr int LIGHT_STATE_ON = (int)VehicleLightState::ON; +constexpr int LIGHT_SWITCH_AUTO = (int)VehicleLightSwitch::AUTOMATIC; +constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT; +constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT; +constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR; +constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR; /** * This property is used for test purpose to generate fake events. Here is the test package that @@ -70,33 +98,39 @@ const int32_t kGenerateFakeDataControllingProperty = enum class FakeDataCommand : int32_t { /** * Starts linear fake data generation. Caller must provide additional data: - * int32Values[1] - VehicleProperty to which command applies + * int32Values[1] - vehicle property to which command applies * int64Values[0] - periodic interval in nanoseconds * floatValues[0] - initial value * floatValues[1] - dispersion defines the min/max value relative to initial value, where * max = initial_value + dispersion, min = initial_value - dispersion. * Dispersion should be non-negative, otherwise the behavior is undefined. * floatValues[2] - increment, with every timer tick the value will be incremented by this - * amount. When reaching to max value, the current value will be set to min. - * It should be non-negative, otherwise the behavior is undefined. + * amount. When reaching to max value, the current value will be set to + * min. It should be non-negative, otherwise the behavior is undefined. */ StartLinear = 0, - /** Stops generating of fake data that was triggered by Start commands. - * int32Values[1] - VehicleProperty to which command applies. VHAL will stop the + /** Stops linear fake data generation that was triggered by StartLinear commands. + * int32Values[1] - vehicle property to which command applies. VHAL will stop the * corresponding linear generation for that property. */ StopLinear = 1, /** - * Starts JSON-based fake data generation. Caller must provide a string value specifying - * the path to fake value JSON file: + * Starts JSON-based fake data generation. It iterates through JSON-encoded VHAL events from a + * file and inject them to VHAL. The iteration can be repeated multiple times or infinitely. + * Caller must provide additional data: + * int32Values[1] - number of iterations. If it is not provided or -1. The iteration will be + * repeated infinite times. * stringValue - path to the fake values JSON file */ StartJson = 2, /** - * Stops JSON-based fake data generation. No additional arguments needed. + * Stops JSON-based fake data generation. As multiple JSON-based generation can happen at the + * same time. Caller must provide the path of fake value JSON file to stop the corresponding + * generation: + * stringValue - path to the fake values JSON file */ StopJson = 3, @@ -133,8 +167,9 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, - .initialValue = {.floatValues = {15000}}}, + .initialValue = {.floatValues = {15000.0f}}}, {.config = { @@ -149,8 +184,9 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, - .initialValue = {.floatValues = {150000}}}, + .initialValue = {.floatValues = {150000.0f}}}, {.config = { @@ -162,6 +198,24 @@ const ConfigDeclaration kVehicleProperties[]{ {.config = { + .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}}, + + {.config = + { + .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}}, + + {.config = + { .prop = toInt(VehicleProperty::INFO_MAKE), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, @@ -179,6 +233,16 @@ const ConfigDeclaration kVehicleProperties[]{ {.config = { + .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + // this was a zoned property on an old vhal, but it is meant to be global + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {SEAT_1_LEFT}}}, + + {.config = + { .prop = toInt(VehicleProperty::PERF_ODOMETER), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, @@ -202,14 +266,16 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::FUEL_LEVEL), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, - .initialValue = {.floatValues = {15000}}}, + .initialValue = {.floatValues = {15000.0f}}}, {.config = { .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN), - .access = VehiclePropertyAccess::READ, + .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {0}}}, @@ -218,14 +284,16 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, - .initialValue = {.floatValues = {150000}}}, + .initialValue = {.floatValues = {150000.0f}}}, {.config = { .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN), - .access = VehiclePropertyAccess::READ, + .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {0}}}, @@ -234,6 +302,7 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {0}}}, @@ -242,8 +311,37 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, - .initialValue = {.floatValues = {0}}}, + .initialValue = {.floatValues = {0.0f}}}, + + {.config = + { + .prop = toInt(VehicleProperty::RANGE_REMAINING), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.floatValues = {100.0f}}}, // units in meters + + {.config = + {.prop = toInt(VehicleProperty::TIRE_PRESSURE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .areaConfigs = + {VehicleAreaConfig{ + .areaId = WHEEL_FRONT_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_FRONT_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_REAR_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, + }, + VehicleAreaConfig{ + .areaId = WHEEL_REAR_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f, + }}}, + .initialValue = {.floatValues = {200}}}, // units in kPa {.config = { @@ -266,6 +364,7 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, }, .initialValue = {.int32Values = {0}}}, @@ -283,11 +382,8 @@ const ConfigDeclaration kVehicleProperties[]{ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}, // TODO(bryaneyler): Ideally, this is generated dynamically from // kHvacPowerProperties. - .configArray = - { - 0x12400500, // HVAC_FAN_SPEED - 0x12400501 // HVAC_FAN_DIRECTION - }}, + .configArray = {toInt(VehicleProperty::HVAC_FAN_SPEED), + toInt(VehicleProperty::HVAC_FAN_DIRECTION)}}, .initialValue = {.int32Values = {1}}}, { @@ -355,6 +451,24 @@ const ConfigDeclaration kVehicleProperties[]{ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}}, + {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}}, + .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR, + FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR}}}, + + {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3, + }, + VehicleAreaConfig{ + .areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3, + }}}, + .initialValue = {.int32Values = {0}}}, // 0 is off and +ve values indicate ventilation level. + {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, @@ -362,14 +476,29 @@ const ConfigDeclaration kVehicleProperties[]{ .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}}, .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling + {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = SEAT_1_LEFT, .minInt32Value = -2, .maxInt32Value = 2, + }, + VehicleAreaConfig{ + .areaId = SEAT_1_RIGHT, .minInt32Value = -2, .maxInt32Value = 2, + }}}, + .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling + {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .areaConfigs = {VehicleAreaConfig{ - .areaId = HVAC_LEFT, .minFloatValue = 16, .maxFloatValue = 32, + .areaId = HVAC_LEFT, + .minFloatValue = 16, + .maxFloatValue = 32, }, VehicleAreaConfig{ - .areaId = HVAC_RIGHT, .minFloatValue = 16, .maxFloatValue = 32, + .areaId = HVAC_RIGHT, + .minFloatValue = 16, + .maxFloatValue = 32, }}}, .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}}, {HVAC_RIGHT, {.floatValues = {20}}}}}, @@ -443,12 +572,51 @@ const ConfigDeclaration kVehicleProperties[]{ }, {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK), - .access = VehiclePropertyAccess::READ, + .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT}, - VehicleAreaConfig{.areaId = DOOR_1_RIGHT}}}, + VehicleAreaConfig{.areaId = DOOR_1_RIGHT}, + VehicleAreaConfig{.areaId = DOOR_2_LEFT}, + VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}}, .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}}, - {DOOR_1_RIGHT, {.int32Values = {1}}}}}, + {DOOR_1_RIGHT, {.int32Values = {1}}}, + {DOOR_2_LEFT, {.int32Values = {1}}}, + {DOOR_2_RIGHT, {.int32Values = {1}}}}}, + + {.config = + { + .prop = toInt(VehicleProperty::DOOR_POS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = + {VehicleAreaConfig{.areaId = DOOR_1_LEFT, .minInt32Value = 0, .maxInt32Value = 1}, + VehicleAreaConfig{.areaId = DOOR_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 1}, + VehicleAreaConfig{.areaId = DOOR_2_LEFT, .minInt32Value = 0, .maxInt32Value = 1}, + VehicleAreaConfig{.areaId = DOOR_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 1}, + VehicleAreaConfig{.areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}}, + .initialValue = {.int32Values = {0}}}, + + {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_RIGHT | WINDOW_2_LEFT | + WINDOW_2_RIGHT}}}, + .initialAreaValues = {{WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT, + {.int32Values = {0}}}}}, + + {.config = + {.prop = toInt(VehicleProperty::WINDOW_POS), + .access = + VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = + {VehicleAreaConfig{.areaId = WINDOW_1_LEFT, .minInt32Value = 0, .maxInt32Value = 10}, + VehicleAreaConfig{.areaId = WINDOW_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 10}, + VehicleAreaConfig{.areaId = WINDOW_2_LEFT, .minInt32Value = 0, .maxInt32Value = 10}, + VehicleAreaConfig{.areaId = WINDOW_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 10}, + VehicleAreaConfig{ + .areaId = WINDOW_ROOF_TOP_1, .minInt32Value = -10, .maxInt32Value = 10}}}, + .initialValue = {.int32Values = {0}}}, {.config = { @@ -475,12 +643,12 @@ const ConfigDeclaration kVehicleProperties[]{ .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .configArray = {3}}, - .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON_FULL), 0}}}, + .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}}, {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT), .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, - .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::BOOT_COMPLETE), 0}}}, + .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}}, {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS), .access = VehiclePropertyAccess::READ_WRITE, @@ -488,11 +656,6 @@ const ConfigDeclaration kVehicleProperties[]{ .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}}, .initialValue = {.int32Values = {100}}}, - {.config = {.prop = toInt(VehicleProperty::AP_POWER_BOOTUP_REASON), - .access = VehiclePropertyAccess::READ, - .changeMode = VehiclePropertyChangeMode::STATIC}, - .initialValue = {.int32Values = {toInt(VehicleApPowerBootupReason::USER_POWER_ON)}}}, - { .config = {.prop = OBD2_LIVE_FRAME, .access = VehiclePropertyAccess::READ, @@ -520,9 +683,126 @@ const ConfigDeclaration kVehicleProperties[]{ .configArray = {1}}, }, + {.config = + { + .prop = toInt(VehicleProperty::HEADLIGHTS_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, + + {.config = + { + .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {LIGHT_STATE_ON}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, + + {.config = + { + .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, + + {.config = + { + .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}}, + {.config = {.prop = VEHICLE_MAP_SERVICE, .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE}}, + + // Example Vendor Extension properties for testing + {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT}, + VehicleAreaConfig{.areaId = DOOR_1_RIGHT}, + VehicleAreaConfig{.areaId = DOOR_2_LEFT}, + VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}}, + .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}}, + {DOOR_1_RIGHT, {.int32Values = {1}}}, + {DOOR_2_LEFT, {.int32Values = {0}}}, + {DOOR_2_RIGHT, {.int32Values = {0}}}}}, + + {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = HVAC_LEFT, .minFloatValue = -10, .maxFloatValue = 10}, + VehicleAreaConfig{.areaId = HVAC_RIGHT, + .minFloatValue = -10, + .maxFloatValue = 10}}}, + .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}}, {HVAC_RIGHT, {.floatValues = {2}}}}}, + + {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = {VehicleAreaConfig{ + .areaId = (int)VehicleAreaWindow::FRONT_WINDSHIELD, + .minInt32Value = -100, + .maxInt32Value = 100}, + VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::REAR_WINDSHIELD, + .minInt32Value = -100, + .maxInt32Value = 100}, + VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::ROOF_TOP_1, + .minInt32Value = -100, + .maxInt32Value = 100}}}, + .initialAreaValues = {{(int)VehicleAreaWindow::FRONT_WINDSHIELD, {.int32Values = {1}}}, + {(int)VehicleAreaWindow::REAR_WINDSHIELD, {.int32Values = {0}}}, + {(int)VehicleAreaWindow::ROOF_TOP_1, {.int32Values = {-1}}}}}, + + {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE}, + .initialValue = {.stringValue = "Vendor String Property"}}, }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp index 07695bfe7e..ba81a521a0 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp @@ -92,10 +92,8 @@ EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore) mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), mRecurrentTimer( std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)), - mLinearFakeValueGenerator(std::make_unique<LinearFakeValueGenerator>( - std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))), - mJsonFakeValueGenerator(std::make_unique<JsonFakeValueGenerator>( - std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))) { + mGeneratorHub( + std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) { initStaticConfig(); for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { mPropStore->registerProperty(kVehicleProperties[i].config); @@ -159,12 +157,28 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { // now, just returns OK; otherwise, hal clients crash with property not supported. return StatusCode::OK; case AP_POWER_STATE_REPORT: - // This property has different behavior between get/set. When it is set, the value - // goes to the vehicle but is NOT updated in the property store back to Android. - // Commented out for now, because it may mess up automated testing that use the - // emulator interface. - // getEmulatorOrDie()->doSetValueFromClient(propValue); - return StatusCode::OK; + switch (propValue.value.int32Values[0]) { + case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT): + case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED): + case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL): + // CPMS is in WAIT_FOR_VHAL state, simply move to ON + doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0)); + break; + case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY): + case toInt(VehicleApPowerStateReport::SHUTDOWN_START): + // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command + doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0)); + break; + case toInt(VehicleApPowerStateReport::ON): + case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE): + case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE): + // Do nothing + break; + default: + // Unknown state + break; + } + break; } } @@ -189,6 +203,7 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) { } getEmulatorOrDie()->doSetValueFromClient(propValue); + doHalEvent(getValuePool()->obtain(propValue)); return StatusCode::OK; } @@ -343,19 +358,54 @@ StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropVa switch (command) { case FakeDataCommand::StartLinear: { ALOGI("%s, FakeDataCommand::StartLinear", __func__); - return mLinearFakeValueGenerator->start(request); + if (v.int32Values.size() < 2) { + ALOGE("%s: expected property ID in int32Values", __func__); + return StatusCode::INVALID_ARG; + } + if (!v.int64Values.size()) { + ALOGE("%s: interval is not provided in int64Values", __func__); + return StatusCode::INVALID_ARG; + } + if (v.floatValues.size() < 3) { + ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__, + v.floatValues.size()); + return StatusCode::INVALID_ARG; + } + int32_t cookie = v.int32Values[1]; + mGeneratorHub.registerGenerator(cookie, + std::make_unique<LinearFakeValueGenerator>(request)); + break; } case FakeDataCommand::StartJson: { ALOGI("%s, FakeDataCommand::StartJson", __func__); - return mJsonFakeValueGenerator->start(request); + if (v.stringValue.empty()) { + ALOGE("%s: path to JSON file is missing", __func__); + return StatusCode::INVALID_ARG; + } + int32_t cookie = std::hash<std::string>()(v.stringValue); + mGeneratorHub.registerGenerator(cookie, + std::make_unique<JsonFakeValueGenerator>(request)); + break; } case FakeDataCommand::StopLinear: { ALOGI("%s, FakeDataCommand::StopLinear", __func__); - return mLinearFakeValueGenerator->stop(request); + if (v.int32Values.size() < 2) { + ALOGE("%s: expected property ID in int32Values", __func__); + return StatusCode::INVALID_ARG; + } + int32_t cookie = v.int32Values[1]; + mGeneratorHub.unregisterGenerator(cookie); + break; } case FakeDataCommand::StopJson: { ALOGI("%s, FakeDataCommand::StopJson", __func__); - return mJsonFakeValueGenerator->stop(request); + if (v.stringValue.empty()) { + ALOGE("%s: path to JSON file is missing", __func__); + return StatusCode::INVALID_ARG; + } + int32_t cookie = std::hash<std::string>()(v.stringValue); + mGeneratorHub.unregisterGenerator(cookie); + break; } case FakeDataCommand::KeyPress: { ALOGI("%s, FakeDataCommand::KeyPress", __func__); @@ -374,6 +424,18 @@ StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropVa return StatusCode::OK; } +VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq( + VehicleApPowerStateReq state, int32_t param) { + auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2); + req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ); + req->areaId = 0; + req->timestamp = elapsedRealtimeNano(); + req->status = VehiclePropertyStatus::AVAILABLE; + req->value.int32Values[0] = toInt(state); + req->value.int32Values[1] = param; + return req; +} + VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp( VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) { auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3); @@ -398,7 +460,7 @@ void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) { mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus); auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode; if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) { - doHalEvent(move(updatedPropValue)); + doHalEvent(std::move(updatedPropValue)); } } } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index c188aefe20..78895e3db2 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -30,8 +30,7 @@ #include "vhal_v2_0/VehiclePropertyStore.h" #include "DefaultConfig.h" -#include "FakeValueGenerator.h" - +#include "GeneratorHub.h" #include "VehicleEmulator.h" namespace android { @@ -68,6 +67,7 @@ private: StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); void onFakeValueGenerated(const VehiclePropValue& value); + VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param); VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay); @@ -85,8 +85,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set<int32_t> mHvacPowerProps; RecurrentTimer mRecurrentTimer; - std::unique_ptr<FakeValueGenerator> mLinearFakeValueGenerator; - std::unique_ptr<FakeValueGenerator> mJsonFakeValueGenerator; + GeneratorHub mGeneratorHub; }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h index 1eeb88dffe..d6ad77df73 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h @@ -27,28 +27,22 @@ namespace V2_0 { namespace impl { -using OnHalEvent = std::function<void(const VehiclePropValue& event)>; -using MuxGuard = std::lock_guard<std::mutex>; - class FakeValueGenerator { public: virtual ~FakeValueGenerator() = default; - /** - * Starts generating VHAL events - * - * @param request in VehiclePropValue with required information to start fake data generation - * @return StatusCode of the start request - */ - virtual StatusCode start(const VehiclePropValue& request) = 0; - /** - * Stops generating VHAL events - * @param request in VehiclePropValue with required information to stop fake data generation - * @return StatusCode of the stop request - */ - virtual StatusCode stop(const VehiclePropValue& request) = 0; + + virtual VehiclePropValue nextEvent() = 0; + + virtual bool hasNext() = 0; }; -} // impl +using Clock = std::chrono::steady_clock; +using Nanos = std::chrono::nanoseconds; +using TimePoint = std::chrono::time_point<Clock, Nanos>; + +using FakeValueGeneratorPtr = std::unique_ptr<FakeValueGenerator>; + +} // namespace impl } // namespace V2_0 } // namespace vehicle diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp new file mode 100644 index 0000000000..548285abfb --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#define LOG_TAG "GeneratorHub" + +#include <log/log.h> + +#include "GeneratorHub.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +GeneratorHub::GeneratorHub(const OnHalEvent& onHalEvent) + : mOnHalEvent(onHalEvent), mThread(&GeneratorHub::run, this) {} + +void GeneratorHub::registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator) { + { + std::lock_guard<std::mutex> g(mLock); + // Register only if the generator can produce event + if (generator->hasNext()) { + // Push the next event if it is a new generator + if (mGenerators.find(cookie) == mGenerators.end()) { + ALOGI("%s: Registering new generator, cookie: %d", __func__, cookie); + mEventQueue.push({cookie, generator->nextEvent()}); + } + mGenerators[cookie] = std::move(generator); + ALOGI("%s: Registered generator, cookie: %d", __func__, cookie); + } + } + mCond.notify_one(); +} + +void GeneratorHub::unregisterGenerator(int32_t cookie) { + { + std::lock_guard<std::mutex> g(mLock); + mGenerators.erase(cookie); + } + mCond.notify_one(); + ALOGI("%s: Unregistered generator, cookie: %d", __func__, cookie); +} + +void GeneratorHub::run() { + while (true) { + std::unique_lock<std::mutex> g(mLock); + // Pop events whose generator does not exist (may be already unregistered) + while (!mEventQueue.empty() + && mGenerators.find(mEventQueue.top().cookie) == mGenerators.end()) { + mEventQueue.pop(); + } + // Wait until event queue is not empty + mCond.wait(g, [this] { return !mEventQueue.empty(); }); + + const VhalEvent& curEvent = mEventQueue.top(); + + TimePoint eventTime(Nanos(curEvent.val.timestamp)); + // Wait until the soonest event happen + if (mCond.wait_until(g, eventTime) != std::cv_status::timeout) { + // It is possible that a new generator is registered and produced a sooner event, or current + // generator is unregistered, in this case the thread will re-evaluate the soonest event + ALOGI("Something happened while waiting"); + continue; + } + // Now it's time to handle current event. + mOnHalEvent(curEvent.val); + // Update queue by popping current event and producing next event from the same generator + int32_t cookie = curEvent.cookie; + mEventQueue.pop(); + if (hasNext(cookie)) { + mEventQueue.push({cookie, mGenerators[cookie]->nextEvent()}); + } else { + ALOGI("%s: Generator ended, unregister it, cookie: %d", __func__, cookie); + mGenerators.erase(cookie); + } + } +} + +bool GeneratorHub::hasNext(int32_t cookie) { + return mGenerators.find(cookie) != mGenerators.end() && mGenerators[cookie]->hasNext(); +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h new file mode 100644 index 0000000000..dcf6a4f06e --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h @@ -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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_ + +#include <atomic> +#include <chrono> +#include <condition_variable> +#include <iostream> +#include <queue> +#include <thread> +#include <unordered_map> + +#include "FakeValueGenerator.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +/** + * This is the scheduler for all VHAL event generators. It manages all generators and uses priority + * queue to maintain generated events ordered by timestamp. The scheduler uses a single thread to + * keep querying and updating the event queue to make sure events from all generators are produced + * in order. + */ +class GeneratorHub { +private: + struct VhalEvent { + int32_t cookie; // Cookie is used to find the associated generator. + VehiclePropValue val; + }; + // Comparator used by priority queue to keep track of soonest event. + struct GreaterByTime { + bool operator()(const VhalEvent& lhs, const VhalEvent& rhs) const { + return lhs.val.timestamp > rhs.val.timestamp; + } + }; + + using OnHalEvent = std::function<void(const VehiclePropValue& event)>; + +public: + GeneratorHub(const OnHalEvent& onHalEvent); + ~GeneratorHub() = default; + + /** + * Register a new generator. The generator will be discarded if it could not produce next event. + * The existing generator will be overridden if it has the same cookie. + */ + void registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator); + + void unregisterGenerator(int32_t cookie); + +private: + /** + * Main loop of the single thread to producing event and updating event queue. + */ + void run(); + + bool hasNext(int32_t cookie); + +private: + std::priority_queue<VhalEvent, std::vector<VhalEvent>, GreaterByTime> mEventQueue; + std::unordered_map<int32_t, FakeValueGeneratorPtr> mGenerators; + OnHalEvent mOnHalEvent; + + mutable std::mutex mLock; + std::condition_variable mCond; + std::thread mThread; +}; + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_ diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp index 88b8f865c5..b8fd2babee 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "JsonFakeValueGenerator" #include <fstream> +#include <type_traits> +#include <typeinfo> #include <log/log.h> #include <vhal_v2_0/VehicleUtils.h> @@ -31,57 +33,48 @@ namespace V2_0 { namespace impl { -JsonFakeValueGenerator::JsonFakeValueGenerator(const OnHalEvent& onHalEvent) - : mOnHalEvent(onHalEvent), mThread(&JsonFakeValueGenerator::loop, this) {} - -JsonFakeValueGenerator::~JsonFakeValueGenerator() { - mStopRequested = true; - { - MuxGuard g(mLock); - mGenCfg.index = 0; - mGenCfg.events.clear(); - } - mCond.notify_one(); - if (mThread.joinable()) { - mThread.join(); - } -} - -StatusCode JsonFakeValueGenerator::start(const VehiclePropValue& request) { +JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) { const auto& v = request.value; - if (v.stringValue.empty()) { - ALOGE("%s: path to JSON file is missing", __func__); - return StatusCode::INVALID_ARG; - } const char* file = v.stringValue.c_str(); std::ifstream ifs(file); if (!ifs) { ALOGE("%s: couldn't open %s for parsing.", __func__, file); - return StatusCode::INTERNAL_ERROR; } - std::vector<VehiclePropValue> fakeVhalEvents = parseFakeValueJson(ifs); - - { - MuxGuard g(mLock); - mGenCfg = {0, fakeVhalEvents}; - } - mCond.notify_one(); - return StatusCode::OK; + mGenCfg = { + .index = 0, + .events = parseFakeValueJson(ifs), + }; + // Iterate infinitely if repetition number is not provided + mNumOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1]; } -StatusCode JsonFakeValueGenerator::stop(const VehiclePropValue& request) { - const auto& v = request.value; - if (!v.stringValue.empty()) { - ALOGI("%s: %s", __func__, v.stringValue.c_str()); +VehiclePropValue JsonFakeValueGenerator::nextEvent() { + VehiclePropValue generatedValue; + if (!hasNext()) { + return generatedValue; + } + TimePoint eventTime = Clock::now(); + if (mGenCfg.index != 0) { + // All events (start from 2nd one) are supposed to happen in the future with a delay + // equals to the duration between previous and current event. + eventTime += Nanos(mGenCfg.events[mGenCfg.index].timestamp - + mGenCfg.events[mGenCfg.index - 1].timestamp); } + generatedValue = mGenCfg.events[mGenCfg.index]; + generatedValue.timestamp = eventTime.time_since_epoch().count(); - { - MuxGuard g(mLock); + mGenCfg.index++; + if (mGenCfg.index == mGenCfg.events.size()) { mGenCfg.index = 0; - mGenCfg.events.clear(); + if (mNumOfIterations > 0) { + mNumOfIterations--; + } } - mCond.notify_one(); - return StatusCode::OK; + return generatedValue; +} + +bool JsonFakeValueGenerator::hasNext() { + return mNumOfIterations != 0 && mGenCfg.events.size() > 0; } std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::istream& is) { @@ -131,9 +124,14 @@ std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::is case VehiclePropertyType::STRING: value.stringValue = rawEventValue.asString(); break; + case VehiclePropertyType::MIXED: + copyMixedValueJson(value, rawEventValue); + if (isDiagnosticProperty(event.prop)) { + value.bytes = generateDiagnosticBytes(value); + } + break; default: - ALOGE("%s: unsupported type for property: 0x%x with value: %s", __func__, - event.prop, rawEventValue.asString().c_str()); + ALOGE("%s: unsupported type for property: 0x%x", __func__, event.prop); continue; } fakeVhalEvents.push_back(event); @@ -141,28 +139,58 @@ std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::is return fakeVhalEvents; } -void JsonFakeValueGenerator::loop() { - static constexpr auto kInvalidTime = TimePoint(Nanos::max()); - - while (!mStopRequested) { - auto nextEventTime = kInvalidTime; - { - MuxGuard g(mLock); - if (mGenCfg.index < mGenCfg.events.size()) { - mOnHalEvent(mGenCfg.events[mGenCfg.index]); - } - if (!mGenCfg.events.empty() && mGenCfg.index < mGenCfg.events.size() - 1) { - Nanos intervalNano = - static_cast<Nanos>(mGenCfg.events[mGenCfg.index + 1].timestamp - - mGenCfg.events[mGenCfg.index].timestamp); - nextEventTime = Clock::now() + intervalNano; - } - mGenCfg.index++; +void JsonFakeValueGenerator::copyMixedValueJson(VehiclePropValue::RawValue& dest, + const Json::Value& jsonValue) { + copyJsonArray(dest.int32Values, jsonValue["int32Values"]); + copyJsonArray(dest.int64Values, jsonValue["int64Values"]); + copyJsonArray(dest.floatValues, jsonValue["floatValues"]); + dest.stringValue = jsonValue["stringValue"].asString(); +} + +template <typename T> +void JsonFakeValueGenerator::copyJsonArray(hidl_vec<T>& dest, const Json::Value& jsonArray) { + dest.resize(jsonArray.size()); + for (Json::Value::ArrayIndex i = 0; i < jsonArray.size(); i++) { + if (std::is_same<T, int32_t>::value) { + dest[i] = jsonArray[i].asInt(); + } else if (std::is_same<T, int64_t>::value) { + dest[i] = jsonArray[i].asInt64(); + } else if (std::is_same<T, float>::value) { + dest[i] = jsonArray[i].asFloat(); + } + } +} + +bool JsonFakeValueGenerator::isDiagnosticProperty(int32_t prop) { + return prop == (int32_t)VehicleProperty::OBD2_LIVE_FRAME || + prop == (int32_t)VehicleProperty::OBD2_FREEZE_FRAME; +} + +hidl_vec<uint8_t> JsonFakeValueGenerator::generateDiagnosticBytes( + const VehiclePropValue::RawValue& diagnosticValue) { + size_t byteSize = ((size_t)DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX + + (size_t)DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX + 2); + hidl_vec<uint8_t> bytes(byteSize % 8 == 0 ? byteSize / 8 : byteSize / 8 + 1); + + auto& int32Values = diagnosticValue.int32Values; + for (size_t i = 0; i < int32Values.size(); i++) { + if (int32Values[i] != 0) { + setBit(bytes, i); } + } - std::unique_lock<std::mutex> g(mLock); - mCond.wait_until(g, nextEventTime); + auto& floatValues = diagnosticValue.floatValues; + for (size_t i = 0; i < floatValues.size(); i++) { + if (floatValues[i] != 0.0) { + setBit(bytes, i + (size_t)DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX + 1); + } } + return bytes; +} + +void JsonFakeValueGenerator::setBit(hidl_vec<uint8_t>& bytes, size_t idx) { + uint8_t mask = 1 << (idx % 8); + bytes[idx / 8] |= mask; } } // namespace impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h index 51da4c5383..70575f77bf 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h @@ -17,11 +17,8 @@ #ifndef android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_ #define android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_ -#include <atomic> #include <chrono> -#include <condition_variable> #include <iostream> -#include <thread> #include <json/json.h> @@ -37,32 +34,33 @@ namespace impl { class JsonFakeValueGenerator : public FakeValueGenerator { private: - using Nanos = std::chrono::nanoseconds; - using Clock = std::chrono::steady_clock; - using TimePoint = std::chrono::time_point<Clock, Nanos>; - struct GeneratorCfg { size_t index; std::vector<VehiclePropValue> events; }; public: - JsonFakeValueGenerator(const OnHalEvent& onHalEvent); - ~JsonFakeValueGenerator(); - StatusCode start(const VehiclePropValue& request) override; - StatusCode stop(const VehiclePropValue& request) override; + JsonFakeValueGenerator(const VehiclePropValue& request); + ~JsonFakeValueGenerator() = default; + + VehiclePropValue nextEvent(); + + bool hasNext(); private: std::vector<VehiclePropValue> parseFakeValueJson(std::istream& is); - void loop(); + void copyMixedValueJson(VehiclePropValue::RawValue& dest, const Json::Value& jsonValue); + + template <typename T> + void copyJsonArray(hidl_vec<T>& dest, const Json::Value& jsonArray); + + bool isDiagnosticProperty(int32_t prop); + hidl_vec<uint8_t> generateDiagnosticBytes(const VehiclePropValue::RawValue& diagnosticValue); + void setBit(hidl_vec<uint8_t>& bytes, size_t idx); private: - OnHalEvent mOnHalEvent; - std::thread mThread; - mutable std::mutex mLock; - std::condition_variable mCond; GeneratorCfg mGenCfg; - std::atomic_bool mStopRequested{false}; + int32_t mNumOfIterations; }; } // namespace impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp index 8cb9322fa6..7bdc97cd2b 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp @@ -29,101 +29,48 @@ namespace V2_0 { namespace impl { -LinearFakeValueGenerator::LinearFakeValueGenerator(const OnHalEvent& onHalEvent) - : mOnHalEvent(onHalEvent), - mRecurrentTimer(std::bind(&LinearFakeValueGenerator::onTimer, this, std::placeholders::_1)) {} - -StatusCode LinearFakeValueGenerator::start(const VehiclePropValue& request) { +LinearFakeValueGenerator::LinearFakeValueGenerator(const VehiclePropValue& request) { const auto& v = request.value; - if (v.int32Values.size() < 2) { - ALOGE("%s: expected property ID in int32Values", __func__); - return StatusCode::INVALID_ARG; - } - int32_t propId = v.int32Values[1]; - - if (!v.int64Values.size()) { - ALOGE("%s: interval is not provided in int64Values", __func__); - return StatusCode::INVALID_ARG; - } - auto interval = std::chrono::nanoseconds(v.int64Values[0]); - - if (v.floatValues.size() < 3) { - ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__, - v.floatValues.size()); - return StatusCode::INVALID_ARG; - } - float initialValue = v.floatValues[0]; - float dispersion = v.floatValues[1]; - float increment = v.floatValues[2]; - - MuxGuard g(mLock); - removeLocked(propId); - mGenCfg.insert({propId, GeneratorCfg{ - .initialValue = initialValue, - .currentValue = initialValue, - .dispersion = dispersion, - .increment = increment,}}); - - mRecurrentTimer.registerRecurrentEvent(interval, propId); - return StatusCode::OK; + mGenCfg = GeneratorCfg{ + .propId = v.int32Values[1], + .initialValue = v.floatValues[0], + .currentValue = v.floatValues[0], + .dispersion = v.floatValues[1], + .increment = v.floatValues[2], + .interval = Nanos(v.int64Values[0]), + }; } -StatusCode LinearFakeValueGenerator::stop(const VehiclePropValue& request) { - const auto& v = request.value; - if (v.int32Values.size() < 2) { - ALOGE("%s: expected property ID in int32Values", __func__); - return StatusCode::INVALID_ARG; +VehiclePropValue LinearFakeValueGenerator::nextEvent() { + mGenCfg.currentValue += mGenCfg.increment; + if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) { + mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion; } - int32_t propId = v.int32Values[1]; - - MuxGuard g(mLock); - if (propId == 0) { - // Remove all. - for (auto&& it : mGenCfg) { - removeLocked(it.first); - } - } else { - removeLocked(propId); + VehiclePropValue event = {.prop = mGenCfg.propId}; + auto& value = event.value; + switch (getPropType(event.prop)) { + case VehiclePropertyType::INT32: + value.int32Values.resize(1); + value.int32Values[0] = static_cast<int32_t>(mGenCfg.currentValue); + break; + case VehiclePropertyType::INT64: + value.int64Values.resize(1); + value.int64Values[0] = static_cast<int64_t>(mGenCfg.currentValue); + break; + case VehiclePropertyType::FLOAT: + value.floatValues.resize(1); + value.floatValues[0] = mGenCfg.currentValue; + break; + default: + ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop); } - return StatusCode::OK; + TimePoint eventTime = Clock::now() + mGenCfg.interval; + event.timestamp = eventTime.time_since_epoch().count(); + return event; } -void LinearFakeValueGenerator::removeLocked(int propId) { - if (mGenCfg.erase(propId)) { - mRecurrentTimer.unregisterRecurrentEvent(propId); - } -} - -void LinearFakeValueGenerator::onTimer(const std::vector<int32_t>& properties) { - MuxGuard g(mLock); - - for (int32_t propId : properties) { - auto& cfg = mGenCfg[propId]; - cfg.currentValue += cfg.increment; - if (cfg.currentValue > cfg.initialValue + cfg.dispersion) { - cfg.currentValue = cfg.initialValue - cfg.dispersion; - } - VehiclePropValue event = {.prop = propId}; - auto& value = event.value; - switch (getPropType(event.prop)) { - case VehiclePropertyType::INT32: - value.int32Values.resize(1); - value.int32Values[0] = static_cast<int32_t>(cfg.currentValue); - break; - case VehiclePropertyType::INT64: - value.int64Values.resize(1); - value.int64Values[0] = static_cast<int64_t>(cfg.currentValue); - break; - case VehiclePropertyType::FLOAT: - value.floatValues.resize(1); - value.floatValues[0] = cfg.currentValue; - break; - default: - ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop); - continue; - } - mOnHalEvent(event); - } +bool LinearFakeValueGenerator::hasNext() { + return true; } } // namespace impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h index fe6d097962..d3b666dd9d 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h @@ -17,8 +17,6 @@ #ifndef android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_ #define android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_ -#include <vhal_v2_0/RecurrentTimer.h> - #include "FakeValueGenerator.h" namespace android { @@ -36,27 +34,24 @@ private: // to the client. struct GeneratorCfg { - float initialValue; // + int32_t propId; + float initialValue; float currentValue; // Should be in range (initialValue +/- dispersion). float dispersion; // Defines minimum and maximum value based on initial value. float increment; // Value that we will be added to currentValue with each timer tick. + Nanos interval; }; public: - LinearFakeValueGenerator(const OnHalEvent& onHalEvent); + LinearFakeValueGenerator(const VehiclePropValue& request); ~LinearFakeValueGenerator() = default; - StatusCode start(const VehiclePropValue& request) override; - StatusCode stop(const VehiclePropValue& request) override; -private: - void removeLocked(int propId); - void onTimer(const std::vector<int32_t>& properties); + VehiclePropValue nextEvent(); + + bool hasNext(); private: - mutable std::mutex mLock; - OnHalEvent mOnHalEvent; - RecurrentTimer mRecurrentTimer; - std::unordered_map<int32_t, GeneratorCfg> mGenCfg; + GeneratorCfg mGenCfg; }; } // namespace impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp index 5a9b254594..f0242879bc 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp @@ -33,23 +33,28 @@ namespace V2_0 { namespace impl { -PipeComm::PipeComm() { - // Initialize member vars - mPipeFd = -1; -} - +PipeComm::PipeComm(MessageProcessor* messageProcessor) : CommConn(messageProcessor), mPipeFd(-1) {} -int PipeComm::open() { +void PipeComm::start() { int fd = qemu_pipe_open(CAR_SERVICE_NAME); if (fd < 0) { ALOGE("%s: Could not open connection to service: %s %d", __FUNCTION__, strerror(errno), fd); - return -errno; + return; } - ALOGI("%s: OPENED PIPE, fd=%d", __FUNCTION__, fd); + ALOGI("%s: Starting pipe connection, fd=%d", __FUNCTION__, fd); mPipeFd = fd; - return 0; + + CommConn::start(); +} + +void PipeComm::stop() { + if (mPipeFd > 0) { + ::close(mPipeFd); + mPipeFd = -1; + } + CommConn::stop(); } std::vector<uint8_t> PipeComm::read() { @@ -60,16 +65,13 @@ std::vector<uint8_t> PipeComm::read() { numBytes = qemu_pipe_frame_recv(mPipeFd, msg.data(), msg.size()); if (numBytes == MAX_RX_MSG_SZ) { - ALOGE("%s: Received max size = %d", __FUNCTION__, MAX_RX_MSG_SZ); + ALOGE("%s: Received max size = %d", __FUNCTION__, MAX_RX_MSG_SZ); } else if (numBytes > 0) { msg.resize(numBytes); return msg; } else { ALOGD("%s: Connection terminated on pipe %d, numBytes=%d", __FUNCTION__, mPipeFd, numBytes); - { - std::lock_guard<std::mutex> lock(mMutex); - mPipeFd = -1; - } + mPipeFd = -1; } return std::vector<uint8_t>(); @@ -78,11 +80,8 @@ std::vector<uint8_t> PipeComm::read() { int PipeComm::write(const std::vector<uint8_t>& data) { int retVal = 0; - { - std::lock_guard<std::mutex> lock(mMutex); - if (mPipeFd != -1) { - retVal = qemu_pipe_frame_send(mPipeFd, data.data(), data.size()); - } + if (mPipeFd != -1) { + retVal = qemu_pipe_frame_send(mPipeFd, data.data(), data.size()); } if (retVal < 0) { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h index bcd32d00d3..c8eabb8aa7 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h @@ -19,7 +19,7 @@ #include <mutex> #include <vector> -#include "CommBase.h" +#include "CommConn.h" namespace android { namespace hardware { @@ -30,38 +30,25 @@ namespace V2_0 { namespace impl { /** - * PipeComm uses a qemu pipe interface to connect to the Goldfish Emulator. + * PipeComm opens a qemu pipe to connect to the emulator, allowing the emulator UI to access the + * Vehicle HAL and simulate changing properties. + * + * Since the pipe is a client, it directly implements CommConn, and only one PipeComm can be open + * at a time. */ -class PipeComm : public CommBase { -public: - PipeComm(); +class PipeComm : public CommConn { + public: + PipeComm(MessageProcessor* messageProcessor); - /** - * Opens a pipe and begins listening. - * - * @return int Returns 0 on success. - */ - int open() override; + void start() override; + void stop() override; - /** - * Blocking call to read data from the connection. - * - * @return std::vector<uint8_t> Serialized protobuf data received from emulator. This will be - * an empty vector if the connection was closed or some other error occurred. - */ std::vector<uint8_t> read() override; - - /** - * Transmits a string of data to the emulator. - * - * @param data Serialized protobuf data to transmit. - * - * @return int Number of bytes transmitted, or -1 if failed. - */ int write(const std::vector<uint8_t>& data) override; -private: - std::mutex mMutex; + inline bool isOpen() override { return mPipeFd > 0; } + + private: int mPipeFd; }; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp index 42c1c780cc..9eb8894385 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp @@ -18,6 +18,7 @@ #include <android/hardware/automotive/vehicle/2.0/IVehicle.h> #include <android/log.h> +#include <arpa/inet.h> #include <log/log.h> #include <netinet/in.h> #include <sys/socket.h> @@ -35,45 +36,46 @@ namespace V2_0 { namespace impl { -SocketComm::SocketComm() { - // Initialize member vars - mCurSockFd = -1; - mExit = 0; - mSockFd = -1; -} - +SocketComm::SocketComm(MessageProcessor* messageProcessor) + : mListenFd(-1), mMessageProcessor(messageProcessor) {} SocketComm::~SocketComm() { - stop(); } -int SocketComm::connect() { - sockaddr_in cliAddr; - socklen_t cliLen = sizeof(cliAddr); - int cSockFd = accept(mSockFd, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen); +void SocketComm::start() { + if (!listen()) { + return; + } - if (cSockFd >= 0) { - { - std::lock_guard<std::mutex> lock(mMutex); - mCurSockFd = cSockFd; + mListenThread = std::make_unique<std::thread>(std::bind(&SocketComm::listenThread, this)); +} + +void SocketComm::stop() { + if (mListenFd > 0) { + ::close(mListenFd); + if (mListenThread->joinable()) { + mListenThread->join(); } - ALOGD("%s: Incoming connection received on socket %d", __FUNCTION__, cSockFd); - } else { - cSockFd = -1; + mListenFd = -1; } +} - return cSockFd; +void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) { + std::lock_guard<std::mutex> lock(mMutex); + for (std::unique_ptr<SocketConn> const& conn : mOpenConnections) { + conn->sendMessage(msg); + } } -int SocketComm::open() { +bool SocketComm::listen() { int retVal; struct sockaddr_in servAddr; - mSockFd = socket(AF_INET, SOCK_STREAM, 0); - if (mSockFd < 0) { - ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mSockFd, errno); - mSockFd = -1; - return -errno; + mListenFd = socket(AF_INET, SOCK_STREAM, 0); + if (mListenFd < 0) { + ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mListenFd, errno); + mListenFd = -1; + return false; } memset(&servAddr, 0, sizeof(servAddr)); @@ -81,82 +83,114 @@ int SocketComm::open() { servAddr.sin_addr.s_addr = INADDR_ANY; servAddr.sin_port = htons(DEBUG_SOCKET); - retVal = bind(mSockFd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr)); + retVal = bind(mListenFd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr)); if(retVal < 0) { ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno); - close(mSockFd); - mSockFd = -1; - return -errno; + close(mListenFd); + mListenFd = -1; + return false; } - listen(mSockFd, 1); + ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET); + ::listen(mListenFd, 1); + return true; +} + +SocketConn* SocketComm::accept() { + sockaddr_in cliAddr; + socklen_t cliLen = sizeof(cliAddr); + int sfd = ::accept(mListenFd, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen); + + if (sfd > 0) { + char addr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &cliAddr.sin_addr, addr, INET_ADDRSTRLEN); - // Set the socket to be non-blocking so we can poll it continouously - fcntl(mSockFd, F_SETFL, O_NONBLOCK); + ALOGD("%s: Incoming connection received from %s:%d", __FUNCTION__, addr, cliAddr.sin_port); + return new SocketConn(mMessageProcessor, sfd); + } - return 0; + return nullptr; } -std::vector<uint8_t> SocketComm::read() { - int32_t msgSize; - int numBytes = 0; - - // This is a variable length message. - // Read the number of bytes to rx over the socket - numBytes = ::read(mCurSockFd, &msgSize, sizeof(msgSize)); - msgSize = ntohl(msgSize); +void SocketComm::listenThread() { + while (true) { + SocketConn* conn = accept(); + if (conn == nullptr) { + return; + } - if (numBytes != sizeof(msgSize)) { - // This happens when connection is closed - ALOGD("%s: numBytes=%d, expected=4", __FUNCTION__, numBytes); - ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd); + conn->start(); { std::lock_guard<std::mutex> lock(mMutex); - mCurSockFd = -1; + mOpenConnections.push_back(std::unique_ptr<SocketConn>(conn)); } - - return std::vector<uint8_t>(); } +} - std::vector<uint8_t> msg = std::vector<uint8_t>(msgSize); +/** + * Called occasionally to clean up connections that have been closed. + */ +void SocketComm::removeClosedConnections() { + std::lock_guard<std::mutex> lock(mMutex); + std::remove_if(mOpenConnections.begin(), mOpenConnections.end(), + [](std::unique_ptr<SocketConn> const& c) { return !c->isOpen(); }); +} - numBytes = ::read(mCurSockFd, msg.data(), msgSize); +SocketConn::SocketConn(MessageProcessor* messageProcessor, int sfd) + : CommConn(messageProcessor), mSockFd(sfd) {} - if ((numBytes == msgSize) && (msgSize > 0)) { - // Received a message. - return msg; - } else { - // This happens when connection is closed - ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes, msgSize); - ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd); - { - std::lock_guard<std::mutex> lock(mMutex); - mCurSockFd = -1; +/** + * Reads, in a loop, exactly numBytes from the given fd. If the connection is closed, returns + * an empty buffer, otherwise will return exactly the given number of bytes. + */ +std::vector<uint8_t> readExactly(int fd, int numBytes) { + std::vector<uint8_t> buffer(numBytes); + int totalRead = 0; + int offset = 0; + while (totalRead < numBytes) { + int numRead = ::read(fd, &buffer.data()[offset], numBytes - offset); + if (numRead == 0) { + buffer.resize(0); + return buffer; } - return std::vector<uint8_t>(); + totalRead += numRead; } + return buffer; } -void SocketComm::stop() { - if (mExit == 0) { - std::lock_guard<std::mutex> lock(mMutex); - mExit = 1; - - // Close emulator socket if it is open - if (mCurSockFd != -1) { - close(mCurSockFd); - mCurSockFd = -1; - } +/** + * Reads an int, guaranteed to be non-zero, from the given fd. If the connection is closed, returns + * -1. + */ +int32_t readInt(int fd) { + std::vector<uint8_t> buffer = readExactly(fd, sizeof(int32_t)); + if (buffer.size() == 0) { + return -1; + } - if (mSockFd != -1) { - close(mSockFd); - mSockFd = -1; - } + int32_t value = *reinterpret_cast<int32_t*>(buffer.data()); + return ntohl(value); +} + +std::vector<uint8_t> SocketConn::read() { + int32_t msgSize = readInt(mSockFd); + if (msgSize <= 0) { + ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mSockFd); + return std::vector<uint8_t>(); + } + + return readExactly(mSockFd, msgSize); +} + +void SocketConn::stop() { + if (mSockFd > 0) { + close(mSockFd); + mSockFd = -1; } } -int SocketComm::write(const std::vector<uint8_t>& data) { +int SocketConn::write(const std::vector<uint8_t>& data) { static constexpr int MSG_HEADER_LEN = 4; int retVal = 0; union { @@ -168,19 +202,17 @@ int SocketComm::write(const std::vector<uint8_t>& data) { msgLen = static_cast<uint32_t>(data.size()); msgLen = htonl(msgLen); - std::lock_guard<std::mutex> lock(mMutex); - if (mCurSockFd != -1) { - retVal = ::write(mCurSockFd, msgLenBytes, MSG_HEADER_LEN); + if (mSockFd > 0) { + retVal = ::write(mSockFd, msgLenBytes, MSG_HEADER_LEN); if (retVal == MSG_HEADER_LEN) { - retVal = ::write(mCurSockFd, data.data(), data.size()); + retVal = ::write(mSockFd, data.data(), data.size()); } } return retVal; } - } // impl } // namespace V2_0 diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h index 12cfb29b8a..88b852bb33 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h @@ -18,8 +18,9 @@ #define android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_ #include <mutex> +#include <thread> #include <vector> -#include "CommBase.h" +#include "CommConn.h" namespace android { namespace hardware { @@ -29,29 +30,60 @@ namespace V2_0 { namespace impl { +class SocketConn; + /** - * SocketComm opens a socket via adb's TCP port forwarding to enable a Host PC to connect to - * the VehicleHAL. + * SocketComm opens a socket, and listens for connections from clients. Typically the client will be + * adb's TCP port-forwarding to enable a host PC to connect to the VehicleHAL. */ -class SocketComm : public CommBase { -public: - SocketComm(); +class SocketComm { + public: + SocketComm(MessageProcessor* messageProcessor); virtual ~SocketComm(); + void start(); + void stop(); + + /** + * Serialized and send the given message to all connected clients. + */ + void sendMessage(emulator::EmulatorMessage const& msg); + + private: + int mListenFd; + std::unique_ptr<std::thread> mListenThread; + std::vector<std::unique_ptr<SocketConn>> mOpenConnections; + MessageProcessor* mMessageProcessor; + std::mutex mMutex; + /** - * Creates a connection to the other side. + * Opens the socket and begins listening. * - * @return int Returns fd or socket number if connection is successful. - * Otherwise, returns -1 if no connection is availble. + * @return bool Returns true on success. */ - int connect() override; + bool listen(); /** - * Opens a socket and begins listening. + * Blocks and waits for a connection from a client, returns a new SocketConn with the connection + * or null, if the connection has been closed. * - * @return int Returns 0 on success. + * @return int Returns fd or socket number if connection is successful. + * Otherwise, returns -1 if no connection is availble. */ - int open() override; + SocketConn* accept(); + + void listenThread(); + + void removeClosedConnections(); +}; + +/** + * SocketConn represents a single connection to a client. + */ +class SocketConn : public CommConn { + public: + SocketConn(MessageProcessor* messageProcessor, int sfd); + virtual ~SocketConn() = default; /** * Blocking call to read data from the connection. @@ -75,10 +107,9 @@ public: */ int write(const std::vector<uint8_t>& data) override; -private: - int mCurSockFd; - std::atomic<int> mExit; - std::mutex mMutex; + inline bool isOpen() override { return mSockFd > 0; } + + private: int mSockFd; }; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp index bf7be09afc..356a6b9568 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp @@ -16,9 +16,10 @@ #define LOG_TAG "VehicleEmulator_v2_0" #include <android/log.h> -#include <algorithm> #include <android-base/properties.h> +#include <log/log.h> #include <utils/SystemClock.h> +#include <algorithm> #include <vhal_v2_0/VehicleUtils.h> @@ -35,32 +36,45 @@ namespace V2_0 { namespace impl { -std::unique_ptr<CommBase> CommFactory::create() { - bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false); +VehicleEmulator::VehicleEmulator(EmulatedVehicleHalIface* hal) : mHal{hal} { + mHal->registerEmulator(this); + + ALOGI("Starting SocketComm"); + mSocketComm = std::make_unique<SocketComm>(this); + mSocketComm->start(); - if (isEmulator) { - return std::make_unique<PipeComm>(); - } else { - return std::make_unique<SocketComm>(); + if (android::base::GetBoolProperty("ro.kernel.qemu", false)) { + ALOGI("Starting PipeComm"); + mPipeComm = std::make_unique<PipeComm>(this); + mPipeComm->start(); } } VehicleEmulator::~VehicleEmulator() { - mExit = true; // Notify thread to finish and wait for it to terminate. - mComm->stop(); // Close emulator socket if it is open. - if (mThread.joinable()) mThread.join(); + mSocketComm->stop(); + if (mPipeComm) { + mPipeComm->stop(); + } } +/** + * This is called by the HAL when a property changes. We need to notify our clients that it has + * changed. + */ void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) { emulator::EmulatorMessage msg; emulator::VehiclePropValue *val = msg.add_value(); populateProtoVehiclePropValue(val, &propValue); msg.set_status(emulator::RESULT_OK); msg.set_msg_type(emulator::SET_PROPERTY_ASYNC); - txMsg(msg); + + mSocketComm->sendMessage(msg); + if (mPipeComm) { + mPipeComm->sendMessage(msg); + } } -void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage& rxMsg, +void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage const& rxMsg, VehicleEmulator::EmulatorMessage& respMsg) { std::vector<VehiclePropConfig> configs = mHal->listProperties(); emulator::VehiclePropGet getProp = rxMsg.prop(0); @@ -79,7 +93,7 @@ void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage& rxMsg, } } -void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage& /* rxMsg */, +void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */, VehicleEmulator::EmulatorMessage& respMsg) { std::vector<VehiclePropConfig> configs = mHal->listProperties(); @@ -92,8 +106,8 @@ void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage& /* rxMsg } } -void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage& rxMsg, - VehicleEmulator::EmulatorMessage& respMsg) { +void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMsg, + VehicleEmulator::EmulatorMessage& respMsg) { int32_t areaId = 0; emulator::VehiclePropGet getProp = rxMsg.prop(0); int32_t propId = getProp.prop(); @@ -119,8 +133,8 @@ void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage& rxMsg, respMsg.set_status(status); } -void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage& /* rxMsg */, - VehicleEmulator::EmulatorMessage& respMsg) { +void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */, + VehicleEmulator::EmulatorMessage& respMsg) { respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP); respMsg.set_status(emulator::RESULT_OK); @@ -132,7 +146,7 @@ void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage& /* rxMs } } -void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage& rxMsg, +void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMsg, VehicleEmulator::EmulatorMessage& respMsg) { emulator::VehiclePropValue protoVal = rxMsg.value(0); VehiclePropValue val = { @@ -173,58 +187,28 @@ void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage& rxMsg, respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY); } -void VehicleEmulator::txMsg(emulator::EmulatorMessage& txMsg) { - int numBytes = txMsg.ByteSize(); - std::vector<uint8_t> msg(static_cast<size_t>(numBytes)); - - if (!txMsg.SerializeToArray(msg.data(), static_cast<int32_t>(msg.size()))) { - ALOGE("%s: SerializeToString failed!", __func__); - return; - } - - if (mExit) { - ALOGW("%s: unable to transmit a message, connection closed", __func__); - return; - } - - // Send the message - int retVal = mComm->write(msg); - if (retVal < 0) { - ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno); - } -} - -void VehicleEmulator::parseRxProtoBuf(std::vector<uint8_t>& msg) { - emulator::EmulatorMessage rxMsg; - emulator::EmulatorMessage respMsg; - - if (rxMsg.ParseFromArray(msg.data(), static_cast<int32_t>(msg.size()))) { - switch (rxMsg.msg_type()) { - case emulator::GET_CONFIG_CMD: - doGetConfig(rxMsg, respMsg); - break; - case emulator::GET_CONFIG_ALL_CMD: - doGetConfigAll(rxMsg, respMsg); - break; - case emulator::GET_PROPERTY_CMD: - doGetProperty(rxMsg, respMsg); - break; - case emulator::GET_PROPERTY_ALL_CMD: - doGetPropertyAll(rxMsg, respMsg); - break; - case emulator::SET_PROPERTY_CMD: - doSetProperty(rxMsg, respMsg); - break; - default: - ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type()); - respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD); - break; - } - - // Send the reply - txMsg(respMsg); - } else { - ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size())); +void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg, + emulator::EmulatorMessage& respMsg) { + switch (rxMsg.msg_type()) { + case emulator::GET_CONFIG_CMD: + doGetConfig(rxMsg, respMsg); + break; + case emulator::GET_CONFIG_ALL_CMD: + doGetConfigAll(rxMsg, respMsg); + break; + case emulator::GET_PROPERTY_CMD: + doGetProperty(rxMsg, respMsg); + break; + case emulator::GET_PROPERTY_ALL_CMD: + doGetPropertyAll(rxMsg, respMsg); + break; + case emulator::SET_PROPERTY_CMD: + doSetProperty(rxMsg, respMsg); + break; + default: + ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type()); + respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD); + break; } } @@ -316,40 +300,6 @@ void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* } } -void VehicleEmulator::rxMsg() { - while (!mExit) { - std::vector<uint8_t> msg = mComm->read(); - - if (msg.size() > 0) { - // Received a message. - parseRxProtoBuf(msg); - } else { - // This happens when connection is closed - ALOGD("%s: msgSize=%zu", __func__, msg.size()); - break; - } - } -} - -void VehicleEmulator::rxThread() { - if (mExit) return; - - int retVal = mComm->open(); - if (retVal != 0) mExit = true; - - // Comms are properly opened - while (!mExit) { - retVal = mComm->connect(); - - if (retVal >= 0) { - rxMsg(); - } - - // Check every 100ms for a new connection - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } -} - } // impl } // namespace V2_0 diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h index 1a8cfe2c48..58e387a749 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h @@ -24,7 +24,9 @@ #include "vhal_v2_0/VehicleHal.h" -#include "CommBase.h" +#include "CommConn.h" +#include "PipeComm.h" +#include "SocketComm.h" #include "VehicleHalProto.pb.h" namespace android { @@ -61,48 +63,36 @@ private: VehicleEmulator* mEmulator; }; -struct CommFactory { - static std::unique_ptr<CommBase> create(); -}; - /** * Emulates vehicle by providing controlling interface from host side either through ADB or Pipe. */ -class VehicleEmulator { -public: - VehicleEmulator(EmulatedVehicleHalIface* hal, - std::unique_ptr<CommBase> comm = CommFactory::create()) - : mHal { hal }, - mComm(comm.release()), - mThread { &VehicleEmulator::rxThread, this} { - mHal->registerEmulator(this); - } +class VehicleEmulator : public MessageProcessor { + public: + VehicleEmulator(EmulatedVehicleHalIface* hal); virtual ~VehicleEmulator(); void doSetValueFromClient(const VehiclePropValue& propValue); + void processMessage(emulator::EmulatorMessage const& rxMsg, + emulator::EmulatorMessage& respMsg) override; -private: + private: + friend class ConnectionThread; using EmulatorMessage = emulator::EmulatorMessage; - void doGetConfig(EmulatorMessage& rxMsg, EmulatorMessage& respMsg); - void doGetConfigAll(EmulatorMessage& rxMsg, EmulatorMessage& respMsg); - void doGetProperty(EmulatorMessage& rxMsg, EmulatorMessage& respMsg); - void doGetPropertyAll(EmulatorMessage& rxMsg, EmulatorMessage& respMsg); - void doSetProperty(EmulatorMessage& rxMsg, EmulatorMessage& respMsg); - void txMsg(emulator::EmulatorMessage& txMsg); - void parseRxProtoBuf(std::vector<uint8_t>& msg); + void doGetConfig(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); + void doGetConfigAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); + void doGetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); + void doGetPropertyAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); + void doSetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg); void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg); void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, const VehiclePropValue* val); - void rxMsg(); - void rxThread(); private: - std::atomic<bool> mExit { false }; EmulatedVehicleHalIface* mHal; - std::unique_ptr<CommBase> mComm; - std::thread mThread; + std::unique_ptr<SocketComm> mSocketComm; + std::unique_ptr<PipeComm> mPipeComm; }; } // impl diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 57179dfd67..e874146edf 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -131,6 +131,9 @@ enum VehiclePropertyGroup : int32_t { * When a property's status field is not set to AVAILABLE: * - IVehicle#set may return StatusCode::NOT_AVAILABLE. * - IVehicle#get is not guaranteed to work. + * + * Properties set to values out of range must be ignored and no action taken + * in response to such ill formed requests. */ enum VehicleProperty : int32_t { @@ -243,7 +246,7 @@ enum VehicleProperty : int32_t { * Fuel door location * * @change_mode VehiclePropertyChangeMode:STATIC - * @data_enum FuelDoorLocationType + * @data_enum PortLocationType * @access VehiclePropertyAccess:READ */ INFO_FUEL_DOOR_LOCATION = ( @@ -267,6 +270,7 @@ enum VehicleProperty : int32_t { /** * Driver's seat location + * VHAL implementations must ignore the areaId. Use VehicleArea:GLOBAL. * * @change_mode VehiclePropertyChangeMode:STATIC * @data_enum VehicleAreaSeat @@ -306,6 +310,37 @@ enum VehicleProperty : int32_t { | VehicleArea:GLOBAL), /** + * Speed of the vehicle for displays + * + * Some cars display a slightly slower speed than the actual speed. This is + * usually displayed on the speedometer. + * + * @change_mode VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:METER_PER_SEC + */ + PERF_VEHICLE_SPEED_DISPLAY = ( + 0x0208 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /** + * Steering angle of the vehicle + * + * Angle is in degrees. Left is negative. + * + * @change_mode VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:DEGREES + */ + PERF_STEERING_ANGLE = ( + 0x0209 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /** * Temperature of engine coolant * * @change_mode VehiclePropertyChangeMode:CONTINUOUS @@ -587,7 +622,13 @@ enum VehicleProperty : int32_t { * * This property corresponds to the low fuel warning on the dashboard. * Once FUEL_LEVEL_LOW is set, it should not be cleared until more fuel is - * added to the vehicle. + * added to the vehicle. This property may take into account all fuel + * sources for a vehicle - for example: + * + * For a gas powered vehicle, this property is based soley on gas level. + * For a battery powered vehicle, this property is based solely on battery level. + * For a hybrid vehicle, this property may be based on the combination of gas and battery + * levels, at the OEM's discretion. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ @@ -1088,7 +1129,7 @@ enum VehicleProperty : int32_t { /** * Property to control power state of application processor * - * It is assumed that AP's power state is controller by separate power + * 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 @@ -1099,7 +1140,7 @@ enum VehicleProperty : int32_t { * 0 if not used. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VEHICLE_PROP_ACCESS_READ + * @access VehiclePropertyAccess:READ */ AP_POWER_STATE_REQ = ( 0x0A00 @@ -1118,7 +1159,7 @@ enum VehicleProperty : int32_t { * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VEHICLE_PROP_ACCESS_WRITE + * @access VehiclePropertyAccess:WRITE */ AP_POWER_STATE_REPORT = ( 0x0A01 @@ -2230,17 +2271,8 @@ enum VehicleApPowerStateConfigFlag : int32_t /* NOTE: type is guessed */ { }; enum VehicleApPowerStateReq : int32_t { - /** vehicle HAL will never publish this state to AP */ - OFF = 0, - - /** vehicle HAL will never publish this state to AP */ - DEEP_SLEEP = 1, - - /** AP is on but display must be off. */ - ON_DISP_OFF = 2, - - /** AP is on with display on. This state allows full user interaction. */ - ON_FULL = 3, + /** Transition Android from WAIT_FOR_VHAL to ON state */ + ON = 0, /** * The power controller has requested AP to shutdown. AP can either enter @@ -2250,8 +2282,16 @@ enum VehicleApPowerStateReq : int32_t { * system. * * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type + * + * SHUTDOWN_PRPARE may be requested from either WAIT_FOR_VHAL or ON states. */ - SHUTDOWN_PREPARE = 4, + SHUTDOWN_PREPARE = 1, + + /** Cancel the shutdown and transition from SHUTDOWN_PREPARE to WAIT_FOR_VHAL state */ + CANCEL_SHUTDOWN = 2, + + /** VHAL is finished with shutdown procedures and ready for Android to suspend/shutdown */ + FINISHED = 3, }; /** @@ -2277,26 +2317,30 @@ enum VehicleApPowerStateShutdownParam : int32_t { enum VehicleApPowerStateReport : int32_t { /** - * AP has finished boot up, and can start shutdown if requested by power - * controller. + * Device has booted, CarService has initialized and is ready to accept commands from VHAL. + * Device starts in WAIT_FOR_VHAL state. The user is not logged in, and vendor apps/services + * are expected to control the display and audio. */ - BOOT_COMPLETE = 0x1, + WAIT_FOR_VHAL = 0x1, /** - * AP is entering deep sleep state. How this state is implemented may vary - * depending on each H/W, but AP's power must be kept in this state. + * AP is ready to suspend and has entered WAIT_FOR_FINISHED state. + * + * int32Values[1]: Time to turn on AP in secs. Power controller may turn on + * AP after specified time so that AP can run tasks like + * update. If it is set to 0, there is no wake up, and power + * controller may not necessarily support wake-up. */ DEEP_SLEEP_ENTRY = 0x2, /** - * AP is exiting from deep sleep state, and is in - * VehicleApPowerState#SHUTDOWN_PREPARE state. - * The power controller may change state to other ON states based on the - * current state. + * AP is exiting from deep sleep state, and is in WAIT_FOR_VHAL state. */ DEEP_SLEEP_EXIT = 0x3, /** + * AP remains in SHUTDOWN_PREPARE state as idle and cleanup tasks execute. + * * int32Values[1]: Time to postpone shutdown in ms. Maximum value can be * 5000 ms. * If AP needs more time, it will send another POSTPONE @@ -2305,63 +2349,31 @@ enum VehicleApPowerStateReport : int32_t { SHUTDOWN_POSTPONE = 0x4, /** - * AP is starting shutting down. When system completes shutdown, everything - * will stop in AP as kernel will stop all other contexts. It is - * responsibility of vehicle HAL or lower level to synchronize that state - * with external power controller. As an example, some kind of ping - * with timeout in power controller can be a solution. + * AP is ready to shutdown and has entered WAIT_FOR_FINISHED state. * * int32Values[1]: Time to turn on AP in secs. Power controller may turn on * AP after specified time so that AP can run tasks like * update. If it is set to 0, there is no wake up, and power - * controller may not necessarily support wake-up. If power - * controller turns on AP due to timer, it must start with - * VehicleApPowerState#ON_DISP_OFF state, and after - * receiving VehicleApPowerSetState#BOOT_COMPLETE, it shall - * do state transition to - * VehicleApPowerState#SHUTDOWN_PREPARE. + * controller may not necessarily support wake-up. */ SHUTDOWN_START = 0x5, /** - * User has requested to turn off headunit's display, which is detected in - * android side. - * The power controller may change the power state to - * VehicleApPowerState#ON_DISP_OFF. + * AP has transitioned from WAIT_FOR_VHAL state to ON. */ - DISPLAY_OFF = 0x6, + ON = 0x6, /** - * User has requested to turn on headunit's display, most probably from power - * key input which is attached to headunit. The power controller may change - * the power state to VehicleApPowerState#ON_FULL. - */ - DISPLAY_ON = 0x7, -}; - -/** - * Enum to represent bootup reason. - */ -enum VehicleApPowerBootupReason : int32_t { - /** - * Power on due to user's pressing of power key or rotating of ignition - * switch. + * AP has transitions to SHUTDOWN_PREPARE state. In this state, Garage Mode will execute idle + * tasks, and other services that have registered for this state transition may execute + * cleanup activities. */ - USER_POWER_ON = 0, + SHUTDOWN_PREPARE = 0x7, /** - * Automatic power on triggered by door unlock or any other kind of automatic - * user detection. + * AP has transitioned from SHUTDOWN_PREPARE state to WAIT_FOR_VHAL. */ - USER_UNLOCK = 1, - - /** - * Automatic power on triggered by timer. This only happens when AP has asked - * wake-up after - * certain time through time specified in - * VehicleApPowerSetState#SHUTDOWN_START. - */ - TIMER = 2, + SHUTDOWN_CANCELLED = 0x8, }; enum VehicleHwKeyInputAction : int32_t { @@ -2399,13 +2411,15 @@ enum VehicleUnit : int32_t { NANO_SECS = 0x50, SECS = 0x53, YEAR = 0x59, - KILOPASCAL = 0x70, // Electrical Units WATT_HOUR = 0x60, MILLIAMPERE = 0x61, MILLIVOLT = 0x62, MILLIWATTS = 0x63, + + KILOPASCAL = 0x70, + DEGREES = 0x80, }; /** diff --git a/biometrics/face/1.0/Android.bp b/biometrics/face/1.0/Android.bp new file mode 100644 index 0000000000..45dbad9d3a --- /dev/null +++ b/biometrics/face/1.0/Android.bp @@ -0,0 +1,27 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.biometrics.face@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IBiometricsFace.hal", + "IBiometricsFaceClientCallback.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + types: [ + "FaceAcquiredInfo", + "FaceError", + "OptionalBool", + "OptionalUint64", + "Status", + "UserHandle", + ], + gen_java: true, +} + diff --git a/biometrics/face/1.0/IBiometricsFace.hal b/biometrics/face/1.0/IBiometricsFace.hal new file mode 100644 index 0000000000..e3c256a2bf --- /dev/null +++ b/biometrics/face/1.0/IBiometricsFace.hal @@ -0,0 +1,252 @@ +/* + * 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. + */ + +package android.hardware.biometrics.face@1.0; + +import IBiometricsFaceClientCallback; + +// TODO(b/78538290): Update comments with state machine transitions when ready. +// TODO(b/78537981): Update comments with callback interaction contract. +// TODO(b/79496983): Update comments with status returns fully enumerated. +/** + * The HAL interface for biometric face authentication. + */ +interface IBiometricsFace { + + /** + * Sets the current client callback. + * + * Registers a user function that must receive notifications from the HAL. + * There is usually only one client (FaceService). This call must block + * if the HAL state machine is in busy state until the HAL leaves the + * busy state. + * + * All callback methods pass a deviceId to differentiate callback + * invocations in the case where multiple sensors exist. + * + * @param clientCallback The client defined callback to register. + * @return result, with its "value" parameter representing a "deviceId", + * which must be unique for a given sensor. + */ + @callflow(next={"setActiveUser"}) + @entry + setCallback(IBiometricsFaceClientCallback clientCallback) + generates (OptionalUint64 result); + + /** + * Sets the active user, which all subsequent HAL operations are applied to. + * + * HAL service implementors must ensure that operations are restricted to + * the given user. Clients must not call any part of this interface, except + * for setCallback(), without first having set an active user. The + * implementation is responsible for cancelling the current operation and + * returning to the idle state. Calling this method with the same userId + * should have no effect on the state machine. + * + * @param userId A non-negative user identifier that must be unique and + * persistent for a given user. + * @param storePath filesystem path to the template storage directory. + */ + @callflow(next={"authenticate", "generateChallenge", "enumerate", "remove"}) + setActiveUser(int32_t userId, string storePath) generates (Status status); + + /** + * Begins a secure transaction request, e.g. enrollment. + * + * Generates a unique and cryptographically secure random token used to + * indicate the start of a secure transaction. generateChallenge() and + * revokeChallenge() specify a pin/pattern/password cleared time window where + * the secure transaction is allowed. + * + * generateChallenge() generates a challenge which must then be wrapped by the + * gatekeeper after verifying a successful strong authentication attempt, + * which generates a Hardware Authentication Token. The challenge prevents + * spoofing and replay attacks and ensures that we only update a user’s face + * template if the operation was preceded by some kind of strong credential + * confirmation (e.g. device password). + * + * @param challengeTimeoutSec A timeout in seconds, after which the driver + * must invalidate the challenge. This is to prevent bugs or crashes in + * the system from leaving a challenge enabled indefinitely. + * @return result, with its "value" parameter representing a "challenge": a + * unique and cryptographically secure random token. + */ + @callflow(next={"enroll", "revokeChallenge", "setFeatureDisabled"}) + generateChallenge(uint32_t challengeTimeoutSec) + generates (OptionalUint64 result); + + /** + * Enrolls a user's face. + * + * Note that this interface permits implementations where multiple faces can + * be enrolled for a single user. However, allowing multiple faces to be + * enrolled can be a severe security vulnerability and hence, most + * implementations must ensure that only a single face be enrolled at a + * given time. Multi-enrollment must only be used where there is a clear + * necessity for a shared use case, e.g. TVs or cars. + * + * Note that the Hardware Authentication Token must still be valid after + * this call, and must be explicitly invalidated by a call to + * revokeChallenge(). This allows clients to immediately reattempt + * enrollment (for example, if a user wasn’t satisfied with their enrollment) + * without having to go through another strong authentication flow. + * + * This method triggers the IBiometricsFaceClientCallback#onEnrollResult() + * method. + * + * @param hat A valid Hardware Authentication Token, generated as a result + * of a generateChallenge() challenge being wrapped by the gatekeeper + * after a sucessful strong authentication request. + * @param timeoutSec A timeout in seconds, after which this enrollment + * attempt is cancelled. Note that the client still needs to + * call revokeChallenge() to terminate the enrollment session. + * @param disabledFeatures A list of features to be disabled during + * enrollment. Note that all features are enabled by default. + * @return status The status of this method call. + */ + @callflow(next={"cancel", "enroll", "revokeChallenge", "remove"}) + enroll(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures) + generates (Status status); + + /** + * Finishes the secure transaction by invalidating the challenge generated + * by generateChallenge(). + * + * Clients must call this method once enrollment is complete, and the user's + * face template no longer needs to be updated. + * + * @return status The status of this method call. + */ + @callflow(next={"authenticate", "setActiveUser", "enumerate", "remove"}) + revokeChallenge() generates (Status status); + + /** + * Requires all subsequent enroll/authenticate calls to use the feature. + * This method does not affect enroll, which has its own feature list. + * + * Changes the state of previous enrollment setting. Because this may + * decrease security, the user must enter their password before this method + * is invoked (see @param HAT). The driver must verify the HAT before + * changing any feature state. + * Note: In some cases it may not be possible to change the state of this + * flag without re-enrolling. For example, if the user didn't provide + * attention during the original enrollment. This flag reflects the same + * persistent state as the one passed to enroll(). + * + * @param feature The feature to be enabled or disabled. + * @param enabled True to enable the feature, false to disable. + * @param hat A valid Hardware Authentication Token, generated as a result + * of getChallenge(). + * @return status The status of this method call. + */ + setFeature(Feature feature, bool enabled, vec<uint8_t> hat) + generates(Status status); + + /** + * Retrieves the current state of the feature. + * + * @return enabled True if the feature is enabled, false if disabled. + */ + getFeature(Feature feature) generates (bool enabled); + + /** + * Returns an identifier associated with the current face set. + * + * The authenticator ID must change whenever a new face is enrolled. The + * authenticator ID must not be changed when a face is deleted. The + * authenticator ID must be an entropy-encoded random number which all + * current templates are tied to. The authenticator ID must be immutable + * outside of an active enrollment window to prevent replay attacks. + * + * @return result, with its value parameter representing an + * "authenticatorId": an identifier associated to the user's current + * face enrollment. + */ + @callflow(next={"authenticate"}) + getAuthenticatorId() generates (OptionalUint64 result); + + /** + * Cancels a pending enrollment or authentication request. + * + * @return status The status of this method call. + */ + @callflow(next={"authenticate", "enroll", "enumerate", "remove", + "setActiveUser"}) + cancel() generates (Status status); + + /** + * Enumerates all face templates associated with the active user. + * + * The onEnumerate() callback method is invoked once for each face template + * found. + * + * @return status The status of this method call. + */ + @callflow(next={"remove", "enroll", "authenticate", "setActiveUser"}) + enumerate() generates (Status status); + + /** + * Removes a face template or all face templates associated with the active + * user. + * + * This method triggers the IBiometricsFaceClientCallback#onRemoved() method. + * + * @param faceId The id correpsonding to the face to be removed; or 0 if all + * faces are to be removed. + * @return status The status of this method call. + */ + @callflow(next={"enumerate", "authenticate", "cancel", "getAuthenticatorId", + "setActiveUser"}) + remove(uint32_t faceId) generates (Status status); + + /** + * Authenticates the active user. + * + * An optional operationId can be specified as a token from the transaction + * being authorized. The hardware may enter a standby state during + * authentication, where the device is idle to conserve power while + * authenticating, e.g. after 3 seconds without finding a face. See + * IBiometricsFace#userActivity() for more info. + * + * @param operationId A non-zero operation id associated with a crypto + * object instance; or 0 if not being used. + * @return status The status of this method call. + */ + @callflow(next={"cancel", "generateChallenge", "remove"}) + authenticate(uint64_t operationId) generates (Status status); + + /** + * A hint to the HAL to continue looking for faces. + * + * This method should only be used when the HAL is in the authenticating + * or standby state. Using this method when the HAL is not in one of the + * mentioned states must return OPERATION_NOT_SUPPORTED. Calling this + * method while the HAL is already authenticating may extend the duration + * where it's looking for a face. + * + * @return status The status of this method call. + */ + userActivity() generates (Status status); + + /** + * Reset lockout for the current user. + * + * @param hat A valid Hardware Authentication Token, generated when the + * user authenticates with Pin/Pattern/Pass. + * @return true if lockout was reset, false otherwise. + */ + resetLockout(vec<uint8_t> hat) generates (bool success); +}; diff --git a/biometrics/face/1.0/IBiometricsFaceClientCallback.hal b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal new file mode 100644 index 0000000000..93848c57bb --- /dev/null +++ b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal @@ -0,0 +1,116 @@ +/* + * 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. + */ + +package android.hardware.biometrics.face@1.0; + +/** + * This callback interface is used by clients to recieve updates from the face + * HAL. + */ +interface IBiometricsFaceClientCallback { + + /** + * A callback invoked when one enrollment step has been completed. + * + * @param deviceId A unique id associated with the HAL implementation + * service that processed this enrollment step. + * @param faceId The id of the face template being enrolled. + * @param userId The active user id for the template being enrolled. + * @param remaining The number of remaining steps before enrolllment is + * complete or 0 if enrollment has completed successfully. + */ + oneway onEnrollResult(uint64_t deviceId, uint32_t faceId, int32_t userId, + uint32_t remaining); + + /** + * A callback invoked when a face has been successfully authenticated. + * + * @param deviceId A unique id associated with the HAL implementation + * service that processed this autentication attempt. + * @param faceId The id of the face template that passed the authentication + * challenge. + * @param userId The active user id for the authenticated face. + * @param token The hardware authentication token associated with this + * authenticate operation. + */ + oneway onAuthenticated(uint64_t deviceId, uint32_t faceId, int32_t userId, + vec<uint8_t> token); + + /** + * A callback invoked when a face is acquired. + * + * If a non-critical, recoverable error occurs during an enrollment or + * authentication attempt, the HAL implementation must invoke this callback + * to allow clients to inform the user that some actionable change must be + * made. + * + * @param deviceId A unique id associated with the HAL implementation + * service that acquired a face. + * @param userId The id of the active user associated with the attempted + * face acquisition. + * @param acquiredInfo A message about the quality of the acquired image. + * @param vendorCode An optional vendor-specific message. This is only valid + * when acquiredInfo == FaceAcquiredInfo.VENDOR. This message is opaque + * to the framework, and vendors must provide code to handle it. For + * example this can be used to guide enrollment in Settings or provide + * a message during authentication that is vendor-specific. The vendor + * is expected to provide help strings to cover all known values. + */ + oneway onAcquired(uint64_t deviceId, int32_t userId, + FaceAcquiredInfo acquiredInfo, int32_t vendorCode); + + /** + * A callback invoked when an error has occured. + * + * @param deviceId A unique id associated with the HAL implementation + * service where this error occured. + * @param userId The id of the active user when the error occured, or + * UserHandle::NONE if an active user had not been set yet. + * @param error A message about the error that occurred. + * @param vendorCode An optional, vendor-speicifc error message. Only valid + * when error == FaceError.VENDOR. This message is opaque to the + * framework, and vendors must provide code to handle it. For example, + * this scan be used to show the user an error message specific to the + * device. The vendor is expected to provide error strings to cover + * all known values. + */ + oneway onError(uint64_t deviceId, int32_t userId, FaceError error, + int32_t vendorCode); + + /** + * A callback invoked when a face template has been removed. + * + * @param deviceId A unique id associated with the HAL implementation + * service that processed this removal. + * @param faceId The id of the face template that was removed. + * @param userId The active user id for the removed face template. + * @param remaining The number of face templates remaining after this + * removal, or 0 if there are no more. + */ + oneway onRemoved(uint64_t deviceId, uint32_t faceId, int32_t userId, + uint32_t remaining); + + /** + * A callback invoked to enumerate all current face templates. + * + * @param deviceId A unique id associated with the HAL implementation + * service that processed this enumeration. + * @param faceIds A list of ids of all currently enrolled face templates. + * @param userId The active user id for the enumerated face template. + */ + oneway onEnumerate(uint64_t deviceId, vec<uint32_t> faceIds, + int32_t userId); +}; diff --git a/biometrics/face/1.0/types.hal b/biometrics/face/1.0/types.hal new file mode 100644 index 0000000000..89e809b3f7 --- /dev/null +++ b/biometrics/face/1.0/types.hal @@ -0,0 +1,372 @@ +/* + * 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. + */ + +package android.hardware.biometrics.face@1.0; + +/* + * In the event setActiveUser is not called, all error messages will return + * this userId. + */ +enum UserHandle : int32_t { + NONE = -1 +}; + +/** + * Status codes returned directly by the HIDL method calls upon critical errors + * where the callback cannot be invoked. Most errors should sent through the + * onError callback using one of the FaceErrors below. + */ +enum Status : uint32_t { + /** + * The method was invoked successfully. + */ + OK = 0, + + /** + * One of the arguments to the method call is invalid. + */ + ILLEGAL_ARGUMENT = 1, + + /** + * This face HAL does not support this operation. + */ + OPERATION_NOT_SUPPORTED = 2, + + /** + * The HAL has encountered an internal error and cannot complete the request. + */ + INTERNAL_ERROR = 3, + + /** + * The operation could not be completed because there are no enrolled + * templates. + */ + NOT_ENROLLED = 4 +}; + +enum Feature : uint32_t { + /** + * Require the user to look at the device during enrollment and + * authentication. Note this is to accommodate people who have limited + * vision. Must be enabled by default. + */ + REQUIRE_ATTENTION = 1, + + /** + * Require a diverse set of poses during enrollment. Note this is to + * accommodate people with limited mobility. Must be enabled by default. + */ + REQUIRE_DIVERSITY = 2 +}; + +/** + * Face errors represent events that can't be immediately recovered by user + * intervention. These are returned in the onError callback. + * + * Upon receiving a face error, clients must terminate the current operation and + * notify the user where possible. + */ +enum FaceError : int32_t { + + /** + * A hardware error has occured that cannot be resolved. Try again later. + */ + HW_UNAVAILABLE = 1, + + /** + * The current enroll or authenticate operation could not be completed; + * the sensor was unable to process the current image. + */ + UNABLE_TO_PROCESS = 2, + + /** + * The current operation took too long to complete. This is intended to + * prevent programs from blocking the face HAL indefinitely. The timeout is + * framework and sensor-specific, but is generally on the order of 30 + * seconds. + */ + TIMEOUT = 3, + + /** + * The current operation could not be completed because there is not enough + * storage space remaining to do so. + */ + NO_SPACE = 4, + + /** + * The current operation has been cancelled. This may happen if a new + * request (authenticate, remove) is initiated while an on-going operation + * is in progress, or if cancel() was called. + */ + CANCELED = 5, + + /** + * The current remove operation could not be completed; the face template + * provided could not be removed. + */ + UNABLE_TO_REMOVE = 6, + + /** + * Face authentication is locked out due to too many unsuccessful attempts. + * This is a "soft" lockout, and authentication can be restarted after + * a period of time, generally on the order of 30 seconds. + */ + LOCKOUT = 7, + + /** + * Used to enable a vendor-specific error message. + */ + VENDOR = 8, + + /** + * Face authentication is disabled until the user unlocks with strong + * authentication (PIN/Pattern/Password). + */ + LOCKOUT_PERMANENT = 9 +}; + +/** + * Face acquisition information provides feedback for the current enrollment + * or authentication operation. + * + * This information indicates that the user can take immediate action to resolve + * an issue, and clients must ensure that this information is surfaced to the + * user. + */ +enum FaceAcquiredInfo : int32_t { + + /** + * The face acquired was good; no further user interaction is necessary. + */ + GOOD = 0, + + /** + * The face data acquired was too noisy or did not have sufficient detail. + * This is a catch-all for all acquisition errors not captured by the other + * constants. + */ + INSUFFICIENT = 1, + + /** + * Because there was too much ambient light, the captured face data was too + * bright. It's reasonable to return this after multiple + * FaceAcquiredInfo.INSUFFICIENT. + * + * The user is expected to take action to retry the operation in better + * lighting conditions when this is returned. + */ + TOO_BRIGHT = 2, + + /** + * Because there was not enough illumination, the captured face data was too + * dark. It's reasonable to return this after multiple + * FaceAcquiredInfo.INSUFFICIENT. + * + * The user is expected to take action to retry the operation in better + * lighting conditions when this is returned. + */ + TOO_DARK = 3, + + /** + * The detected face is too close to the sensor, and the image cannot be + * processed. + * + * The user is expected to be informed to move further from the sensor when + * this is returned. + */ + TOO_CLOSE = 4, + + /** + * The detected face is too small, as the user might be too far away from + * the sensor. + * + * The user is expected to be informed to move closer to the sensor when + * this is returned. + */ + TOO_FAR = 5, + + /** + * Only the upper part of the face was detected. The sensor's field of view + * is too high. + * + * The user should be informed to move up with respect to the sensor when + * this is returned. + */ + FACE_TOO_HIGH = 6, + + /** + * Only the lower part of the face was detected. The sensor's field of view + * is too low. + * + * The user should be informed to move down with respect to the sensor when + * this is returned. + */ + FACE_TOO_LOW = 7, + + /** + * Only the right part of the face was detected. The sensor's field of view + * is too far right. + * + * The user should be informed to move to the right with respect to the + * sensor when this is returned. + */ + FACE_TOO_RIGHT = 8, + + /** + * Only the left part of the face was detected. The sensor's field of view + * is too far left. + * + * The user should be informed to move to the left with respect to the + * sensor when this is returned. + */ + FACE_TOO_LEFT = 9, + + /** + * The user's eyes have strayed away from the sensor. If this message is + * sent, the user should be informed to look at the device. If the user + * can't be found in the frame, one of the other acquisition messages + * must be sent, e.g. NOT_DETECTED. + */ + POOR_GAZE = 10, + + /** + * No face was detected within the sensor's field of view. + * + * The user should be informed to point the sensor to a face when this is + * returned. + */ + NOT_DETECTED = 11, + + /** + * Too much motion was detected. + * + * The user should be informed to keep their face steady relative to the + * sensor. + */ + TOO_MUCH_MOTION = 12, + + /** + * The sensor needs to be re-calibrated. This is an unexpected condition, + * and must only be sent if a serious, uncorrectable, and unrecoverable + * calibration issue is detected which requires user intervention, e.g. + * re-enrolling. The expected response to this message is to direct the + * user to re-enroll. + */ + RECALIBRATE = 13, + + /** + * The face is too different from a previous acquisition. This condition + * only applies to enrollment. This can happen if the user passes the + * device to someone else in the middle of enrollment. + */ + TOO_DIFFERENT = 14, + + /** + * The face is too similar to a previous acquisition. This condition only + * applies to enrollment. The user should change their pose. + */ + TOO_SIMILAR = 15, + + /** + * The magnitude of the pan angle of the user’s face with respect to the sensor’s + * capture plane is too high. + * + * The pan angle is defined as the angle swept out by the user’s face turning + * their neck left and right. The pan angle would be zero if the user faced the + * camera directly. + * + * The user should be informed to look more directly at the camera. + */ + PAN_TOO_EXTREME = 16, + + /** + * The magnitude of the tilt angle of the user’s face with respect to the sensor’s + * capture plane is too high. + * + * The tilt angle is defined as the angle swept out by the user’s face looking up + * and down. The pan angle would be zero if the user faced the camera directly. + * + * The user should be informed to look more directly at the camera. + */ + TILT_TOO_EXTREME = 17, + + /** + * The magnitude of the roll angle of the user’s face with respect to the sensor’s + * capture plane is too high. + * + * The roll angle is defined as the angle swept out by the user’s face tilting their head + * towards their shoulders to the left and right. The pan angle would be zero if the user + * faced the camera directly. + * + * The user should be informed to look more directly at the camera. + */ + ROLL_TOO_EXTREME = 18, + + /** + * The user’s face has been obscured by some object. + * + * The user should be informed to remove any objects from the line of sight from + * the sensor to the user’s face. + */ + FACE_OBSCURED = 19, + + /** + * This message represents the earliest message sent at the beginning of the authentication + * pipeline. It is expected to be used to measure latency. For example, in a camera-based + * authentication system it's expected to be sent prior to camera initialization. Note this + * should be sent whenever authentication is restarted (see IBiometricsFace#userActivity). + * The framework will measure latency based on the time between the last START message and the + * onAuthenticated callback. + */ + START = 20, + + /** + * Used to enable a vendor-specific acquisition message. + */ + VENDOR = 21 +}; + +/** + * Result structure with an additional uint64_t field. See documentation in + * setCallback(), preEnroll(), and getAuthenticatorId() for usage of the value. + */ +struct OptionalUint64 { + /** + * The return status. + */ + Status status; + + /** + * This value is only meaningful if status is OK. + */ + uint64_t value; +}; + +/** + * Result structure with an addition bool field. See documentation in + * getRequireAttention() for usage of the value. + */ +struct OptionalBool { + /** + * The return status. + */ + Status status; + + /** + * This value is only meaningful if status is OK. + */ + bool value; +};
\ No newline at end of file diff --git a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc index 9bfd3bac6e..1667677bfe 100644 --- a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc +++ b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc @@ -4,5 +4,5 @@ service vendor.fps_hal /vendor/bin/hw/android.hardware.biometrics.fingerprint@2. # /data is mounted. class late_start user system - group system input - writepid /dev/cpuset/system-background/tasks
\ No newline at end of file + group system input uhid + writepid /dev/cpuset/system-background/tasks diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp index 90fbb3f279..beb9a3eaff 100644 --- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp +++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp @@ -105,6 +105,9 @@ using ::android::hardware::bluetooth::V1_0::Status; (ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE \ << ACL_PACKET_BOUNDARY_FLAG_OFFSET) +// To be removed in VTS release builds +#define ACL_HANDLE_QCA_DEBUG_MESSAGE 0xedc + constexpr char kCallbackNameAclEventReceived[] = "aclDataReceived"; constexpr char kCallbackNameHciEventReceived[] = "hciEventReceived"; constexpr char kCallbackNameInitializationComplete[] = "initializationComplete"; @@ -318,6 +321,19 @@ void BluetoothHidlTest::handle_no_ops() { break; } } + // To be removed in VTS release builds + while (acl_queue.size() > 0) { + hidl_vec<uint8_t> acl_packet = acl_queue.front(); + uint16_t connection_handle = acl_packet[1] & 0xF; + connection_handle <<= 8; + connection_handle |= acl_packet[0]; + bool packet_is_no_op = connection_handle == ACL_HANDLE_QCA_DEBUG_MESSAGE; + if (packet_is_no_op) { + acl_queue.pop(); + } else { + break; + } + } } // Receive an event, discarding NO-OPs. diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp index 900454e78b..840c4b864e 100644 --- a/broadcastradio/2.0/default/Android.bp +++ b/broadcastradio/2.0/default/Android.bp @@ -43,7 +43,6 @@ cc_binary { "libbase", "libhidlbase", "libhidltransport", - "liblog", "libutils", ], } diff --git a/broadcastradio/2.0/default/BroadcastRadio.cpp b/broadcastradio/2.0/default/BroadcastRadio.cpp index 0148fecc48..28a0dd504a 100644 --- a/broadcastradio/2.0/default/BroadcastRadio.cpp +++ b/broadcastradio/2.0/default/BroadcastRadio.cpp @@ -13,15 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "BcRadioDef.module" -#define LOG_NDEBUG 0 - #include "BroadcastRadio.h" -#include <log/log.h> - #include "resources.h" +#include <android-base/logging.h> + namespace android { namespace hardware { namespace broadcastradio { @@ -66,7 +63,6 @@ BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio) mAmFmConfig(gDefaultAmFmConfig) {} Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) { - ALOGV("%s", __func__); _hidl_cb(mProperties); return {}; } @@ -77,8 +73,6 @@ AmFmRegionConfig BroadcastRadio::getAmFmConfig() const { } Return<void> BroadcastRadio::getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb) { - ALOGV("%s(%d)", __func__, full); - if (full) { AmFmRegionConfig config = {}; config.ranges = hidl_vec<AmFmBandRange>({ @@ -96,8 +90,6 @@ Return<void> BroadcastRadio::getAmFmRegionConfig(bool full, getAmFmRegionConfig_ } Return<void> BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb) { - ALOGV("%s", __func__); - hidl_vec<DabTableEntry> config = { {"5A", 174928}, {"7D", 194064}, {"8A", 195936}, {"8B", 197648}, {"9A", 202928}, {"9B", 204640}, {"9C", 206352}, {"10B", 211648}, {"10C", 213360}, {"10D", 215072}, @@ -111,7 +103,7 @@ Return<void> BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb) Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback, openSession_cb _hidl_cb) { - ALOGV("%s", __func__); + LOG(DEBUG) << "opening new session..."; /* For the needs of default implementation it's fine to instantiate new session object * out of the lock scope. If your implementation needs it, use reentrant lock. @@ -122,7 +114,7 @@ Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback, auto oldSession = mSession.promote(); if (oldSession != nullptr) { - ALOGI("Closing previously opened tuner"); + LOG(INFO) << "closing previously opened tuner"; oldSession->close(); mSession = nullptr; } @@ -134,14 +126,14 @@ Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback, } Return<void> BroadcastRadio::getImage(uint32_t id, getImage_cb _hidl_cb) { - ALOGV("%s(%x)", __func__, id); + LOG(DEBUG) << "fetching image " << std::hex << id; if (id == resources::demoPngId) { _hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng))); return {}; } - ALOGI("Image %x doesn't exists", id); + LOG(INFO) << "image " << std::hex << id << " doesn't exists"; _hidl_cb({}); return {}; } @@ -149,7 +141,7 @@ Return<void> BroadcastRadio::getImage(uint32_t id, getImage_cb _hidl_cb) { Return<void> BroadcastRadio::registerAnnouncementListener( const hidl_vec<AnnouncementType>& enabled, const sp<IAnnouncementListener>& /* listener */, registerAnnouncementListener_cb _hidl_cb) { - ALOGV("%s(%s)", __func__, toString(enabled).c_str()); + LOG(DEBUG) << "registering announcement listener for " << toString(enabled); _hidl_cb(Result::NOT_SUPPORTED, nullptr); return {}; diff --git a/broadcastradio/2.0/default/TunerSession.cpp b/broadcastradio/2.0/default/TunerSession.cpp index da9756208f..2ba4d02092 100644 --- a/broadcastradio/2.0/default/TunerSession.cpp +++ b/broadcastradio/2.0/default/TunerSession.cpp @@ -14,15 +14,12 @@ * limitations under the License. */ -#define LOG_TAG "BcRadioDef.tuner" -#define LOG_NDEBUG 0 - #include "TunerSession.h" #include "BroadcastRadio.h" +#include <android-base/logging.h> #include <broadcastradio-utils-2x/Utils.h> -#include <log/log.h> namespace android { namespace hardware { @@ -68,7 +65,7 @@ static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) { } void TunerSession::tuneInternalLocked(const ProgramSelector& sel) { - ALOGV("%s(%s)", __func__, toString(sel).c_str()); + LOG(VERBOSE) << "tune (internal) to " << toString(sel); VirtualProgram virtualProgram; ProgramInfo programInfo; @@ -93,17 +90,18 @@ const VirtualRadio& TunerSession::virtualRadio() const { } Return<Result> TunerSession::tune(const ProgramSelector& sel) { - ALOGV("%s(%s)", __func__, toString(sel).c_str()); + LOG(DEBUG) << "tune to " << toString(sel); + lock_guard<mutex> lk(mMut); if (mIsClosed) return Result::INVALID_STATE; if (!utils::isSupported(module().mProperties, sel)) { - ALOGW("Selector not supported"); + LOG(WARNING) << "selector not supported: " << toString(sel); return Result::NOT_SUPPORTED; } if (!utils::isValid(sel)) { - ALOGE("ProgramSelector is not valid"); + LOG(ERROR) << "selector is not valid: " << toString(sel); return Result::INVALID_ARGUMENTS; } @@ -119,8 +117,9 @@ Return<Result> TunerSession::tune(const ProgramSelector& sel) { return Result::OK; } -Return<Result> TunerSession::scan(bool directionUp, bool /* skipSubChannel */) { - ALOGV("%s", __func__); +Return<Result> TunerSession::scan(bool directionUp, bool skipSubChannel) { + LOG(DEBUG) << "seek up=" << directionUp << " skipSubChannel=" << skipSubChannel; + lock_guard<mutex> lk(mMut); if (mIsClosed) return Result::INVALID_STATE; @@ -130,8 +129,8 @@ Return<Result> TunerSession::scan(bool directionUp, bool /* skipSubChannel */) { if (list.empty()) { mIsTuneCompleted = false; - auto task = [this, directionUp]() { - ALOGI("Performing failed seek up=%d", directionUp); + auto task = [this]() { + LOG(DEBUG) << "program list is empty, seek couldn't stop"; mCallback->onTuneFailed(Result::TIMEOUT, {}); }; @@ -162,7 +161,7 @@ Return<Result> TunerSession::scan(bool directionUp, bool /* skipSubChannel */) { mIsTuneCompleted = false; auto task = [this, tuneTo, directionUp]() { - ALOGI("Performing seek up=%d", directionUp); + LOG(VERBOSE) << "executing seek up=" << directionUp; lock_guard<mutex> lk(mMut); tuneInternalLocked(tuneTo); @@ -173,21 +172,21 @@ Return<Result> TunerSession::scan(bool directionUp, bool /* skipSubChannel */) { } Return<Result> TunerSession::step(bool directionUp) { - ALOGV("%s", __func__); + LOG(DEBUG) << "step up=" << directionUp; lock_guard<mutex> lk(mMut); if (mIsClosed) return Result::INVALID_STATE; cancelLocked(); if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) { - ALOGE("Can't step in anything else than AM/FM"); + LOG(WARNING) << "can't step in anything else than AM/FM"; return Result::NOT_SUPPORTED; } auto stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY); auto range = getAmFmRangeLocked(); if (!range) { - ALOGE("Can't find current band"); + LOG(ERROR) << "can't find current band"; return Result::INTERNAL_ERROR; } @@ -201,7 +200,7 @@ Return<Result> TunerSession::step(bool directionUp) { mIsTuneCompleted = false; auto task = [this, stepTo]() { - ALOGI("Performing step to %s", std::to_string(stepTo).c_str()); + LOG(VERBOSE) << "executing step to " << stepTo; lock_guard<mutex> lk(mMut); @@ -213,7 +212,7 @@ Return<Result> TunerSession::step(bool directionUp) { } void TunerSession::cancelLocked() { - ALOGV("%s", __func__); + LOG(VERBOSE) << "cancelling current operations..."; mThread.cancelAll(); if (utils::getType(mCurrentProgram.primaryId) != IdentifierType::INVALID) { @@ -222,7 +221,6 @@ void TunerSession::cancelLocked() { } Return<void> TunerSession::cancel() { - ALOGV("%s", __func__); lock_guard<mutex> lk(mMut); if (mIsClosed) return {}; @@ -232,7 +230,7 @@ Return<void> TunerSession::cancel() { } Return<Result> TunerSession::startProgramListUpdates(const ProgramFilter& filter) { - ALOGV("%s(%s)", __func__, toString(filter).c_str()); + LOG(DEBUG) << "requested program list updates, filter=" << toString(filter); lock_guard<mutex> lk(mMut); if (mIsClosed) return Result::INVALID_STATE; @@ -259,41 +257,37 @@ Return<Result> TunerSession::startProgramListUpdates(const ProgramFilter& filter } Return<void> TunerSession::stopProgramListUpdates() { - ALOGV("%s", __func__); + LOG(DEBUG) << "requested program list updates to stop"; return {}; } Return<void> TunerSession::isConfigFlagSet(ConfigFlag flag, isConfigFlagSet_cb _hidl_cb) { - ALOGV("%s(%s)", __func__, toString(flag).c_str()); + LOG(VERBOSE) << __func__ << " " << toString(flag); _hidl_cb(Result::NOT_SUPPORTED, false); return {}; } Return<Result> TunerSession::setConfigFlag(ConfigFlag flag, bool value) { - ALOGV("%s(%s, %d)", __func__, toString(flag).c_str(), value); + LOG(VERBOSE) << __func__ << " " << toString(flag) << " " << value; return Result::NOT_SUPPORTED; } Return<void> TunerSession::setParameters(const hidl_vec<VendorKeyValue>& /* parameters */, setParameters_cb _hidl_cb) { - ALOGV("%s", __func__); - _hidl_cb({}); return {}; } Return<void> TunerSession::getParameters(const hidl_vec<hidl_string>& /* keys */, getParameters_cb _hidl_cb) { - ALOGV("%s", __func__); - _hidl_cb({}); return {}; } Return<void> TunerSession::close() { - ALOGV("%s", __func__); + LOG(DEBUG) << "closing session..."; lock_guard<mutex> lk(mMut); if (mIsClosed) return {}; @@ -304,7 +298,7 @@ Return<void> TunerSession::close() { std::optional<AmFmBandRange> TunerSession::getAmFmRangeLocked() const { if (!mIsTuneCompleted) { - ALOGW("tune operation in process"); + LOG(WARNING) << "tune operation is in process"; return {}; } if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) return {}; diff --git a/broadcastradio/2.0/default/VirtualProgram.cpp b/broadcastradio/2.0/default/VirtualProgram.cpp index acde704f9b..a971927610 100644 --- a/broadcastradio/2.0/default/VirtualProgram.cpp +++ b/broadcastradio/2.0/default/VirtualProgram.cpp @@ -13,15 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "BcRadioDef.VirtualProgram" - #include "VirtualProgram.h" #include "resources.h" #include <android-base/logging.h> #include <broadcastradio-utils-2x/Utils.h> -#include <log/log.h> namespace android { namespace hardware { @@ -72,7 +69,7 @@ VirtualProgram::operator ProgramInfo() const { info.physicallyTunedTo = selectId(IdentifierType::SXM_CHANNEL); break; default: - LOG(FATAL) << "Unsupported program type: " << toString(pType); + LOG(FATAL) << "unsupported program type: " << toString(pType); } info.infoFlags |= ProgramInfoFlags::TUNED; diff --git a/broadcastradio/2.0/default/VirtualRadio.cpp b/broadcastradio/2.0/default/VirtualRadio.cpp index f601d41637..0b65979b76 100644 --- a/broadcastradio/2.0/default/VirtualRadio.cpp +++ b/broadcastradio/2.0/default/VirtualRadio.cpp @@ -13,13 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "BcRadioDef.VirtualRadio" -//#define LOG_NDEBUG 0 - #include "VirtualRadio.h" #include <broadcastradio-utils-2x/Utils.h> -#include <log/log.h> namespace android { namespace hardware { diff --git a/broadcastradio/2.0/default/service.cpp b/broadcastradio/2.0/default/service.cpp index 7e677a1323..af96dad47f 100644 --- a/broadcastradio/2.0/default/service.cpp +++ b/broadcastradio/2.0/default/service.cpp @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "BcRadioDef.service" - #include <android-base/logging.h> #include <hidl/HidlTransportSupport.h> @@ -26,7 +24,9 @@ using android::hardware::joinRpcThreadpool; using android::hardware::broadcastradio::V2_0::implementation::BroadcastRadio; using android::hardware::broadcastradio::V2_0::implementation::gAmFmRadio; -int main(int /* argc */, char** /* argv */) { +int main() { + android::base::SetDefaultTag("BcRadioDef"); + android::base::SetMinimumLogSeverity(android::base::VERBOSE); configureRpcThreadpool(4, true); BroadcastRadio broadcastRadio(gAmFmRadio); diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp index 3d7039dc9b..e36f4d9050 100644 --- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp +++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "BcRadio.vts" -#define LOG_NDEBUG 0 #define EGMOCK_VERBOSE 1 #include <VtsHalHidlTargetTestBase.h> @@ -446,7 +444,7 @@ TEST_F(BroadcastRadioHalTest, FmTune) { EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune); - ALOGD("current program info: %s", toString(infoCb).c_str()); + LOG(DEBUG) << "current program info: " << toString(infoCb); // it should tune exactly to what was requested auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY); @@ -514,12 +512,12 @@ TEST_F(BroadcastRadioHalTest, Seek) { // TODO(b/69958777): see FmTune workaround std::this_thread::sleep_for(gTuneWorkaround); - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _); + EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _).Times(AnyNumber()); auto result = mSession->scan(true /* up */, true /* skip subchannel */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune); - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _); + EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _).Times(AnyNumber()); result = mSession->scan(false /* down */, false /* don't skip subchannel */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune); @@ -548,7 +546,7 @@ TEST_F(BroadcastRadioHalTest, Step) { EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune); - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _); + EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _).Times(AnyNumber()); result = mSession->step(false /* down */); EXPECT_EQ(Result::OK, result); EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune); @@ -823,11 +821,11 @@ int main(int argc, char** argv) { using android::hardware::broadcastradio::V2_0::vts::gEnv; using android::hardware::broadcastradio::V2_0::IBroadcastRadio; using android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment; + android::base::SetDefaultTag("BcRadio.vts"); + android::base::SetMinimumLogSeverity(android::base::VERBOSE); gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadio>; ::testing::AddGlobalTestEnvironment(gEnv); ::testing::InitGoogleTest(&argc, argv); gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; + return RUN_ALL_TESTS(); } diff --git a/broadcastradio/common/utils/Android.bp b/broadcastradio/common/utils/Android.bp index 33ba7da22f..32e06d7bdf 100644 --- a/broadcastradio/common/utils/Android.bp +++ b/broadcastradio/common/utils/Android.bp @@ -29,7 +29,6 @@ cc_library_static { export_include_dirs: ["include"], shared_libs: [ "libbase", - "liblog", "libutils", ], } diff --git a/broadcastradio/common/utils/WorkerThread.cpp b/broadcastradio/common/utils/WorkerThread.cpp index bfcbb390e8..31f4d3f83e 100644 --- a/broadcastradio/common/utils/WorkerThread.cpp +++ b/broadcastradio/common/utils/WorkerThread.cpp @@ -14,13 +14,8 @@ * limitations under the License. */ -#define LOG_TAG "WorkerThread" -//#define LOG_NDEBUG 0 - #include <broadcastradio-utils/WorkerThread.h> -#include <log/log.h> - namespace android { using std::chrono::milliseconds; @@ -39,7 +34,6 @@ bool operator<(const WorkerThread::Task& lhs, const WorkerThread::Task& rhs) { WorkerThread::WorkerThread() : mIsTerminating(false), mThread(&WorkerThread::threadLoop, this) {} WorkerThread::~WorkerThread() { - ALOGV("%s", __func__); { lock_guard<mutex> lk(mMut); mIsTerminating = true; @@ -49,8 +43,6 @@ WorkerThread::~WorkerThread() { } void WorkerThread::schedule(function<void()> task, milliseconds delay) { - ALOGV("%s", __func__); - auto when = steady_clock::now() + delay; lock_guard<mutex> lk(mMut); @@ -59,14 +51,11 @@ void WorkerThread::schedule(function<void()> task, milliseconds delay) { } void WorkerThread::cancelAll() { - ALOGV("%s", __func__); - lock_guard<mutex> lk(mMut); priority_queue<Task>().swap(mTasks); // empty queue } void WorkerThread::threadLoop() { - ALOGV("%s", __func__); while (!mIsTerminating) { unique_lock<mutex> lk(mMut); if (mTasks.empty()) { diff --git a/broadcastradio/common/utils2x/Utils.cpp b/broadcastradio/common/utils2x/Utils.cpp index f292c0855f..789265328f 100644 --- a/broadcastradio/common/utils2x/Utils.cpp +++ b/broadcastradio/common/utils2x/Utils.cpp @@ -14,12 +14,10 @@ * limitations under the License. */ #define LOG_TAG "BcRadioDef.utils" -//#define LOG_NDEBUG 0 #include <broadcastradio-utils-2x/Utils.h> #include <android-base/logging.h> -#include <log/log.h> namespace android { namespace hardware { @@ -130,7 +128,7 @@ bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) { case IdentifierType::SXM_SERVICE_ID: return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID); default: // includes all vendor types - ALOGW("Unsupported program type: %s", toString(type).c_str()); + LOG(WARNING) << "unsupported program type: " << toString(type); return false; } } @@ -166,7 +164,7 @@ uint64_t getId(const ProgramSelector& sel, const IdentifierType type) { return val; } - ALOGW("Identifier %s not found", toString(type).c_str()); + LOG(WARNING) << "identifier not found: " << toString(type); return 0; } @@ -205,7 +203,7 @@ bool isValid(const ProgramIdentifier& id) { auto expect = [&valid](bool condition, std::string message) { if (!condition) { valid = false; - ALOGE("Identifier not valid, expected %s", message.c_str()); + LOG(ERROR) << "identifier not valid, expected " << message; } }; diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h index 1f716f1bce..f6cd6aed4a 100644 --- a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h +++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h @@ -29,7 +29,7 @@ * INTERNAL IMPLEMENTATION - don't use in user code. */ #if EGMOCK_VERBOSE -#define EGMOCK_LOG_(...) ALOGV("egmock: " __VA_ARGS__) +#define EGMOCK_LOG_(...) LOG(VERBOSE) << "egmock: " << __VA_ARGS__ #else #define EGMOCK_LOG_(...) #endif diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp index dc4e0f01ff..08354b312d 100644 --- a/camera/common/1.0/default/CameraModule.cpp +++ b/camera/common/1.0/default/CameraModule.cpp @@ -235,7 +235,7 @@ void CameraModule::appendAvailableKeys(CameraMetadata &chars, chars.update(keyTag, availableKeys); } -CameraModule::CameraModule(camera_module_t *module) { +CameraModule::CameraModule(camera_module_t *module) : mNumberOfCameras(0) { if (module == NULL) { ALOGE("%s: camera hardware module must not be null", __FUNCTION__); assert(0); @@ -264,7 +264,8 @@ int CameraModule::init() { res = mModule->init(); ATRACE_END(); } - mCameraInfoMap.setCapacity(getNumberOfCameras()); + mNumberOfCameras = getNumberOfCameras(); + mCameraInfoMap.setCapacity(mNumberOfCameras); return res; } @@ -319,6 +320,45 @@ int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { return OK; } +int CameraModule::getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo) { + ATRACE_CALL(); + Mutex::Autolock lock(mCameraInfoLock); + if (physicalCameraId < mNumberOfCameras) { + ALOGE("%s: Invalid physical camera ID %d", __FUNCTION__, physicalCameraId); + return -EINVAL; + } + + // Only query physical camera info for 2.5 version for newer + 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__); + return -ENODEV; + } + if (mModule->get_physical_camera_info == nullptr) { + ALOGE("%s: get_physical_camera is NULL for module version 2.5", __FUNCTION__); + return -EINVAL; + } + + ssize_t index = mPhysicalCameraInfoMap.indexOfKey(physicalCameraId); + if (index == NAME_NOT_FOUND) { + // Get physical camera characteristics, and cache it + camera_metadata_t *info = nullptr; + ATRACE_BEGIN("camera_module->get_physical_camera_info"); + int ret = mModule->get_physical_camera_info(physicalCameraId, &info); + ATRACE_END(); + if (ret != 0) { + return ret; + } + + index = mPhysicalCameraInfoMap.add(physicalCameraId, info); + } + + assert(index != NAME_NOT_FOUND); + *physicalInfo = mPhysicalCameraInfoMap[index]; + return OK; +} + int CameraModule::getDeviceVersion(int cameraId) { ssize_t index = mDeviceVersionMap.indexOfKey(cameraId); if (index == NAME_NOT_FOUND) { @@ -412,6 +452,16 @@ int CameraModule::setTorchMode(const char* camera_id, bool enable) { return res; } +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"); + res = mModule->is_stream_combination_supported(cameraId, streams); + ATRACE_END(); + } + return res; +} + status_t CameraModule::filterOpenErrorCode(status_t err) { switch(err) { case NO_ERROR: @@ -426,8 +476,8 @@ status_t CameraModule::filterOpenErrorCode(status_t err) { } void CameraModule::removeCamera(int cameraId) { - free_camera_metadata( - const_cast<camera_metadata_t*>(mCameraInfoMap[cameraId].static_camera_characteristics)); + free_camera_metadata(const_cast<camera_metadata_t*>( + mCameraInfoMap.valueFor(cameraId).static_camera_characteristics)); mCameraInfoMap.removeItem(cameraId); mDeviceVersionMap.removeItem(cameraId); } diff --git a/camera/common/1.0/default/OWNERS b/camera/common/1.0/default/OWNERS index 18acfee145..369b2048cb 100644 --- a/camera/common/1.0/default/OWNERS +++ b/camera/common/1.0/default/OWNERS @@ -1,6 +1,7 @@ cychen@google.com epeev@google.com etalvala@google.com +jchowdhary@google.com shuzhenwang@google.com yinchiayeh@google.com zhijunhe@google.com diff --git a/camera/common/1.0/default/VendorTagDescriptor.cpp b/camera/common/1.0/default/VendorTagDescriptor.cpp index 052bf5be60..d2bee85daf 100644 --- a/camera/common/1.0/default/VendorTagDescriptor.cpp +++ b/camera/common/1.0/default/VendorTagDescriptor.cpp @@ -176,6 +176,93 @@ void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const { } +int VendorTagDescriptorCache::getTagCount(metadata_vendor_id_t id) const { + int ret = 0; + auto desc = mVendorMap.find(id); + if (desc != mVendorMap.end()) { + ret = desc->second->getTagCount(); + } else { + ALOGE("%s: Vendor descriptor id is missing!", __func__); + } + + return ret; +} + +void VendorTagDescriptorCache::getTagArray(uint32_t* tagArray, metadata_vendor_id_t id) const { + auto desc = mVendorMap.find(id); + if (desc != mVendorMap.end()) { + desc->second->getTagArray(tagArray); + } else { + ALOGE("%s: Vendor descriptor id is missing!", __func__); + } +} + +const char* VendorTagDescriptorCache::getSectionName(uint32_t tag, metadata_vendor_id_t id) const { + const char* ret = nullptr; + auto desc = mVendorMap.find(id); + if (desc != mVendorMap.end()) { + ret = desc->second->getSectionName(tag); + } else { + ALOGE("%s: Vendor descriptor id is missing!", __func__); + } + + return ret; +} + +const char* VendorTagDescriptorCache::getTagName(uint32_t tag, metadata_vendor_id_t id) const { + const char* ret = nullptr; + auto desc = mVendorMap.find(id); + if (desc != mVendorMap.end()) { + ret = desc->second->getTagName(tag); + } else { + ALOGE("%s: Vendor descriptor id is missing!", __func__); + } + + return ret; +} + +int VendorTagDescriptorCache::getTagType(uint32_t tag, metadata_vendor_id_t id) const { + int ret = 0; + auto desc = mVendorMap.find(id); + if (desc != mVendorMap.end()) { + ret = desc->second->getTagType(tag); + } else { + ALOGE("%s: Vendor descriptor id is missing!", __func__); + } + + return ret; +} + +void VendorTagDescriptorCache::dump(int fd, int verbosity, int indentation) const { + for (const auto& desc : mVendorMap) { + desc.second->dump(fd, verbosity, indentation); + } +} + +int32_t VendorTagDescriptorCache::addVendorDescriptor( + metadata_vendor_id_t id, sp<hardware::camera::common::V1_0::helper::VendorTagDescriptor> desc) { + auto entry = mVendorMap.find(id); + if (entry != mVendorMap.end()) { + ALOGE("%s: Vendor descriptor with same id already present!", __func__); + return BAD_VALUE; + } + + mVendorMap.emplace(id, desc); + return NO_ERROR; +} + +int32_t VendorTagDescriptorCache::getVendorTagDescriptor( + metadata_vendor_id_t id, + sp<hardware::camera::common::V1_0::helper::VendorTagDescriptor>* desc /*out*/) { + auto entry = mVendorMap.find(id); + if (entry == mVendorMap.end()) { + return NAME_NOT_FOUND; + } + + *desc = entry->second; + + return NO_ERROR; +} } // namespace params } // namespace camera2 @@ -192,10 +279,17 @@ static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag); static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag); +static int vendor_tag_descriptor_cache_get_tag_count(metadata_vendor_id_t id); +static void vendor_tag_descriptor_cache_get_all_tags(uint32_t* tagArray, metadata_vendor_id_t id); +static const char* vendor_tag_descriptor_cache_get_section_name(uint32_t tag, + metadata_vendor_id_t id); +static const char* vendor_tag_descriptor_cache_get_tag_name(uint32_t tag, metadata_vendor_id_t id); +static int vendor_tag_descriptor_cache_get_tag_type(uint32_t tag, metadata_vendor_id_t id); } /* extern "C" */ static Mutex sLock; static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor; +static sp<VendorTagDescriptorCache> sGlobalVendorTagDescriptorCache; status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps, /*out*/ @@ -310,6 +404,39 @@ sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() { return sGlobalVendorTagDescriptor; } +status_t VendorTagDescriptorCache::setAsGlobalVendorTagCache( + const sp<VendorTagDescriptorCache>& cache) { + status_t res = OK; + Mutex::Autolock al(sLock); + sGlobalVendorTagDescriptorCache = cache; + + struct vendor_tag_cache_ops* opsPtr = NULL; + if (cache != NULL) { + opsPtr = &(cache->mVendorCacheOps); + opsPtr->get_tag_count = vendor_tag_descriptor_cache_get_tag_count; + opsPtr->get_all_tags = vendor_tag_descriptor_cache_get_all_tags; + opsPtr->get_section_name = vendor_tag_descriptor_cache_get_section_name; + opsPtr->get_tag_name = vendor_tag_descriptor_cache_get_tag_name; + opsPtr->get_tag_type = vendor_tag_descriptor_cache_get_tag_type; + } + if ((res = set_camera_metadata_vendor_cache_ops(opsPtr)) != OK) { + ALOGE("%s: Could not set vendor tag cache, received error %s (%d).", __FUNCTION__, + strerror(-res), res); + } + return res; +} + +void VendorTagDescriptorCache::clearGlobalVendorTagCache() { + Mutex::Autolock al(sLock); + set_camera_metadata_vendor_cache_ops(NULL); + sGlobalVendorTagDescriptorCache.clear(); +} + +sp<VendorTagDescriptorCache> VendorTagDescriptorCache::getGlobalVendorTagCache() { + Mutex::Autolock al(sLock); + return sGlobalVendorTagDescriptorCache; +} + extern "C" { int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* /*v*/) { @@ -357,6 +484,50 @@ int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* /*v*/, uint32_t t return sGlobalVendorTagDescriptor->getTagType(tag); } +int vendor_tag_descriptor_cache_get_tag_count(metadata_vendor_id_t id) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptorCache == NULL) { + ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__); + return VENDOR_TAG_COUNT_ERR; + } + return sGlobalVendorTagDescriptorCache->getTagCount(id); +} + +void vendor_tag_descriptor_cache_get_all_tags(uint32_t* tagArray, metadata_vendor_id_t id) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptorCache == NULL) { + ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__); + } + sGlobalVendorTagDescriptorCache->getTagArray(tagArray, id); +} + +const char* vendor_tag_descriptor_cache_get_section_name(uint32_t tag, metadata_vendor_id_t id) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptorCache == NULL) { + ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__); + return VENDOR_SECTION_NAME_ERR; + } + return sGlobalVendorTagDescriptorCache->getSectionName(tag, id); +} + +const char* vendor_tag_descriptor_cache_get_tag_name(uint32_t tag, metadata_vendor_id_t id) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptorCache == NULL) { + ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__); + return VENDOR_TAG_NAME_ERR; + } + return sGlobalVendorTagDescriptorCache->getTagName(tag, id); +} + +int vendor_tag_descriptor_cache_get_tag_type(uint32_t tag, metadata_vendor_id_t id) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptorCache == NULL) { + ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__); + return VENDOR_TAG_NAME_ERR; + } + return sGlobalVendorTagDescriptorCache->getTagType(tag, id); +} + } /* extern "C" */ } // namespace helper diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h index deebd09480..ee75e722d1 100644 --- a/camera/common/1.0/default/include/CameraModule.h +++ b/camera/common/1.0/default/include/CameraModule.h @@ -65,6 +65,8 @@ public: 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); private: // Derive camera characteristics keys defined after HAL device version @@ -74,8 +76,10 @@ private: int32_t keyTag, const Vector<int32_t>& appendKeys); status_t filterOpenErrorCode(status_t err); camera_module_t *mModule; + int mNumberOfCameras; KeyedVector<int, camera_info> mCameraInfoMap; KeyedVector<int, int> mDeviceVersionMap; + KeyedVector<int, camera_metadata_t*> mPhysicalCameraInfoMap; Mutex mCameraInfoLock; }; diff --git a/camera/common/1.0/default/include/VendorTagDescriptor.h b/camera/common/1.0/default/include/VendorTagDescriptor.h index a040540edb..0f54db52d1 100644 --- a/camera/common/1.0/default/include/VendorTagDescriptor.h +++ b/camera/common/1.0/default/include/VendorTagDescriptor.h @@ -157,6 +157,81 @@ class VendorTagDescriptor : }; +} /* namespace helper */ +} /* namespace V1_0 */ +} /* namespace common */ +} /* namespace camera */ + +namespace camera2 { +namespace params { + +class VendorTagDescriptorCache { + public: + typedef android::hardware::camera::common::V1_0::helper::VendorTagDescriptor + VendorTagDescriptor; + VendorTagDescriptorCache(){}; + int32_t addVendorDescriptor(metadata_vendor_id_t id, sp<VendorTagDescriptor> desc); + + int32_t getVendorTagDescriptor(metadata_vendor_id_t id, sp<VendorTagDescriptor>* desc /*out*/); + + // Returns the number of vendor tags defined. + int getTagCount(metadata_vendor_id_t id) const; + + // Returns an array containing the id's of vendor tags defined. + void getTagArray(uint32_t* tagArray, metadata_vendor_id_t id) const; + + // Returns the section name string for a given vendor tag id. + const char* getSectionName(uint32_t tag, metadata_vendor_id_t id) const; + + // Returns the tag name string for a given vendor tag id. + const char* getTagName(uint32_t tag, metadata_vendor_id_t id) const; + + // Returns the tag type for a given vendor tag id. + int getTagType(uint32_t tag, metadata_vendor_id_t id) const; + + /** + * Dump the currently configured vendor tags to a file descriptor. + */ + void dump(int fd, int verbosity, int indentation) const; + + protected: + std::unordered_map<metadata_vendor_id_t, sp<VendorTagDescriptor>> mVendorMap; + struct vendor_tag_cache_ops mVendorCacheOps; +}; + +} /* namespace params */ +} /* namespace camera2 */ + +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { + +class VendorTagDescriptorCache + : public ::android::hardware::camera2::params::VendorTagDescriptorCache, + public LightRefBase<VendorTagDescriptorCache> { + public: + /** + * Sets the global vendor tag descriptor cache to use for this process. + * Camera metadata operations that access vendor tags will use the + * vendor tag definitions set this way. + * + * Returns OK on success, or a negative error code. + */ + static status_t setAsGlobalVendorTagCache(const sp<VendorTagDescriptorCache>& cache); + + /** + * Returns the global vendor tag cache used by this process. + * This will contain NULL if no vendor tags are defined. + */ + static sp<VendorTagDescriptorCache> getGlobalVendorTagCache(); + + /** + * Clears the global vendor tag cache used by this process. + */ + static void clearGlobalVendorTagCache(); +}; + } // namespace helper } // namespace V1_0 } // namespace common diff --git a/camera/device/1.0/default/OWNERS b/camera/device/1.0/default/OWNERS index 18acfee145..369b2048cb 100644 --- a/camera/device/1.0/default/OWNERS +++ b/camera/device/1.0/default/OWNERS @@ -1,6 +1,7 @@ cychen@google.com epeev@google.com etalvala@google.com +jchowdhary@google.com shuzhenwang@google.com yinchiayeh@google.com zhijunhe@google.com diff --git a/camera/device/3.2/ICameraDevice.hal b/camera/device/3.2/ICameraDevice.hal index 1f523e420d..5236bb1cd8 100644 --- a/camera/device/3.2/ICameraDevice.hal +++ b/camera/device/3.2/ICameraDevice.hal @@ -148,7 +148,9 @@ interface ICameraDevice { * session handle for active operations. * * @param callback Interface to invoke by the HAL for device asynchronous - * events. + * events. For HALs newer than version 3.2, HAL must use castFrom + * method to check the exact version of callback sent by camera service. + * * @return status Status code for the operation, one of: * OK: * On a successful open of the camera device. diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal index e62dc072cd..278be5d091 100644 --- a/camera/device/3.2/ICameraDeviceSession.hal +++ b/camera/device/3.2/ICameraDeviceSession.hal @@ -149,9 +149,8 @@ interface ICameraDeviceSession { * - Including too many output streams of a certain format. * - Unsupported rotation configuration * - Stream sizes/formats don't satisfy the - * camera3_stream_configuration_t->operation_mode requirements - * for non-NORMAL mode, or the requested operation_mode is not - * supported by the HAL. + * StreamConfigurationMode requirements for non-NORMAL mode, or + * the requested operation_mode is not supported by the HAL. * - Unsupported usage flag * The camera service cannot filter out all possible illegal stream * configurations, since some devices may support more simultaneous diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp index 297e7781e6..4f85b58cf9 100644 --- a/camera/device/3.2/default/CameraDevice.cpp +++ b/camera/device/3.2/default/CameraDevice.cpp @@ -101,7 +101,7 @@ Status CameraDevice::getHidlStatus(int status) { } // Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. -Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { +Return<void> CameraDevice::getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb) { Status status = initStatus(); CameraResourceCost resCost; if (status == Status::OK) { @@ -141,7 +141,8 @@ Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { return Void(); } -Return<void> CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) { +Return<void> CameraDevice::getCameraCharacteristics( + ICameraDevice::getCameraCharacteristics_cb _hidl_cb) { Status status = initStatus(); CameraMetadata cameraCharacteristics; if (status == Status::OK) { @@ -172,7 +173,8 @@ Return<Status> CameraDevice::setTorchMode(TorchMode mode) { return status; } -Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) { +Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, + ICameraDevice::open_cb _hidl_cb) { Status status = initStatus(); sp<CameraDeviceSession> session = nullptr; diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp index fd785df1a9..f2d7a47e83 100644 --- a/camera/device/3.2/default/CameraDeviceSession.cpp +++ b/camera/device/3.2/default/CameraDeviceSession.cpp @@ -44,13 +44,15 @@ static constexpr int METADATA_SHRINK_ABS_THRESHOLD = 4096; static constexpr int METADATA_SHRINK_REL_THRESHOLD = 2; HandleImporter CameraDeviceSession::sHandleImporter; +buffer_handle_t CameraDeviceSession::sEmptyBuffer = nullptr; + const int CameraDeviceSession::ResultBatcher::NOT_BATCHED; CameraDeviceSession::CameraDeviceSession( camera3_device_t* device, const camera_metadata_t* deviceInfo, const sp<ICameraDeviceCallback>& callback) : - camera3_callback_ops({&sProcessCaptureResult, &sNotify}), + camera3_callback_ops({&sProcessCaptureResult, &sNotify, nullptr, nullptr}), mDevice(device), mDeviceVersion(device->common.version), mFreeBufEarly(shouldFreeBufEarly()), @@ -246,10 +248,50 @@ void CameraDeviceSession::overrideResultForPrecaptureCancelLocked( } } +Status CameraDeviceSession::importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) { + + if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { + if (allowEmptyBuf) { + *outBufPtr = &sEmptyBuffer; + return Status::OK; + } else { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + } + + Mutex::Autolock _l(mInflightLock); + CirculatingBuffers& cbs = mCirculatingBuffers[streamId]; + if (cbs.count(bufId) == 0) { + // Register a newly seen buffer + buffer_handle_t importedBuf = buf; + sHandleImporter.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; +} + Status CameraDeviceSession::importRequest( const CaptureRequest& request, hidl_vec<buffer_handle_t*>& allBufPtrs, hidl_vec<int>& allFences) { + return importRequestImpl(request, allBufPtrs, allFences); +} + +Status CameraDeviceSession::importRequestImpl( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences, + bool allowEmptyBuf) { bool hasInputBuf = (request.inputBuffer.streamId != -1 && request.inputBuffer.bufferId != 0); size_t numOutputBufs = request.outputBuffers.size(); @@ -277,25 +319,15 @@ Status CameraDeviceSession::importRequest( } for (size_t i = 0; i < numBufs; i++) { - buffer_handle_t buf = allBufs[i]; - uint64_t bufId = allBufIds[i]; - CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]]; - 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; - sHandleImporter.importBuffer(importedBuf); - if (importedBuf == nullptr) { - ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i); - return Status::INTERNAL_ERROR; - } else { - cbs[bufId] = importedBuf; - } + Status st = importBuffer( + streamIds[i], allBufIds[i], allBufs[i], &allBufPtrs[i], + // Disallow empty buf for input stream, otherwise follow + // the allowEmptyBuf argument. + (hasInputBuf && i == numOutputBufs) ? false : allowEmptyBuf); + if (st != Status::OK) { + // Detailed error logs printed in importBuffer + return st; } - allBufPtrs[i] = &cbs[bufId]; } // All buffers are imported. Now validate output buffer acquire fences @@ -1271,18 +1303,26 @@ Return<void> CameraDeviceSession::close() { ATRACE_END(); // free all imported buffers + Mutex::Autolock _l(mInflightLock); for(auto& pair : mCirculatingBuffers) { CirculatingBuffers& buffers = pair.second; for (auto& p2 : buffers) { sHandleImporter.freeBuffer(p2.second); } + buffers.clear(); } + mCirculatingBuffers.clear(); mClosed = true; } return Void(); } +uint64_t CameraDeviceSession::getCapResultBufferId(const buffer_handle_t&, int) { + // No need to fill in bufferId by default + return BUFFER_ID_NO_BUFFER; +} + status_t CameraDeviceSession::constructCaptureResult(CaptureResult& result, const camera3_capture_result *hal_result) { uint32_t frameNumber = hal_result->frame_number; @@ -1396,6 +1436,14 @@ status_t CameraDeviceSession::constructCaptureResult(CaptureResult& result, result.outputBuffers[i].streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; result.outputBuffers[i].buffer = nullptr; + if (hal_result->output_buffers[i].buffer != nullptr) { + result.outputBuffers[i].bufferId = getCapResultBufferId( + *(hal_result->output_buffers[i].buffer), + result.outputBuffers[i].streamId); + } else { + result.outputBuffers[i].bufferId = 0; + } + result.outputBuffers[i].status = (BufferStatus) hal_result->output_buffers[i].status; // skip acquire fence since it's of no use to camera service if (hal_result->output_buffers[i].release_fence != -1) { diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h index bcee259fbd..a96c245067 100644 --- a/camera/device/3.2/default/CameraDeviceSession.h +++ b/camera/device/3.2/default/CameraDeviceSession.h @@ -161,6 +161,7 @@ protected: std::map<uint32_t, bool> mInflightRawBoostPresent; ::android::hardware::camera::common::V1_0::helper::CameraMetadata mOverridenRequest; + static const uint64_t BUFFER_ID_NO_BUFFER = 0; // buffers currently ciculating between HAL and camera service // key: bufferId sent via HIDL interface // value: imported buffer_handle_t @@ -171,6 +172,7 @@ protected: std::map<int, CirculatingBuffers> mCirculatingBuffers; static HandleImporter sHandleImporter; + static buffer_handle_t sEmptyBuffer; bool mInitFail; bool mFirstRequest = false; @@ -301,11 +303,23 @@ protected: Status initStatus() const; // Validate and import request's input buffer and acquire fence - Status importRequest( + virtual Status importRequest( const CaptureRequest& request, hidl_vec<buffer_handle_t*>& allBufPtrs, hidl_vec<int>& allFences); + Status importRequestImpl( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences, + // Optional argument for ICameraDeviceSession@3.5 impl + bool allowEmptyBuf = false); + + Status importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf); + static void cleanupInflightFences( hidl_vec<int>& allFences, size_t numFences); @@ -332,6 +346,11 @@ protected: static callbacks_process_capture_result_t sProcessCaptureResult; static callbacks_notify_t sNotify; + // By default camera service uses frameNumber/streamId pair to retrieve the buffer that + // was sent to HAL. Override this implementation if HAL is using buffers from buffer management + // APIs to send output buffer. + virtual uint64_t getCapResultBufferId(const buffer_handle_t& buf, int streamId); + status_t constructCaptureResult(CaptureResult& result, const camera3_capture_result *hal_result); diff --git a/camera/device/3.2/default/CameraDevice_3_2.h b/camera/device/3.2/default/CameraDevice_3_2.h index 9534707bd0..f4745337f8 100644 --- a/camera/device/3.2/default/CameraDevice_3_2.h +++ b/camera/device/3.2/default/CameraDevice_3_2.h @@ -51,7 +51,7 @@ using ::android::Mutex; /* * The camera device HAL implementation is opened lazily (via the open call) */ -struct CameraDevice : public ICameraDevice { +struct CameraDevice : public virtual RefBase { // Called by 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. @@ -60,7 +60,14 @@ struct CameraDevice : public ICameraDevice { CameraDevice(sp<CameraModule> module, const std::string& cameraId, const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames); - ~CameraDevice(); + virtual ~CameraDevice(); + + // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when + // dealing with minor version revs and simultaneous implementation and interface inheritance + virtual sp<ICameraDevice> getInterface() { + return new TrampolineDeviceInterface_3_2(this); + } + // Caller must use this method to check if CameraDevice ctor failed bool isInitFailed() { return mInitFail; } // Used by provider HAL to signal external camera disconnected @@ -68,16 +75,16 @@ struct CameraDevice : public ICameraDevice { /* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */ // The following method can be called without opening the actual camera device - Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override; - Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override; - Return<Status> setTorchMode(TorchMode mode) override; + Return<void> getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb); + Return<void> getCameraCharacteristics(ICameraDevice::getCameraCharacteristics_cb _hidl_cb); + Return<Status> setTorchMode(TorchMode mode); // Open the device HAL and also return a default capture session - Return<void> open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) override; + Return<void> open(const sp<ICameraDeviceCallback>& callback, ICameraDevice::open_cb _hidl_cb); // Forward the dump call to the opened session, or do nothing - Return<void> dumpState(const ::android::hardware::hidl_handle& fd) override; + Return<void> dumpState(const ::android::hardware::hidl_handle& fd); /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */ protected: @@ -106,6 +113,39 @@ protected: static Status getHidlStatus(int); Status initStatus() const; + +private: + struct TrampolineDeviceInterface_3_2 : public ICameraDevice { + TrampolineDeviceInterface_3_2(sp<CameraDevice> parent) : + mParent(parent) {} + + virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return<void> getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return<Status> setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return<void> dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + private: + sp<CameraDevice> mParent; + }; + }; } // namespace implementation diff --git a/camera/device/3.2/default/OWNERS b/camera/device/3.2/default/OWNERS index 18acfee145..369b2048cb 100644 --- a/camera/device/3.2/default/OWNERS +++ b/camera/device/3.2/default/OWNERS @@ -1,6 +1,7 @@ cychen@google.com epeev@google.com etalvala@google.com +jchowdhary@google.com shuzhenwang@google.com yinchiayeh@google.com zhijunhe@google.com diff --git a/camera/device/3.3/default/OWNERS b/camera/device/3.3/default/OWNERS index 18acfee145..369b2048cb 100644 --- a/camera/device/3.3/default/OWNERS +++ b/camera/device/3.3/default/OWNERS @@ -1,6 +1,7 @@ cychen@google.com epeev@google.com etalvala@google.com +jchowdhary@google.com shuzhenwang@google.com yinchiayeh@google.com zhijunhe@google.com diff --git a/camera/device/3.4/ICameraDeviceSession.hal b/camera/device/3.4/ICameraDeviceSession.hal index c41d90e27a..e1663e6669 100644 --- a/camera/device/3.4/ICameraDeviceSession.hal +++ b/camera/device/3.4/ICameraDeviceSession.hal @@ -54,7 +54,7 @@ interface ICameraDeviceSession extends @3.3::ICameraDeviceSession { * - Including too many output streams of a certain format. * - Unsupported rotation configuration * - Stream sizes/formats don't satisfy the - * camera3_stream_configuration_t->operation_mode requirements + * StreamConfigurationMode requirements * for non-NORMAL mode, or the requested operation_mode is not * supported by the HAL. * - Unsupported usage flag diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp index f2e031c674..e52577cfb9 100644 --- a/camera/device/3.4/default/CameraDeviceSession.cpp +++ b/camera/device/3.4/default/CameraDeviceSession.cpp @@ -87,6 +87,14 @@ CameraDeviceSession::~CameraDeviceSession() { Return<void> CameraDeviceSession::configureStreams_3_4( const StreamConfiguration& requestedConfiguration, ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb) { + configureStreams_3_4_Impl(requestedConfiguration, _hidl_cb); + return Void(); +} + +void CameraDeviceSession::configureStreams_3_4_Impl( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb, + uint32_t streamConfigCounter) { Status status = initStatus(); HalStreamConfiguration outStreams; @@ -97,7 +105,7 @@ Return<void> CameraDeviceSession::configureStreams_3_4( ALOGE("%s: trying to configureStreams with physical camera id with V3.2 callback", __FUNCTION__); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } } } @@ -109,7 +117,7 @@ Return<void> CameraDeviceSession::configureStreams_3_4( ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!", __FUNCTION__, mInflightBuffers.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } if (!mInflightAETriggerOverrides.empty()) { @@ -117,7 +125,7 @@ Return<void> CameraDeviceSession::configureStreams_3_4( " trigger overrides!", __FUNCTION__, mInflightAETriggerOverrides.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } if (!mInflightRawBoostPresent.empty()) { @@ -125,12 +133,12 @@ Return<void> CameraDeviceSession::configureStreams_3_4( " boost overrides!", __FUNCTION__, mInflightRawBoostPresent.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } if (status != Status::OK) { _hidl_cb(status, outStreams); - return Void(); + return; } const camera_metadata_t *paramBuffer = nullptr; @@ -139,11 +147,12 @@ Return<void> CameraDeviceSession::configureStreams_3_4( } camera3_stream_configuration_t stream_list{}; + stream_list.stream_configuration_counter = streamConfigCounter; hidl_vec<camera3_stream_t*> streams; stream_list.session_parameters = paramBuffer; if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) { _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } ATRACE_BEGIN("camera3->configure_streams"); @@ -168,7 +177,7 @@ Return<void> CameraDeviceSession::configureStreams_3_4( } _hidl_cb(status, outStreams); - return Void(); + return; } bool CameraDeviceSession::preProcessConfigurationLocked_3_4( diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp index e7361dd463..0f236570cd 100644 --- a/camera/device/3.4/default/ExternalCameraDevice.cpp +++ b/camera/device/3.4/default/ExternalCameraDevice.cpp @@ -48,24 +48,31 @@ constexpr int OPEN_RETRY_SLEEP_US = 100000; // 100ms * MAX_RETRY = 0.5 seconds } // anonymous namespace ExternalCameraDevice::ExternalCameraDevice( - const std::string& cameraId, const ExternalCameraConfig& cfg) : + const std::string& cameraId, const ExternalCameraConfig& cfg) : mCameraId(cameraId), - mCfg(cfg) { - - status_t ret = initCameraCharacteristics(); - if (ret != OK) { - ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret); - mInitFailed = true; - } -} + mCfg(cfg) {} ExternalCameraDevice::~ExternalCameraDevice() {} 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; } -Return<void> ExternalCameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { +Return<void> ExternalCameraDevice::getResourceCost( + ICameraDevice::getResourceCost_cb _hidl_cb) { CameraResourceCost resCost; resCost.resourceCost = 100; _hidl_cb(Status::OK, resCost); @@ -73,11 +80,11 @@ Return<void> ExternalCameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) } Return<void> ExternalCameraDevice::getCameraCharacteristics( - getCameraCharacteristics_cb _hidl_cb) { + ICameraDevice::getCameraCharacteristics_cb _hidl_cb) { Mutex::Autolock _l(mLock); V3_2::CameraMetadata hidlChars; - if (isInitFailed()) { + if (isInitFailedLocked()) { _hidl_cb(Status::INTERNAL_ERROR, hidlChars); return Void(); } @@ -94,7 +101,7 @@ Return<Status> ExternalCameraDevice::setTorchMode(TorchMode) { } Return<void> ExternalCameraDevice::open( - const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) { + const sp<ICameraDeviceCallback>& callback, ICameraDevice::open_cb _hidl_cb) { Status status = Status::OK; sp<ExternalCameraDeviceSession> session = nullptr; @@ -143,7 +150,7 @@ Return<void> ExternalCameraDevice::open( } } - session = new ExternalCameraDeviceSession( + session = createSession( callback, mCfg, mSupportedFormats, mCroppingType, mCameraCharacteristics, mCameraId, std::move(fd)); if (session == nullptr) { @@ -371,8 +378,12 @@ status_t ExternalCameraDevice::initDefaultCharsKeys( const uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN; UPDATE(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, ×tampSource, 1); - // Orientation probably isn't useful for external facing camera? - const int32_t orientation = 0; + // 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 @@ -479,52 +490,9 @@ status_t ExternalCameraDevice::initDefaultCharsKeys( UPDATE(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys, ARRAY_SIZE(availableResultKeys)); - const int32_t availableCharacteristicsKeys[] = { - 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}; UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, - availableCharacteristicsKeys, - ARRAY_SIZE(availableCharacteristicsKeys)); + AVAILABLE_CHARACTERISTICS_KEYS_3_4.data(), + AVAILABLE_CHARACTERISTICS_KEYS_3_4.size()); return OK; } @@ -931,6 +899,18 @@ void ExternalCameraDevice::initSupportedFormatsLocked(int fd) { } } +sp<ExternalCameraDeviceSession> ExternalCameraDevice::createSession( + const sp<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 new ExternalCameraDeviceSession( + cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)); +} + } // namespace implementation } // namespace V3_4 } // namespace device diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp index dce40ff285..66b17db955 100644 --- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp @@ -81,6 +81,8 @@ bool tryLock(std::mutex& mutex) return locked; } +buffer_handle_t sEmptyBuffer = nullptr; + } // Anonymous namespace // Static instances @@ -103,11 +105,8 @@ ExternalCameraDeviceSession::ExternalCameraDeviceSession( mCroppingType(croppingType), mCameraId(cameraId), mV4l2Fd(std::move(v4l2Fd)), - mOutputThread(new OutputThread(this, mCroppingType)), mMaxThumbResolution(getMaxThumbResolution()), - mMaxJpegResolution(getMaxJpegResolution()) { - mInitFail = initialize(); -} + mMaxJpegResolution(getMaxJpegResolution()) {} bool ExternalCameraDeviceSession::initialize() { if (mV4l2Fd.get() < 0) { @@ -142,6 +141,12 @@ bool ExternalCameraDeviceSession::initialize() { model = card; } } + + initOutputThread(); + if (mOutputThread == nullptr) { + ALOGE("%s: init OutputThread failed!", __FUNCTION__); + return true; + } mOutputThread->setExifMakeModel(make, model); status_t status = initDefaultRequests(); @@ -168,6 +173,32 @@ bool ExternalCameraDeviceSession::initialize() { return false; } +bool ExternalCameraDeviceSession::isInitFailed() { + Mutex::Autolock _l(mLock); + if (!mInitialized) { + mInitFail = initialize(); + mInitialized = true; + } + return mInitFail; +} + +void ExternalCameraDeviceSession::initOutputThread() { + mOutputThread = new OutputThread(this, mCroppingType); +} + +void ExternalCameraDeviceSession::closeOutputThread() { + closeOutputThreadImpl(); +} + +void ExternalCameraDeviceSession::closeOutputThreadImpl() { + if (mOutputThread) { + mOutputThread->flush(); + mOutputThread->requestExit(); + mOutputThread->join(); + mOutputThread.clear(); + } +} + Status ExternalCameraDeviceSession::initStatus() const { Mutex::Autolock _l(mLock); Status status = Status::OK; @@ -181,7 +212,7 @@ Status ExternalCameraDeviceSession::initStatus() const { ExternalCameraDeviceSession::~ExternalCameraDeviceSession() { if (!isClosed()) { ALOGE("ExternalCameraDeviceSession deleted before close!"); - close(); + close(/*callerIsDtor*/true); } } @@ -344,17 +375,31 @@ Return<void> ExternalCameraDeviceSession::configureStreams_3_4( ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb) { V3_2::StreamConfiguration config_v32; V3_3::HalStreamConfiguration outStreams_v33; + V3_4::HalStreamConfiguration outStreams; Mutex::Autolock _il(mInterfaceLock); config_v32.operationMode = requestedConfiguration.operationMode; config_v32.streams.resize(requestedConfiguration.streams.size()); + uint32_t blobBufferSize = 0; + int numStallStream = 0; for (size_t i = 0; i < config_v32.streams.size(); i++) { config_v32.streams[i] = requestedConfiguration.streams[i].v3_2; + if (config_v32.streams[i].format == PixelFormat::BLOB) { + blobBufferSize = requestedConfiguration.streams[i].bufferSize; + numStallStream++; + } } - Status status = configureStreams(config_v32, &outStreams_v33); + // Fail early if there are multiple BLOB streams + if (numStallStream > kMaxStallStream) { + ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__, + kMaxStallStream, numStallStream); + _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams); + return Void(); + } + + Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize); - V3_4::HalStreamConfiguration outStreams; outStreams.streams.resize(outStreams_v33.streams.size()); for (size_t i = 0; i < outStreams.streams.size(); i++) { outStreams.streams[i].v3_3 = outStreams_v33.streams[i]; @@ -428,18 +473,23 @@ Return<Status> ExternalCameraDeviceSession::flush() { return Status::OK; } -Return<void> ExternalCameraDeviceSession::close() { +Return<void> ExternalCameraDeviceSession::close(bool callerIsDtor) { Mutex::Autolock _il(mInterfaceLock); bool closed = isClosed(); if (!closed) { - mOutputThread->flush(); - mOutputThread->requestExit(); - mOutputThread->join(); + if (callerIsDtor) { + closeOutputThreadImpl(); + } else { + closeOutputThread(); + } Mutex::Autolock _l(mLock); // free all buffers - for(auto pair : mStreamMap) { - cleanupBuffersLocked(/*Stream ID*/pair.first); + { + Mutex::Autolock _l(mCbsLock); + for(auto pair : mStreamMap) { + cleanupBuffersLocked(/*Stream ID*/pair.first); + } } v4l2StreamOffLocked(); ALOGV("%s: closing V4L2 camera FD %d", __FUNCTION__, mV4l2Fd.get()); @@ -449,10 +499,61 @@ Return<void> ExternalCameraDeviceSession::close() { return Void(); } -Status ExternalCameraDeviceSession::importRequest( +Status ExternalCameraDeviceSession::importRequestLocked( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences) { + return importRequestLockedImpl(request, allBufPtrs, allFences); +} + +Status ExternalCameraDeviceSession::importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) { + Mutex::Autolock _l(mCbsLock); + return importBufferLocked(streamId, bufId, buf, outBufPtr, allowEmptyBuf); +} + +Status ExternalCameraDeviceSession::importBufferLocked(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf) { + + if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) { + if (allowEmptyBuf) { + *outBufPtr = &sEmptyBuffer; + return Status::OK; + } else { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + } + + CirculatingBuffers& cbs = mCirculatingBuffers[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; + sHandleImporter.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; +} + +Status ExternalCameraDeviceSession::importRequestLockedImpl( const CaptureRequest& request, hidl_vec<buffer_handle_t*>& allBufPtrs, - hidl_vec<int>& allFences) { + hidl_vec<int>& allFences, + bool allowEmptyBuf) { size_t numOutputBufs = request.outputBuffers.size(); size_t numBufs = numOutputBufs; // Validate all I/O buffers @@ -471,26 +572,17 @@ Status ExternalCameraDeviceSession::importRequest( streamIds[i] = request.outputBuffers[i].streamId; } - for (size_t i = 0; i < numBufs; i++) { - buffer_handle_t buf = allBufs[i]; - uint64_t bufId = allBufIds[i]; - CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]]; - 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; - sHandleImporter.importBuffer(importedBuf); - if (importedBuf == nullptr) { - ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i); - return Status::INTERNAL_ERROR; - } else { - cbs[bufId] = importedBuf; + { + Mutex::Autolock _l(mCbsLock); + for (size_t i = 0; i < numBufs; i++) { + Status st = importBufferLocked( + streamIds[i], allBufIds[i], allBufs[i], &allBufPtrs[i], + allowEmptyBuf); + if (st != Status::OK) { + // Detailed error logs printed in importBuffer + return st; } } - allBufPtrs[i] = &cbs[bufId]; } // All buffers are imported. Now validate output buffer acquire fences @@ -638,7 +730,7 @@ Status ExternalCameraDeviceSession::processOneCaptureRequest(const CaptureReques } } - status = importRequest(request, allBufPtrs, allFences); + status = importRequestLocked(request, allBufPtrs, allFences); if (status != Status::OK) { return status; } @@ -761,9 +853,11 @@ Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequ result.outputBuffers[i].bufferId = req->buffers[i].bufferId; if (req->buffers[i].fenceTimeout) { result.outputBuffers[i].status = BufferStatus::ERROR; - native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); - handle->data[0] = req->buffers[i].acquireFence; - result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false); + 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.setTo(handle, /*shouldOwn*/false); + } notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER); } else { result.outputBuffers[i].status = BufferStatus::OK; @@ -1592,8 +1686,9 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( * main image needs to hold APP1, headers, and at most a poorly * compressed image */ const ssize_t maxThumbCodeSize = 64 * 1024; - const ssize_t maxJpegCodeSize = parent->getJpegBufferSize(jpegSize.width, - jpegSize.height); + const ssize_t maxJpegCodeSize = mBlobBufferSize == 0 ? + parent->getJpegBufferSize(jpegSize.width, jpegSize.height) : + mBlobBufferSize; /* Check that getJpegBufferSize did not return an error */ if (maxJpegCodeSize < 0) { @@ -1732,6 +1827,12 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { (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 @@ -1744,7 +1845,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { // TODO: in some special case maybe we can decode jpg directly to gralloc output? ATRACE_BEGIN("MJPGtoI420"); - int res = libyuv::MJPGToI420( + res = libyuv::MJPGToI420( inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride, @@ -1768,10 +1869,23 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { 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.acquireFence != -1) { + if (*(halBuf.bufPtr) == nullptr) { + ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId); + halBuf.fenceTimeout = true; + } else if (halBuf.acquireFence != -1) { int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs); if (ret) { halBuf.fenceTimeout = true; @@ -1859,7 +1973,8 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( const Size& v4lSize, const Size& thumbSize, - const hidl_vec<Stream>& streams) { + const hidl_vec<Stream>& streams, + uint32_t blobBufferSize) { std::lock_guard<std::mutex> lk(mBufferLock); if (mScaledYu12Frames.size() != 0) { ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)", @@ -1928,6 +2043,8 @@ Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( it = mIntermediateBuffers.erase(it); } } + + mBlobBufferSize = blobBufferSize; return Status::OK; } @@ -2027,7 +2144,7 @@ void ExternalCameraDeviceSession::cleanupBuffersLocked(int id) { } void ExternalCameraDeviceSession::updateBufferCaches(const hidl_vec<BufferCache>& cachesToRemove) { - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mCbsLock); for (auto& cache : cachesToRemove) { auto cbsIt = mCirculatingBuffers.find(cache.streamId); if (cbsIt == mCirculatingBuffers.end()) { @@ -2046,7 +2163,8 @@ void ExternalCameraDeviceSession::updateBufferCaches(const hidl_vec<BufferCache> } } -bool ExternalCameraDeviceSession::isSupported(const Stream& stream) { +bool ExternalCameraDeviceSession::isSupported(const Stream& stream, + const std::vector<SupportedV4L2Format>& supportedFormats) { int32_t ds = static_cast<int32_t>(stream.dataSpace); PixelFormat fmt = stream.format; uint32_t width = stream.width; @@ -2089,7 +2207,7 @@ bool ExternalCameraDeviceSession::isSupported(const Stream& stream) { // 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 : mSupportedFormats) { + for (const auto& v4l2Fmt : supportedFormats) { if (width == v4l2Fmt.width && height == v4l2Fmt.height) { return true; } @@ -2424,9 +2542,9 @@ void ExternalCameraDeviceSession::enqueueV4l2Frame(const sp<V4L2Frame>& frame) { mV4L2BufferReturned.notify_one(); } -Status ExternalCameraDeviceSession::configureStreams( - const V3_2::StreamConfiguration& config, V3_3::HalStreamConfiguration* out) { - ATRACE_CALL(); +Status ExternalCameraDeviceSession::isStreamCombinationSupported( + const V3_2::StreamConfiguration& config, + const std::vector<SupportedV4L2Format>& supportedFormats) { if (config.operationMode != StreamConfigurationMode::NORMAL_MODE) { ALOGE("%s: unsupported operation mode: %d", __FUNCTION__, config.operationMode); return Status::ILLEGAL_ARGUMENT; @@ -2441,7 +2559,7 @@ Status ExternalCameraDeviceSession::configureStreams( int numStallStream = 0; for (const auto& stream : config.streams) { // Check if the format/width/height combo is supported - if (!isSupported(stream)) { + if (!isSupported(stream, supportedFormats)) { return Status::ILLEGAL_ARGUMENT; } if (stream.format == PixelFormat::BLOB) { @@ -2463,7 +2581,21 @@ Status ExternalCameraDeviceSession::configureStreams( return Status::ILLEGAL_ARGUMENT; } - Status status = initStatus(); + return Status::OK; +} + +Status ExternalCameraDeviceSession::configureStreams( + const V3_2::StreamConfiguration& config, + V3_3::HalStreamConfiguration* out, + uint32_t blobBufferSize) { + ATRACE_CALL(); + + Status status = isStreamCombinationSupported(config, mSupportedFormats); + if (status != Status::OK) { + return status; + } + + status = initStatus(); if (status != Status::OK) { return status; } @@ -2479,30 +2611,33 @@ Status ExternalCameraDeviceSession::configureStreams( } Mutex::Autolock _l(mLock); - // Add new streams - for (const auto& stream : config.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; + { + Mutex::Autolock _l(mCbsLock); + // Add new streams for (const auto& stream : config.streams) { - if (id == stream.id) { - found = true; - break; + if (mStreamMap.count(stream.id) == 0) { + mStreamMap[stream.id] = stream; + mCirculatingBuffers.emplace(stream.id, CirculatingBuffers{}); } } - if (!found) { - // Unmap all buffers of deleted stream - cleanupBuffersLocked(id); - it = mStreamMap.erase(it); - } else { - ++it; + + // Cleanup removed streams + for(auto it = mStreamMap.begin(); it != mStreamMap.end();) { + int id = it->first; + bool found = false; + for (const auto& stream : config.streams) { + if (id == stream.id) { + found = true; + break; + } + } + if (!found) { + // Unmap all buffers of deleted stream + cleanupBuffersLocked(id); + it = mStreamMap.erase(it); + } else { + ++it; + } } } @@ -2587,7 +2722,7 @@ Status ExternalCameraDeviceSession::configureStreams( } status = mOutputThread->allocateIntermediateBuffers(v4lSize, - mMaxThumbResolution, config.streams); + mMaxThumbResolution, config.streams, blobBufferSize); if (status != Status::OK) { ALOGE("%s: allocating intermediate buffers failed!", __FUNCTION__); return status; diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp index 680c95ad3b..0941052c78 100644 --- a/camera/device/3.4/default/ExternalCameraUtils.cpp +++ b/camera/device/3.4/default/ExternalCameraUtils.cpp @@ -160,9 +160,11 @@ namespace external { namespace common { namespace { - const int kDefaultJpegBufSize = 5 << 20; // 5MB - const int kDefaultNumVideoBuffer = 4; - const int kDefaultNumStillBuffer = 2; + 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"; @@ -276,10 +278,17 @@ ExternalCameraConfig ExternalCameraConfig::loadFromCfg(const char* cfgPath) { 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", + " num video buffers %d, num still buffers %d, orientation %d", __FUNCTION__, ret.maxJpegBufSize, - ret.numVideoBuffers, ret.numStillBuffers); + 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); @@ -292,7 +301,8 @@ ExternalCameraConfig ExternalCameraConfig::loadFromCfg(const char* cfgPath) { ExternalCameraConfig::ExternalCameraConfig() : maxJpegBufSize(kDefaultJpegBufSize), numVideoBuffers(kDefaultNumVideoBuffer), - numStillBuffers(kDefaultNumStillBuffer) { + numStillBuffers(kDefaultNumStillBuffer), + orientation(kDefaultOrientation) { fpsLimits.push_back({/*Size*/{ 640, 480}, /*FPS upper bound*/30.0}); fpsLimits.push_back({/*Size*/{1280, 720}, /*FPS upper bound*/7.5}); fpsLimits.push_back({/*Size*/{1920, 1080}, /*FPS upper bound*/5.0}); diff --git a/camera/device/3.4/default/OWNERS b/camera/device/3.4/default/OWNERS index 18acfee145..369b2048cb 100644 --- a/camera/device/3.4/default/OWNERS +++ b/camera/device/3.4/default/OWNERS @@ -1,6 +1,7 @@ cychen@google.com epeev@google.com etalvala@google.com +jchowdhary@google.com shuzhenwang@google.com yinchiayeh@google.com zhijunhe@google.com diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h index fdc8a5afd2..00500b15f8 100644 --- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h +++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h @@ -87,6 +87,12 @@ protected: void postProcessConfigurationFailureLocked_3_4( const StreamConfiguration& requestedConfiguration); + void configureStreams_3_4_Impl( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb, + // Optional argument for ICameraDeviceSession@3.5 impl + uint32_t streamConfigCounter = 0); + Return<void> processCaptureRequest_3_4( const hidl_vec<V3_4::CaptureRequest>& requests, const hidl_vec<V3_2::BufferCache>& cachesToRemove, diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h index 0b94c11222..9cc55cbc07 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h @@ -97,7 +97,7 @@ struct ExternalCameraDeviceSession : public virtual RefBase { // Call by CameraDevice to dump active device states void dumpState(const native_handle_t*); // Caller must use this method to check if CameraDeviceSession ctor failed - bool isInitFailed() { return mInitFail; } + bool isInitFailed(); bool isClosed(); // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when @@ -134,7 +134,7 @@ protected: ICameraDeviceSession::processCaptureRequest_cb); Return<Status> flush(); - Return<void> close(); + Return<void> close(bool callerIsDtor = false); Return<void> configureStreams_3_3( const V3_2::StreamConfiguration&, @@ -170,32 +170,63 @@ protected: std::vector<HalStreamBuffer> buffers; }; + static const uint64_t BUFFER_ID_NO_BUFFER = 0; + Status constructDefaultRequestSettingsRaw(RequestTemplate type, V3_2::CameraMetadata *outMetadata); bool initialize(); + // To init/close different version of output thread + virtual void initOutputThread(); + virtual void closeOutputThread(); + void closeOutputThreadImpl(); + Status initStatus() const; status_t initDefaultRequests(); status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp); - Status configureStreams(const V3_2::StreamConfiguration&, V3_3::HalStreamConfiguration* out); + Status configureStreams(const V3_2::StreamConfiguration&, + V3_3::HalStreamConfiguration* out, + // Only filled by configureStreams_3_4, and only one blob stream supported + uint32_t blobBufferSize = 0); // fps = 0.0 means default, which is // slowest fps that is at least 30, or fastest fps if 30 is not supported int configureV4l2StreamLocked(const SupportedV4L2Format& fmt, double fps = 0.0); int v4l2StreamOffLocked(); int setV4l2FpsLocked(double fps); + static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config, + const std::vector<SupportedV4L2Format>& supportedFormats); // TODO: change to unique_ptr for better tracking sp<V4L2Frame> dequeueV4l2FrameLocked(/*out*/nsecs_t* shutterTs); // Called with mLock hold void enqueueV4l2Frame(const sp<V4L2Frame>&); // Check if input Stream is one of supported stream setting on this device - bool isSupported(const Stream&); + static bool isSupported(const Stream& stream, + const std::vector<SupportedV4L2Format>& supportedFormats); // Validate and import request's output buffers and acquire fence - Status importRequest( + virtual Status importRequestLocked( const CaptureRequest& request, hidl_vec<buffer_handle_t*>& allBufPtrs, hidl_vec<int>& allFences); + + Status importRequestLockedImpl( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences, + // Optional argument for ICameraDeviceSession@3.5 impl + bool allowEmptyBuf = false); + + Status importBuffer(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf); + + Status importBufferLocked(int32_t streamId, + uint64_t bufId, buffer_handle_t buf, + /*out*/buffer_handle_t** outBufPtr, + bool allowEmptyBuf); + static void cleanupInflightFences( hidl_vec<int>& allFences, size_t numFences); void cleanupBuffersLocked(int id); @@ -221,18 +252,26 @@ protected: class OutputThread : public android::Thread { public: OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType); - ~OutputThread(); + virtual ~OutputThread(); Status allocateIntermediateBuffers( const Size& v4lSize, const Size& thumbSize, - const hidl_vec<Stream>& streams); + const hidl_vec<Stream>& streams, + uint32_t blobBufferSize); Status submitRequest(const std::shared_ptr<HalRequest>&); void flush(); void dump(int fd); virtual bool threadLoop() override; void setExifMakeModel(const std::string& make, const std::string& model); - private: + + protected: + // Methods to request output buffer in parallel + // No-op for device@3.4. Implemented in device@3.5 + virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; } + virtual int waitForBufferRequestDone( + /*out*/std::vector<HalStreamBuffer>*) { return 0; } + 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; @@ -289,6 +328,7 @@ protected: std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames; YCbCrLayout mYu12FrameLayout; YCbCrLayout mYu12ThumbFrameLayout; + uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size std::string mExifMake; std::string mExifModel; @@ -314,6 +354,7 @@ protected: // - init failed // - camera disconnected bool mClosed = false; + bool mInitialized = false; bool mInitFail = false; bool mFirstRequest = false; common::V1_0::helper::CameraMetadata mLatestReqSetting; @@ -346,6 +387,8 @@ protected: typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers; // 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; diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h index ff0cfb301e..719a3ed848 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h @@ -25,6 +25,8 @@ #include <hidl/MQDescriptor.h> #include "ExternalCameraDeviceSession.h" +#include <vector> + namespace android { namespace hardware { namespace camera { @@ -49,7 +51,7 @@ using ::android::sp; /* * The camera device HAL implementation is opened lazily (via the open call) */ -struct ExternalCameraDevice : public ICameraDevice { +struct ExternalCameraDevice : public virtual RefBase { // Called by external camera provider HAL. // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could @@ -57,33 +59,54 @@ struct ExternalCameraDevice : public ICameraDevice { // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying // camera is detached. ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg); - ~ExternalCameraDevice(); + virtual ~ExternalCameraDevice(); + + // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when + // dealing with minor version revs and simultaneous implementation and interface inheritance + virtual sp<ICameraDevice> getInterface() { + return new TrampolineDeviceInterface_3_4(this); + } // Caller must use this method to check if CameraDevice ctor failed bool isInitFailed(); + bool isInitFailedLocked(); /* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */ // The following method can be called without opening the actual camera device - Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override; + Return<void> getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb); - Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override; + Return<void> getCameraCharacteristics( + ICameraDevice::getCameraCharacteristics_cb _hidl_cb); - Return<Status> setTorchMode(TorchMode) override; + Return<Status> setTorchMode(TorchMode); // Open the device HAL and also return a default capture session - Return<void> open(const sp<ICameraDeviceCallback>&, open_cb) override; + Return<void> open(const sp<ICameraDeviceCallback>&, ICameraDevice::open_cb); // Forward the dump call to the opened session, or do nothing - Return<void> dumpState(const ::android::hardware::hidl_handle&) override; + Return<void> dumpState(const ::android::hardware::hidl_handle&); /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */ protected: + // Overridden by child implementations for returning different versions of + // ExternalCameraDeviceSession + virtual sp<ExternalCameraDeviceSession> createSession( + const sp<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); + // 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 non-device dependent keys - status_t initDefaultCharsKeys(::android::hardware::camera::common::V1_0::helper::CameraMetadata*); + 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*); @@ -103,6 +126,7 @@ protected: /*inout*/std::vector<SupportedV4L2Format>* pFmts); Mutex mLock; + bool mInitialized = false; bool mInitFailed = false; std::string mCameraId; const ExternalCameraConfig& mCfg; @@ -112,6 +136,84 @@ protected: wp<ExternalCameraDeviceSession> mSession = nullptr; ::android::hardware::camera::common::V1_0::helper::CameraMetadata mCameraCharacteristics; + + const std::vector<int32_t> AVAILABLE_CHARACTERISTICS_KEYS_3_4 = { + 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}; + +private: + + struct TrampolineDeviceInterface_3_4 : public ICameraDevice { + TrampolineDeviceInterface_3_4(sp<ExternalCameraDevice> parent) : + mParent(parent) {} + + virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return<void> getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return<Status> setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return<void> dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + private: + sp<ExternalCameraDevice> mParent; + }; + }; } // namespace implementation diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h index 5754ccbec3..3b1ac96934 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h @@ -80,6 +80,9 @@ struct ExternalCameraConfig { // Minimum output stream size Size minStreamSize; + // The value of android.sensor.orientation + int32_t orientation; + private: ExternalCameraConfig(); }; diff --git a/camera/device/3.5/Android.bp b/camera/device/3.5/Android.bp new file mode 100644 index 0000000000..2a9ba05571 --- /dev/null +++ b/camera/device/3.5/Android.bp @@ -0,0 +1,33 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.camera.device@3.5", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ICameraDevice.hal", + "ICameraDeviceCallback.hal", + "ICameraDeviceSession.hal", + ], + interfaces: [ + "android.hardware.camera.common@1.0", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", + "android.hardware.camera.device@3.4", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], + types: [ + "BufferRequest", + "BufferRequestStatus", + "StreamBufferRequestError", + "StreamBufferRet", + "StreamBuffersVal", + "StreamConfiguration", + ], + gen_java: false, +} + diff --git a/camera/device/3.5/ICameraDevice.hal b/camera/device/3.5/ICameraDevice.hal new file mode 100644 index 0000000000..492105c1bf --- /dev/null +++ b/camera/device/3.5/ICameraDevice.hal @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package android.hardware.camera.device@3.5; + +import android.hardware.camera.common@1.0::Status; +import @3.2::CameraMetadata; +import @3.2::ICameraDevice; +import @3.4::StreamConfiguration; + +/** + * Camera device interface + * + * Supports the android.hardware.Camera API, and the android.hardware.camera2 + * API at LIMITED or better hardware level. + * + */ +interface ICameraDevice extends @3.2::ICameraDevice { + + /** + * getPhysicalCameraCharacteristics: + * + * Return the static camera information for a physical camera ID backing + * this logical camera device. This information may not change between consecutive calls. + * + * Note that HAL must support this function for physical camera IDs that are + * not exposed via ICameraProvider::getCameraIdList(). Calling + * getCameraDeviceInterface_V3_x() on these camera IDs must return ILLEGAL_ARGUMENT. + * + * The characteristics of all cameras returned by + * ICameraProvider::getCameraIdList() must be queried via + * getCameraCharacteristics(). Calling getPhysicalCameraCharacteristics() on + * those cameras must return ILLEGAL_ARGUMENT. + * + * @param physicalCameraId The physical camera id parsed from the logical + * camera's ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS static metadata + * key. The framework assumes that this ID is just the <id> part of fully + * qualified camera device name "device@<major>.<minor>/<type>/<id>". And + * the physical camera must be of the same version and type as the parent + * logical camera device. + * + * @return status Status code for the operation, one of: + * OK: + * On a successful query of the physical camera device characteristics + * INTERNAL_ERROR: + * The camera device cannot be opened due to an internal + * error. + * CAMERA_DISCONNECTED: + * An external camera device has been disconnected, and is no longer + * available. This camera device interface is now stale, and a new + * instance must be acquired if the device is reconnected. All + * subsequent calls on this interface must return + * CAMERA_DISCONNECTED. + * ILLEGAL_ARGUMENT: + * If the physicalCameraId is not a valid physical camera Id outside + * of ICameraProvider::getCameraIdList(). + * + * @return cameraCharacteristics + * The static metadata for this logical camera device's physical device, or an empty + * metadata structure if status is not OK. + * + */ + getPhysicalCameraCharacteristics(string physicalCameraId) + generates (Status status, CameraMetadata cameraCharacteristics); + + + /** + * isStreamCombinationSupported: + * + * Check for device support of specific camera stream combination. + * + * The streamList must contain at least one output-capable stream, and may + * not contain more than one input-capable stream. + * In contrast to regular stream configuration the framework does not create + * or initialize any actual streams. This means that Hal must not use or + * consider the stream "id" value. + * + * ------------------------------------------------------------------------ + * + * Preconditions: + * + * The framework can call this method at any time before, during and + * after active session configuration. This means that calls must not + * impact the performance of pending camera requests in any way. In + * particular there must not be any glitches or delays during normal + * camera streaming. + * + * Performance requirements: + * This call is expected to be significantly faster than stream + * configuration. In general HW and SW camera settings must not be + * changed and there must not be a user-visible impact on camera performance. + * + * @return Status Status code for the operation, one of: + * OK: + * On successful stream combination query. + * METHOD_NOT_SUPPORTED: + * The camera device does not support stream combination query. + * INTERNAL_ERROR: + * The stream combination query cannot complete due to internal + * error. + * @return true in case the stream combination is supported, false otherwise. + * + */ + isStreamCombinationSupported(@3.4::StreamConfiguration streams) + generates (Status status, bool queryStatus); +}; diff --git a/camera/device/3.5/ICameraDeviceCallback.hal b/camera/device/3.5/ICameraDeviceCallback.hal new file mode 100644 index 0000000000..aa4ad22ac5 --- /dev/null +++ b/camera/device/3.5/ICameraDeviceCallback.hal @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package android.hardware.camera.device@3.5; + +import @3.2::StreamBuffer; +import @3.4::ICameraDeviceCallback; + +/** + * Callback methods for the HAL to call into the framework. + */ +interface ICameraDeviceCallback extends @3.4::ICameraDeviceCallback { + + /** + * requestStreamBuffers: + * + * Synchronous callback for HAL to ask for output buffers from camera service. + * + * This call may be serialized in camera service so it is strongly + * recommended to only call this method from one thread. + * + * When camera device advertises + * (CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion == + * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5), HAL + * can use this method to request buffers from camera service. + * + * @return status Status code for the operation, one of: + * OK: all requested buffers are returned + * FAILED_PARTIAL: some streams failed while some succeeds. Check + * individual StreamBufferRet for details. + * FAILED_CONFIGURING: the request failed because camera servicve is + * performing configureStreams and no buffers are returned. + * FAILED_UNKNOWN: the request failed for unknown reason and no buffers + * are returned. + * + * Performance requirements: + * This is a blocking call that takes more time with more buffers requested. + * HAL must not request large amount of buffers on a latency critical code + * path. It is highly recommended to use a dedicated thread to perform + * all requestStreamBuffers calls, and adjust the thread priority and/or + * timing of making the call in order for buffers to arrive before HAL is + * ready to fill the buffer. + */ + requestStreamBuffers(vec<BufferRequest> bufReqs) + generates (BufferRequestStatus st, vec<StreamBufferRet> buffers); + + /** + * returnStreamBuffers: + * + * Synchronous callback for HAL to return output buffers to camera service. + * + * If this method is called during a configureStreams call, it must be blocked + * until camera service finishes the ongoing configureStreams call. + */ + returnStreamBuffers(vec<StreamBuffer> buffers); + +}; diff --git a/camera/device/3.5/ICameraDeviceSession.hal b/camera/device/3.5/ICameraDeviceSession.hal new file mode 100644 index 0000000000..b2b71cdd35 --- /dev/null +++ b/camera/device/3.5/ICameraDeviceSession.hal @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package android.hardware.camera.device@3.5; + +import android.hardware.camera.common@1.0::Status; +import @3.4::ICameraDeviceSession; +import @3.4::HalStreamConfiguration; + +/** + * Camera device active session interface. + * + * Obtained via ICameraDevice::open(), this interface contains the methods to + * configure and request captures from an active camera device. + */ +interface ICameraDeviceSession extends @3.4::ICameraDeviceSession { + + /** + * configureStreams_3_5: + * + * Identical to @3.4::ICameraDeviceSession.configureStreams, except that: + * + * - a streamConfigCounter counter is provided to check for race condition + * between configureStreams_3_5 and signalStreamFlush call. + * + * @return status Status code for the operation, one of: + * OK: + * On successful stream configuration. + * INTERNAL_ERROR: + * If there has been a fatal error and the device is no longer + * operational. Only close() can be called successfully by the + * framework after this error is returned. + * ILLEGAL_ARGUMENT: + * If the requested stream configuration is invalid. Some examples + * of invalid stream configurations include: + * - Including more than 1 INPUT stream + * - Not including any OUTPUT streams + * - Including streams with unsupported formats, or an unsupported + * size for that format. + * - Including too many output streams of a certain format. + * - Unsupported rotation configuration + * - Stream sizes/formats don't satisfy the + * StreamConfigurationMode requirements + * for non-NORMAL mode, or the requested operation_mode is not + * supported by the HAL. + * - Unsupported usage flag + * The camera service cannot filter out all possible illegal stream + * configurations, since some devices may support more simultaneous + * streams or larger stream resolutions than the minimum required + * for a given camera device hardware level. The HAL must return an + * ILLEGAL_ARGUMENT for any unsupported stream set, and then be + * ready to accept a future valid stream configuration in a later + * configureStreams call. + * @return halConfiguration The stream parameters desired by the HAL for + * each stream, including maximum buffers, the usage flags, and the + * override format. + */ + configureStreams_3_5(@3.5::StreamConfiguration requestedConfiguration) + generates (Status status, + @3.4::HalStreamConfiguration halConfiguration); + + + /** + * signalStreamFlush: + * + * Signaling HAL camera service is about to perform configureStreams_3_5 and + * HAL must return all buffers of designated streams. HAL must finish + * inflight requests normally and return all buffers that belongs to the + * designated streams through processCaptureResult or returnStreamBuffer + * API in a timely manner, or camera service will run into a fatal error. + * + * Note that this call serves as an optional hint and camera service may + * skip sending this call if all buffers are already returned. + * + * @param streamIds The ID of streams camera service need all of its + * buffers returned. + * + * @param streamConfigCounter Note that due to concurrency nature, it is + * possible the signalStreamFlush call arrives later than the + * corresponding configureStreams_3_5 call, HAL must check + * streamConfigCounter for such race condition. If the counter is less + * than the counter in the last configureStreams_3_5 call HAL last + * received, the call is stale and HAL should just return this call. + */ + oneway signalStreamFlush( + vec<int32_t> streamIds, + uint32_t streamConfigCounter + ); +}; diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp new file mode 100644 index 0000000000..7a48865a3b --- /dev/null +++ b/camera/device/3.5/default/Android.bp @@ -0,0 +1,102 @@ +// +// 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. +// + +cc_library_headers { + name: "camera.device@3.5-impl_headers", + vendor: true, + export_include_dirs: ["include/device_v3_5_impl"] +} + +cc_library_headers { + name: "camera.device@3.5-external-impl_headers", + vendor: true, + export_include_dirs: ["include/ext_device_v3_5_impl"] +} + +cc_library_shared { + name: "camera.device@3.5-impl", + defaults: ["hidl_defaults"], + proprietary: true, + vendor: true, + srcs: [ + "CameraDevice.cpp", + "CameraDeviceSession.cpp", + ], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libutils", + "libcutils", + "camera.device@3.2-impl", + "camera.device@3.3-impl", + "camera.device@3.4-impl", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", + "android.hardware.camera.device@3.4", + "android.hardware.camera.device@3.5", + "android.hardware.camera.provider@2.4", + "android.hardware.graphics.mapper@2.0", + "liblog", + "libhardware", + "libcamera_metadata", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + local_include_dirs: ["include/device_v3_5_impl"], +} + +cc_library_shared { + name: "camera.device@3.5-external-impl", + defaults: ["hidl_defaults"], + proprietary: true, + vendor: true, + srcs: [ + "ExternalCameraDevice.cpp", + "ExternalCameraDeviceSession.cpp", + ], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libutils", + "libcutils", + "camera.device@3.2-impl", + "camera.device@3.3-impl", + "camera.device@3.4-external-impl", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@3.3", + "android.hardware.camera.device@3.4", + "android.hardware.camera.device@3.5", + "android.hardware.camera.provider@2.4", + "android.hardware.graphics.mapper@2.0", + "liblog", + "libhardware", + "libcamera_metadata", + "libfmq", + "libsync", + "libyuv", + "libjpeg", + "libexif", + "libtinyxml2" + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + local_include_dirs: ["include/ext_device_v3_5_impl"], + export_shared_lib_headers: [ + "libfmq", + ], +} diff --git a/camera/device/3.5/default/CameraDevice.cpp b/camera/device/3.5/default/CameraDevice.cpp new file mode 100644 index 0000000000..cffda4e1cf --- /dev/null +++ b/camera/device/3.5/default/CameraDevice.cpp @@ -0,0 +1,157 @@ +/* + * 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. + */ + +#define LOG_TAG "CamDev@3.5-impl" +#include <log/log.h> + +#include "CameraModule.h" +#include "CameraDevice_3_5.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +using namespace ::android::hardware::camera::device; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::device::V3_2::CameraMetadata; + +CameraDevice::CameraDevice(sp<CameraModule> module, const std::string& cameraId, + const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) : + V3_4::implementation::CameraDevice(module, cameraId, cameraDeviceNames) { +} + +CameraDevice::~CameraDevice() { +} + +sp<V3_2::implementation::CameraDeviceSession> CameraDevice::createSession(camera3_device_t* device, + const camera_metadata_t* deviceInfo, + const sp<V3_2::ICameraDeviceCallback>& callback) { + sp<CameraDeviceSession> session = new CameraDeviceSession(device, deviceInfo, callback); + IF_ALOGV() { + session->getInterface()->interfaceChain([]( + ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) { + ALOGV("Session interface chain:"); + for (auto iface : interfaceChain) { + ALOGV(" %s", iface.c_str()); + } + }); + } + return session; +} + +Return<void> CameraDevice::getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) { + Status status = initStatus(); + CameraMetadata cameraCharacteristics; + if (status == Status::OK) { + // Require module 2.5+ version. + if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_5) { + ALOGE("%s: get_physical_camera_info must be called on camera module 2.5 or newer", + __FUNCTION__); + status = Status::INTERNAL_ERROR; + } else { + char *end; + errno = 0; + long id = strtol(physicalCameraId.c_str(), &end, 0); + if (id > INT_MAX || (errno == ERANGE && id == LONG_MAX) || + id < INT_MIN || (errno == ERANGE && id == LONG_MIN) || + *end != '\0') { + ALOGE("%s: Invalid physicalCameraId %s", __FUNCTION__, physicalCameraId.c_str()); + status = Status::ILLEGAL_ARGUMENT; + } else { + camera_metadata_t *physicalInfo = nullptr; + int ret = mModule->getPhysicalCameraInfo((int)id, &physicalInfo); + if (ret == OK) { + V3_2::implementation::convertToHidl(physicalInfo, &cameraCharacteristics); + } else if (ret == -EINVAL) { + ALOGE("%s: %s is not a valid physical camera Id outside of getCameraIdList()", + __FUNCTION__, physicalCameraId.c_str()); + status = Status::ILLEGAL_ARGUMENT; + } else { + ALOGE("%s: Failed to get physical camera %s info: %s (%d)!", __FUNCTION__, + physicalCameraId.c_str(), strerror(-ret), ret); + status = Status::INTERNAL_ERROR; + } + } + } + } + _hidl_cb(status, cameraCharacteristics); + return Void(); +} + +Return<void> CameraDevice::isStreamCombinationSupported(const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) { + Status status; + bool streamsSupported = false; + + // Require module 2.5+ version. + if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_5) { + ALOGE("%s: is_stream_combination_supported must be called on camera module 2.5 or "\ + "newer", __FUNCTION__); + status = Status::INTERNAL_ERROR; + } else { + camera_stream_combination_t streamComb{}; + streamComb.operation_mode = static_cast<uint32_t> (streams.operationMode); + streamComb.num_streams = streams.streams.size(); + camera_stream_t *streamBuffer = new camera_stream_t[streamComb.num_streams]; + + size_t i = 0; + for (const auto &it : streams.streams) { + streamBuffer[i].stream_type = static_cast<int> (it.v3_2.streamType); + streamBuffer[i].width = it.v3_2.width; + streamBuffer[i].height = it.v3_2.height; + streamBuffer[i].format = static_cast<int> (it.v3_2.format); + streamBuffer[i].data_space = static_cast<android_dataspace_t> (it.v3_2.dataSpace); + streamBuffer[i].usage = static_cast<uint32_t> (it.v3_2.usage); + streamBuffer[i].physical_camera_id = it.physicalCameraId.c_str(); + streamBuffer[i++].rotation = static_cast<int> (it.v3_2.rotation); + } + streamComb.streams = streamBuffer; + auto res = mModule->isStreamCombinationSupported(mCameraIdInt, &streamComb); + switch (res) { + case NO_ERROR: + streamsSupported = true; + status = Status::OK; + break; + case BAD_VALUE: + status = Status::OK; + break; + case INVALID_OPERATION: + status = Status::METHOD_NOT_SUPPORTED; + break; + default: + ALOGE("%s: Unexpected error: %d", __FUNCTION__, res); + status = Status::INTERNAL_ERROR; + }; + delete [] streamBuffer; + } + + _hidl_cb(status, streamsSupported); + return Void(); +} + +// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice. + +} // namespace implementation +} // namespace V3_5 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + diff --git a/camera/device/3.5/default/CameraDeviceSession.cpp b/camera/device/3.5/default/CameraDeviceSession.cpp new file mode 100644 index 0000000000..0770f0418c --- /dev/null +++ b/camera/device/3.5/default/CameraDeviceSession.cpp @@ -0,0 +1,364 @@ +/* + * 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. + */ + +#define LOG_TAG "CamDevSession@3.5-impl" +#define ATRACE_TAG ATRACE_TAG_CAMERA +#include <android/log.h> + +#include <vector> +#include <utils/Trace.h> +#include "CameraDeviceSession.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +CameraDeviceSession::CameraDeviceSession( + camera3_device_t* device, + const camera_metadata_t* deviceInfo, + const sp<V3_2::ICameraDeviceCallback>& callback) : + V3_4::implementation::CameraDeviceSession(device, deviceInfo, callback) { + + mCallback_3_5 = nullptr; + + auto castResult = ICameraDeviceCallback::castFrom(callback); + if (castResult.isOk()) { + sp<ICameraDeviceCallback> callback3_5 = castResult; + if (callback3_5 != nullptr) { + mCallback_3_5 = callback3_5; + } + } + + if (mCallback_3_5 != nullptr) { + camera_metadata_entry bufMgrVersion = mDeviceInfo.find( + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION); + if (bufMgrVersion.count > 0) { + mSupportBufMgr = (bufMgrVersion.data.u8[0] == + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5); + if (mSupportBufMgr) { + request_stream_buffers = sRequestStreamBuffers; + return_stream_buffers = sReturnStreamBuffers; + } + } + } +} + +CameraDeviceSession::~CameraDeviceSession() { +} + +Return<void> CameraDeviceSession::configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb) { + configureStreams_3_4_Impl(requestedConfiguration.v3_4, _hidl_cb, + requestedConfiguration.streamConfigCounter); + return Void(); +} + +Return<void> CameraDeviceSession::signalStreamFlush( + const hidl_vec<int32_t>& streamIds, uint32_t streamConfigCounter) { + std::vector<camera3_stream_t*> streams(streamIds.size()); + { + Mutex::Autolock _l(mInflightLock); + for (size_t i = 0; i < streamIds.size(); i++) { + int32_t id = streamIds[i]; + if (mStreamMap.count(id) == 0) { + ALOGE("%s: unknown streamId %d", __FUNCTION__, id); + return Void(); + } + streams[i] = &mStreamMap[id]; + } + } + if (mDevice->ops->signal_stream_flush != nullptr) { + mDevice->ops->signal_stream_flush(mDevice, + streamConfigCounter, streams.size(), streams.data()); + } + return Void(); +} + +Status CameraDeviceSession::importRequest( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences) { + if (mSupportBufMgr) { + return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true); + } + return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false); +} + +void CameraDeviceSession::pushBufferId( + const buffer_handle_t& buf, uint64_t bufferId, int streamId) { + std::lock_guard<std::mutex> lock(mBufferIdMapLock); + + // emplace will return existing entry if there is one. + auto pair = mBufferIdMaps.emplace(streamId, BufferIdMap{}); + BufferIdMap& bIdMap = pair.first->second; + bIdMap[buf] = bufferId; +} + +uint64_t CameraDeviceSession::popBufferId( + const buffer_handle_t& buf, int streamId) { + std::lock_guard<std::mutex> lock(mBufferIdMapLock); + + auto streamIt = mBufferIdMaps.find(streamId); + if (streamIt == mBufferIdMaps.end()) { + return BUFFER_ID_NO_BUFFER; + } + BufferIdMap& bIdMap = streamIt->second; + auto it = bIdMap.find(buf); + if (it == bIdMap.end()) { + return BUFFER_ID_NO_BUFFER; + } + uint64_t bufId = it->second; + bIdMap.erase(it); + if (bIdMap.empty()) { + mBufferIdMaps.erase(streamIt); + } + return bufId; +} + +uint64_t CameraDeviceSession::getCapResultBufferId(const buffer_handle_t& buf, int streamId) { + if (mSupportBufMgr) { + return popBufferId(buf, streamId); + } + return BUFFER_ID_NO_BUFFER; +} + +Camera3Stream* CameraDeviceSession::getStreamPointer(int32_t streamId) { + Mutex::Autolock _l(mInflightLock); + if (mStreamMap.count(streamId) == 0) { + ALOGE("%s: unknown streamId %d", __FUNCTION__, streamId); + return nullptr; + } + return &mStreamMap[streamId]; +} + +void CameraDeviceSession::cleanupInflightBufferFences( + std::vector<int>& fences, std::vector<std::pair<buffer_handle_t, int>>& bufs) { + hidl_vec<int> hFences = fences; + cleanupInflightFences(hFences, fences.size()); + for (auto& p : bufs) { + popBufferId(p.first, p.second); + } +} + +camera3_buffer_request_status_t CameraDeviceSession::requestStreamBuffers( + uint32_t num_buffer_reqs, + const camera3_buffer_request_t *buffer_reqs, + /*out*/uint32_t *num_returned_buf_reqs, + /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) { + ATRACE_CALL(); + *num_returned_buf_reqs = 0; + hidl_vec<BufferRequest> hBufReqs(num_buffer_reqs); + for (size_t i = 0; i < num_buffer_reqs; i++) { + hBufReqs[i].streamId = + static_cast<Camera3Stream*>(buffer_reqs[i].stream)->mId; + hBufReqs[i].numBuffersRequested = buffer_reqs[i].num_buffers_requested; + } + + ATRACE_BEGIN("HIDL requestStreamBuffers"); + BufferRequestStatus status; + hidl_vec<StreamBufferRet> bufRets; + auto err = mCallback_3_5->requestStreamBuffers(hBufReqs, + [&status, &bufRets] + (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) { + status = s; + bufRets = std::move(rets); + }); + if (!err.isOk()) { + ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + ATRACE_END(); + + if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) { + if (bufRets.size() != num_buffer_reqs) { + ALOGE("%s: expect %d buffer requests returned, only got %zu", + __FUNCTION__, num_buffer_reqs, bufRets.size()); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + + for (size_t i = 0; i < num_buffer_reqs; i++) { + // maybe we can query all streams in one call to avoid frequent locking device here? + Camera3Stream* stream = getStreamPointer(bufRets[i].streamId); + if (stream == nullptr) { + ALOGE("%s: unknown streamId %d", __FUNCTION__, bufRets[i].streamId); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + returned_buf_reqs[i].stream = stream; + } + + std::vector<int> importedFences; + std::vector<std::pair<buffer_handle_t, int>> importedBuffers; + for (size_t i = 0; i < num_buffer_reqs; i++) { + int streamId = bufRets[i].streamId; + switch (bufRets[i].val.getDiscriminator()) { + case StreamBuffersVal::hidl_discriminator::error: + returned_buf_reqs[i].num_output_buffers = 0; + switch (bufRets[i].val.error()) { + case StreamBufferRequestError::NO_BUFFER_AVAILABLE: + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_NO_BUFFER_AVAILABLE; + break; + case StreamBufferRequestError::MAX_BUFFER_EXCEEDED: + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_MAX_BUFFER_EXCEEDED; + break; + case StreamBufferRequestError::STREAM_DISCONNECTED: + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_STREAM_DISCONNECTED; + break; + case StreamBufferRequestError::UNKNOWN_ERROR: + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_UNKNOWN_ERROR; + break; + default: + ALOGE("%s: Unknown StreamBufferRequestError %d", + __FUNCTION__, bufRets[i].val.error()); + cleanupInflightBufferFences(importedFences, importedBuffers); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + break; + case StreamBuffersVal::hidl_discriminator::buffers: { + const hidl_vec<StreamBuffer>& hBufs = bufRets[i].val.buffers(); + camera3_stream_buffer_t* outBufs = returned_buf_reqs[i].output_buffers; + for (size_t b = 0; b < hBufs.size(); b++) { + const StreamBuffer& hBuf = hBufs[b]; + camera3_stream_buffer_t& outBuf = outBufs[b]; + // maybe add importBuffers API to avoid frequent locking device? + Status s = importBuffer(streamId, + hBuf.bufferId, hBuf.buffer.getNativeHandle(), + /*out*/&(outBuf.buffer), + /*allowEmptyBuf*/false); + if (s != Status::OK) { + ALOGE("%s: import stream %d bufferId %" PRIu64 " failed!", + __FUNCTION__, streamId, hBuf.bufferId); + cleanupInflightBufferFences(importedFences, importedBuffers); + // Buffer import should never fail - restart HAL since something is very + // wrong. + assert(false); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + + pushBufferId(*(outBuf.buffer), hBuf.bufferId, streamId); + importedBuffers.push_back(std::make_pair(*(outBuf.buffer), streamId)); + + if (!sHandleImporter.importFence( + hBuf.acquireFence, + outBuf.acquire_fence)) { + ALOGE("%s: stream %d bufferId %" PRIu64 "acquire fence is invalid", + __FUNCTION__, streamId, hBuf.bufferId); + cleanupInflightBufferFences(importedFences, importedBuffers); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + importedFences.push_back(outBuf.acquire_fence); + outBuf.stream = returned_buf_reqs[i].stream; + outBuf.status = CAMERA3_BUFFER_STATUS_OK; + outBuf.release_fence = -1; + } + returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_OK; + } break; + default: + ALOGE("%s: unknown StreamBuffersVal discrimator!", __FUNCTION__); + cleanupInflightBufferFences(importedFences, importedBuffers); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + } + + *num_returned_buf_reqs = num_buffer_reqs; + + return (status == BufferRequestStatus::OK) ? + CAMERA3_BUF_REQ_OK : CAMERA3_BUF_REQ_FAILED_PARTIAL; + } + + switch (status) { + case BufferRequestStatus::FAILED_CONFIGURING: + return CAMERA3_BUF_REQ_FAILED_CONFIGURING; + case BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS: + return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS; + case BufferRequestStatus::FAILED_UNKNOWN: + default: + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } +} + +void CameraDeviceSession::returnStreamBuffers( + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers) { + ATRACE_CALL(); + hidl_vec<StreamBuffer> hBufs(num_buffers); + + for (size_t i = 0; i < num_buffers; i++) { + hBufs[i].streamId = + static_cast<Camera3Stream*>(buffers[i]->stream)->mId; + hBufs[i].buffer = nullptr; // use bufferId + hBufs[i].bufferId = popBufferId(*(buffers[i]->buffer), hBufs[i].streamId); + if (hBufs[i].bufferId == BUFFER_ID_NO_BUFFER) { + ALOGE("%s: unknown buffer is returned to stream %d", + __FUNCTION__, hBufs[i].streamId); + } + // ERROR since the buffer is not for application to consume + hBufs[i].status = BufferStatus::ERROR; + // skip acquire fence since it's of no use to camera service + if (buffers[i]->release_fence != -1) { + native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0); + handle->data[0] = buffers[i]->release_fence; + hBufs[i].releaseFence.setTo(handle, /*shouldOwn*/true); + } + } + + mCallback_3_5->returnStreamBuffers(hBufs); + return; +} + +/** + * Static callback forwarding methods from HAL to instance + */ +camera3_buffer_request_status_t CameraDeviceSession::sRequestStreamBuffers( + const struct camera3_callback_ops *cb, + uint32_t num_buffer_reqs, + const camera3_buffer_request_t *buffer_reqs, + /*out*/uint32_t *num_returned_buf_reqs, + /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) { + CameraDeviceSession *d = + const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); + + if (num_buffer_reqs == 0 || buffer_reqs == nullptr || num_returned_buf_reqs == nullptr || + returned_buf_reqs == nullptr) { + ALOGE("%s: bad argument: numBufReq %d, bufReqs %p, numRetBufReq %p, retBufReqs %p", + __FUNCTION__, num_buffer_reqs, buffer_reqs, + num_returned_buf_reqs, returned_buf_reqs); + return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS; + } + + return d->requestStreamBuffers(num_buffer_reqs, buffer_reqs, + num_returned_buf_reqs, returned_buf_reqs); +} + +void CameraDeviceSession::sReturnStreamBuffers( + const struct camera3_callback_ops *cb, + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers) { + CameraDeviceSession *d = + const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); + + d->returnStreamBuffers(num_buffers, buffers); +} + +} // namespace implementation +} // namespace V3_5 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/device/3.5/default/ExternalCameraDevice.cpp b/camera/device/3.5/default/ExternalCameraDevice.cpp new file mode 100644 index 0000000000..6a0b51e09f --- /dev/null +++ b/camera/device/3.5/default/ExternalCameraDevice.cpp @@ -0,0 +1,118 @@ +/* + * 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. + */ + +#define LOG_TAG "ExtCamDev@3.5" +//#define LOG_NDEBUG 0 +#include <log/log.h> + +#include "ExternalCameraDevice_3_5.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +ExternalCameraDevice::ExternalCameraDevice( + const std::string& cameraId, const ExternalCameraConfig& cfg) : + V3_4::implementation::ExternalCameraDevice(cameraId, cfg) {} + +ExternalCameraDevice::~ExternalCameraDevice() {} + +Return<void> ExternalCameraDevice::getPhysicalCameraCharacteristics(const hidl_string&, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) { + CameraMetadata cameraCharacteristics; + // External camera HAL doesn't support physical camera functions + _hidl_cb(Status::ILLEGAL_ARGUMENT, cameraCharacteristics); + return Void(); +} + +sp<V3_4::implementation::ExternalCameraDeviceSession> ExternalCameraDevice::createSession( + const sp<V3_2::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 new ExternalCameraDeviceSession( + cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)); +} + +#define UPDATE(tag, data, size) \ +do { \ + if (metadata->update((tag), (data), (size))) { \ + ALOGE("Update " #tag " failed!"); \ + return -EINVAL; \ + } \ +} while (0) + +status_t ExternalCameraDevice::initDefaultCharsKeys( + ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) { + status_t res = + V3_4::implementation::ExternalCameraDevice::initDefaultCharsKeys(metadata); + + if (res != OK) { + return res; + } + + const uint8_t bufMgrVer = ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5; + UPDATE(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &bufMgrVer, 1); + + std::vector<int> availableCharacteristicsKeys = AVAILABLE_CHARACTERISTICS_KEYS_3_4; + availableCharacteristicsKeys.reserve(availableCharacteristicsKeys.size() + + EXTRA_CHARACTERISTICS_KEYS_3_5.size()); + for (const auto& key : EXTRA_CHARACTERISTICS_KEYS_3_5) { + availableCharacteristicsKeys.push_back(key); + } + UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, + availableCharacteristicsKeys.data(), + availableCharacteristicsKeys.size()); + + return OK; +} + +Return<void> ExternalCameraDevice::isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) { + + if (isInitFailed()) { + ALOGE("%s: camera %s. camera init failed!", __FUNCTION__, mCameraId.c_str()); + _hidl_cb(Status::INTERNAL_ERROR, false); + return Void(); + } + + hidl_vec<V3_2::Stream> streamsV3_2(streams.streams.size()); + size_t i = 0; + for (const auto& it : streams.streams) { + streamsV3_2[i++] = it.v3_2; + } + V3_2::StreamConfiguration streamConfig = {streamsV3_2, streams.operationMode}; + auto status = ExternalCameraDeviceSession::isStreamCombinationSupported(streamConfig, + mSupportedFormats); + _hidl_cb(Status::OK, Status::OK == status); + return Void(); +} +#undef UPDATE + +} // namespace implementation +} // namespace V3_5 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp new file mode 100644 index 0000000000..ae7c45e081 --- /dev/null +++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp @@ -0,0 +1,303 @@ +/* + * 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. + */ + +#define LOG_TAG "ExtCamDevSsn@3.5" +#include <android/log.h> + +#include <utils/Trace.h> +#include "ExternalCameraDeviceSession.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +ExternalCameraDeviceSession::ExternalCameraDeviceSession( + const sp<V3_2::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) : + V3_4::implementation::ExternalCameraDeviceSession( + callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) { + + mCallback_3_5 = nullptr; + + auto castResult = V3_5::ICameraDeviceCallback::castFrom(callback); + if (castResult.isOk()) { + sp<V3_5::ICameraDeviceCallback> callback3_5 = castResult; + if (callback3_5 != nullptr) { + mCallback_3_5 = callback3_5; + } + } + + if (mCallback_3_5 != nullptr) { + mSupportBufMgr = true; + } +} + +ExternalCameraDeviceSession::~ExternalCameraDeviceSession() { + closeOutputThreadImpl(); +} + +Return<void> ExternalCameraDeviceSession::configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb) { + return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb); +} + +Return<void> ExternalCameraDeviceSession::signalStreamFlush( + const hidl_vec<int32_t>& /*streamIds*/, uint32_t /*streamConfigCounter*/) { + return Void(); +} + +Status ExternalCameraDeviceSession::importRequestLocked( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences) { + if (mSupportBufMgr) { + return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true); + } + return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false); +} + + +ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread( + wp<ExternalCameraDeviceSession> parent, + sp<V3_5::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>* outBufReq) { + 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; + *outBufReq = 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; + } + std::chrono::milliseconds 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 hidl 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("HIDL requestStreamBuffers"); + BufferRequestStatus status; + hidl_vec<StreamBufferRet> bufRets; + auto err = mCallbacks->requestStreamBuffers(mHalBufferReqs, + [&status, &bufRets] + (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) { + status = s; + bufRets = std::move(rets); + }); + ATRACE_END(); + if (!err.isOk()) { + ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); + 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.promote(); + if (parent == nullptr) { + ALOGE("%s: session has been disconnected!", __FUNCTION__); + return false; + } + + hidl_vec<int> importedFences; + importedFences.resize(bufRets.size()); + for (size_t i = 0; i < bufRets.size(); i++) { + int streamId = bufRets[i].streamId; + switch (bufRets[i].val.getDiscriminator()) { + case StreamBuffersVal::hidl_discriminator::error: + continue; + case StreamBuffersVal::hidl_discriminator::buffers: { + const hidl_vec<V3_2::StreamBuffer>& hBufs = bufRets[i].val.buffers(); + if (hBufs.size() != 1) { + ALOGE("%s: expect 1 buffer returned, got %zu!", __FUNCTION__, hBufs.size()); + return false; + } + const V3_2::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, hBuf.buffer.getNativeHandle(), + /*out*/&mBufferReqs[i].bufPtr, + /*allowEmptyBuf*/false); + lk.lock(); + + if (s != Status::OK) { + ALOGE("%s: stream %d import buffer failed!", __FUNCTION__, streamId); + cleanupInflightFences(importedFences, i - 1); + return false; + } + if (!sHandleImporter.importFence(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: unkown StreamBuffersVal discrimator!", __FUNCTION__); + return false; + } + } + } else { + ALOGE("%s: requestStreamBuffers call failed!", __FUNCTION__); + } + + mPendingReturnBufferReqs = std::move(mBufferReqs); + mBufferReqs.clear(); + + lk.unlock(); + mRequestDoneCond.notify_one(); + return true; +} + +void ExternalCameraDeviceSession::initOutputThread() { + if (mSupportBufMgr) { + mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5); + mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY); + } + mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread); +} + +void ExternalCameraDeviceSession::closeOutputThreadImpl() { + if (mBufferRequestThread) { + mBufferRequestThread->requestExit(); + mBufferRequestThread->join(); + mBufferRequestThread.clear(); + } +} + +void ExternalCameraDeviceSession::closeOutputThread() { + closeOutputThreadImpl(); + V3_4::implementation::ExternalCameraDeviceSession::closeOutputThread(); +} + +ExternalCameraDeviceSession::OutputThread::OutputThread( + wp<ExternalCameraDeviceSession> parent, + CroppingType ct, + sp<BufferRequestThread> bufReqThread) : + V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct), + mBufferRequestThread(bufReqThread) {} + +ExternalCameraDeviceSession::OutputThread::~OutputThread() {} + +int ExternalCameraDeviceSession::OutputThread::requestBufferStart( + const std::vector<HalStreamBuffer>& bufs) { + if (mBufferRequestThread != nullptr) { + return mBufferRequestThread->requestBufferStart(bufs); + } + return 0; +} + +int ExternalCameraDeviceSession::OutputThread::waitForBufferRequestDone( + /*out*/std::vector<HalStreamBuffer>* outBufs) { + if (mBufferRequestThread != nullptr) { + return mBufferRequestThread->waitForBufferRequestDone(outBufs); + } + return 0; +} + +} // namespace implementation +} // namespace V3_5 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/device/3.5/default/OWNERS b/camera/device/3.5/default/OWNERS new file mode 100644 index 0000000000..369b2048cb --- /dev/null +++ b/camera/device/3.5/default/OWNERS @@ -0,0 +1,7 @@ +cychen@google.com +epeev@google.com +etalvala@google.com +jchowdhary@google.com +shuzhenwang@google.com +yinchiayeh@google.com +zhijunhe@google.com diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h new file mode 100644 index 0000000000..4f7284c5fe --- /dev/null +++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h @@ -0,0 +1,253 @@ +/* + * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H + +#include <android/hardware/camera/device/3.5/ICameraDevice.h> +#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h> +#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h> +#include <../../3.4/default/include/device_v3_4_impl/CameraDeviceSession.h> +#include <unordered_map> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +using namespace ::android::hardware::camera::device; +using ::android::hardware::camera::device::V3_2::BufferStatus; +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::StreamBuffer; +using ::android::hardware::camera::device::V3_5::StreamConfiguration; +using ::android::hardware::camera::device::V3_4::HalStreamConfiguration; +using ::android::hardware::camera::device::V3_5::ICameraDeviceSession; +using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback; +using ::android::hardware::camera::device::V3_2::implementation::Camera3Stream; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; + + +/** + * Function pointer types with C calling convention to + * use for HAL callback functions. + */ +extern "C" { + typedef camera3_buffer_request_status_t (callbacks_request_stream_buffer_t)( + const struct camera3_callback_ops *, + uint32_t num_buffer_reqs, + const camera3_buffer_request_t *buffer_reqs, + /*out*/uint32_t *num_returned_buf_reqs, + /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs); + + typedef void (callbacks_return_stream_buffer_t)( + const struct camera3_callback_ops *, + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers); +} + +struct CameraDeviceSession : public V3_4::implementation::CameraDeviceSession { + + CameraDeviceSession(camera3_device_t*, + const camera_metadata_t* deviceInfo, + const sp<V3_2::ICameraDeviceCallback>&); + virtual ~CameraDeviceSession(); + + virtual sp<V3_2::ICameraDeviceSession> getInterface() override { + return new TrampolineSessionInterface_3_5(this); + } + +protected: + // Methods from v3.4 and earlier will trampoline to inherited implementation + Return<void> configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb); + + Return<void> signalStreamFlush( + const hidl_vec<int32_t>& streamIds, + uint32_t streamConfigCounter); + + virtual Status importRequest( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences) override; + + /** + * Static callback forwarding methods from HAL to instance + */ + static callbacks_request_stream_buffer_t sRequestStreamBuffers; + static callbacks_return_stream_buffer_t sReturnStreamBuffers; + + camera3_buffer_request_status_t requestStreamBuffers( + uint32_t num_buffer_reqs, + const camera3_buffer_request_t *buffer_reqs, + /*out*/uint32_t *num_returned_buf_reqs, + /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs); + + void returnStreamBuffers( + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers); + + struct BufferHasher { + size_t operator()(const buffer_handle_t& buf) const { + if (buf == nullptr) + return 0; + + size_t result = 1; + result = 31 * result + buf->numFds; + for (int i = 0; i < buf->numFds; i++) { + result = 31 * result + buf->data[i]; + } + return result; + } + }; + + struct BufferComparator { + bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const { + if (buf1->numFds == buf2->numFds) { + for (int i = 0; i < buf1->numFds; i++) { + if (buf1->data[i] != buf2->data[i]) { + return false; + } + } + return true; + } + return false; + } + }; + + Camera3Stream* getStreamPointer(int32_t streamId); + + // Register buffer to mBufferIdMaps so we can find corresponding bufferId + // when the buffer is returned to camera service + void pushBufferId(const buffer_handle_t& buf, uint64_t bufferId, int streamId); + + // Method to pop buffer's bufferId from mBufferIdMaps + // BUFFER_ID_NO_BUFFER is returned if no matching buffer is found + uint64_t popBufferId(const buffer_handle_t& buf, int streamId); + + // Method to cleanup imported buffer/fences if requestStreamBuffers fails half way + void cleanupInflightBufferFences( + std::vector<int>& fences, std::vector<std::pair<buffer_handle_t, int>>& bufs); + + // Overrides the default constructCaptureResult behavior for buffer management APIs + virtual uint64_t getCapResultBufferId(const buffer_handle_t& buf, int streamId) override; + + std::mutex mBufferIdMapLock; // protecting mBufferIdMaps and mNextBufferId + typedef std::unordered_map<const buffer_handle_t, uint64_t, + BufferHasher, BufferComparator> BufferIdMap; + // stream ID -> per stream buffer ID map for buffers coming from requestStreamBuffers API + // Entries are created during requestStreamBuffers when a stream first request a buffer, and + // deleted in returnStreamBuffers/processCaptureResult* when all buffers are returned + std::unordered_map<int, BufferIdMap> mBufferIdMaps; + + sp<ICameraDeviceCallback> mCallback_3_5; + bool mSupportBufMgr; + +private: + + struct TrampolineSessionInterface_3_5 : public ICameraDeviceSession { + TrampolineSessionInterface_3_5(sp<CameraDeviceSession> parent) : + mParent(parent) {} + + virtual Return<void> constructDefaultRequestSettings( + V3_2::RequestTemplate type, + V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override { + return mParent->constructDefaultRequestSettings(type, _hidl_cb); + } + + virtual Return<void> configureStreams( + const V3_2::StreamConfiguration& requestedConfiguration, + V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override { + return mParent->configureStreams(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> processCaptureRequest_3_4( + const hidl_vec<V3_4::CaptureRequest>& requests, + const hidl_vec<V3_2::BufferCache>& cachesToRemove, + ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override { + return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb); + } + + virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests, + const hidl_vec<V3_2::BufferCache>& cachesToRemove, + V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override { + return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb); + } + + virtual Return<void> getCaptureRequestMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureRequestMetadataQueue(_hidl_cb); + } + + virtual Return<void> getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return<Status> flush() override { + return mParent->flush(); + } + + virtual Return<void> close() override { + return mParent->close(); + } + + virtual Return<void> configureStreams_3_3( + const V3_2::StreamConfiguration& requestedConfiguration, + configureStreams_3_3_cb _hidl_cb) override { + return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> configureStreams_3_4( + const V3_4::StreamConfiguration& requestedConfiguration, + configureStreams_3_4_cb _hidl_cb) override { + return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + configureStreams_3_5_cb _hidl_cb) override { + return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> signalStreamFlush( + const hidl_vec<int32_t>& requests, + uint32_t streamConfigCounter) override { + return mParent->signalStreamFlush(requests, streamConfigCounter); + } + + private: + sp<CameraDeviceSession> mParent; + }; +}; + +} // namespace implementation +} // namespace V3_5 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h new file mode 100644 index 0000000000..76c8cf80a0 --- /dev/null +++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h @@ -0,0 +1,122 @@ +/* + * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H + +#include "CameraDeviceSession.h" +#include <../../../../3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h> + +#include <android/hardware/camera/device/3.5/ICameraDevice.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +using namespace ::android::hardware::camera::device; + +using ::android::hardware::camera::common::V1_0::helper::CameraModule; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_string; +using ::android::hardware::camera::common::V1_0::TorchMode; +using ::android::hardware::camera::common::V1_0::helper::CameraModule; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::sp; + +struct CameraDevice : public V3_4::implementation::CameraDevice { + // Called by 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. + // Delegates nearly all work to CameraDevice_3_4 + CameraDevice(sp<CameraModule> module, + const std::string& cameraId, + const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames); + virtual ~CameraDevice(); + + virtual sp<V3_2::ICameraDevice> getInterface() override { + return new TrampolineDeviceInterface_3_5(this); + } + +protected: + virtual sp<V3_2::implementation::CameraDeviceSession> createSession(camera3_device_t*, + const camera_metadata_t* deviceInfo, + const sp<V3_2::ICameraDeviceCallback>&) override; + + Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb); + + Return<void> isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb); + +private: + struct TrampolineDeviceInterface_3_5 : public ICameraDevice { + TrampolineDeviceInterface_3_5(sp<CameraDevice> parent) : + mParent(parent) {} + + virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return<void> getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return<Status> setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return<void> dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + virtual Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override { + return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb); + } + + virtual Return<void> isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override { + return mParent->isStreamCombinationSupported(streams, _hidl_cb); + } + + private: + sp<CameraDevice> mParent; + }; +}; + +} // namespace implementation +} // namespace V3_5 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h new file mode 100644 index 0000000000..aa119fc183 --- /dev/null +++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h @@ -0,0 +1,262 @@ +/* + * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H + +#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h> +#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h> +#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +using ::android::hardware::camera::device::V3_2::BufferCache; +using ::android::hardware::camera::device::V3_5::BufferRequest; +using ::android::hardware::camera::device::V3_5::BufferRequestStatus; +using ::android::hardware::camera::device::V3_2::BufferStatus; +using ::android::hardware::camera::device::V3_2::CameraMetadata; +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::CaptureResult; +using ::android::hardware::camera::device::V3_2::ErrorCode; +using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback; +using ::android::hardware::camera::device::V3_2::MsgType; +using ::android::hardware::camera::device::V3_2::NotifyMsg; +using ::android::hardware::camera::device::V3_2::RequestTemplate; +using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::camera::device::V3_5::StreamConfiguration; +using ::android::hardware::camera::device::V3_2::StreamConfigurationMode; +using ::android::hardware::camera::device::V3_2::StreamRotation; +using ::android::hardware::camera::device::V3_2::StreamType; +using ::android::hardware::camera::device::V3_2::DataspaceFlags; +using ::android::hardware::camera::device::V3_2::CameraBlob; +using ::android::hardware::camera::device::V3_2::CameraBlobId; +using ::android::hardware::camera::device::V3_4::HalStreamConfiguration; +using ::android::hardware::camera::device::V3_5::ICameraDeviceSession; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::camera::common::V1_0::helper::ExifUtils; +using ::android::hardware::camera::external::common::ExternalCameraConfig; +using ::android::hardware::camera::external::common::Size; +using ::android::hardware::camera::external::common::SizeHasher; +using ::android::hardware::graphics::common::V1_0::BufferUsage; +using ::android::hardware::graphics::common::V1_0::Dataspace; +using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; +using ::android::base::unique_fd; + +using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format; +using ::android::hardware::camera::device::V3_4::implementation::CroppingType; + +struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession { + + ExternalCameraDeviceSession(const sp<V3_2::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); + virtual ~ExternalCameraDeviceSession(); + + // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when + // dealing with minor version revs and simultaneous implementation and interface inheritance + virtual sp<V3_4::ICameraDeviceSession> getInterface() override { + return new TrampolineSessionInterface_3_5(this); + } + + static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config, + const std::vector<SupportedV4L2Format>& supportedFormats) { + return V3_4::implementation::ExternalCameraDeviceSession::isStreamCombinationSupported( + config, supportedFormats); + } + +protected: + // Methods from v3.4 and earlier will trampoline to inherited implementation + Return<void> configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb); + + Return<void> signalStreamFlush( + const hidl_vec<int32_t>& requests, + uint32_t streamConfigCounter); + + virtual void initOutputThread() override; + virtual void closeOutputThread() override; + void closeOutputThreadImpl(); + + virtual Status importRequestLocked( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences) override; + + class BufferRequestThread : public android::Thread { + public: + BufferRequestThread( + wp<ExternalCameraDeviceSession> parent, + sp<V3_5::ICameraDeviceCallback> callbacks); + + int requestBufferStart(const std::vector<HalStreamBuffer>&); + int waitForBufferRequestDone( + /*out*/std::vector<HalStreamBuffer>*); + + virtual bool threadLoop() override; + + private: + void waitForNextRequest(); + + const wp<ExternalCameraDeviceSession> mParent; + const sp<V3_5::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 + hidl_vec<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 + }; + + sp<BufferRequestThread> mBufferRequestThread; + + class OutputThread : + public V3_4::implementation::ExternalCameraDeviceSession::OutputThread { + public: + // TODO: pass buffer request thread to OutputThread ctor + OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType, + sp<BufferRequestThread> bufReqThread); + virtual ~OutputThread(); + + protected: + // Methods to request output buffer in parallel + virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override; + virtual int waitForBufferRequestDone( + /*out*/std::vector<HalStreamBuffer>*) override; + + const sp<BufferRequestThread> mBufferRequestThread; + }; + + sp<V3_5::ICameraDeviceCallback> mCallback_3_5; + bool mSupportBufMgr; + +private: + + struct TrampolineSessionInterface_3_5 : public ICameraDeviceSession { + TrampolineSessionInterface_3_5(sp<ExternalCameraDeviceSession> parent) : + mParent(parent) {} + + virtual Return<void> constructDefaultRequestSettings( + RequestTemplate type, + V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override { + return mParent->constructDefaultRequestSettings(type, _hidl_cb); + } + + virtual Return<void> configureStreams( + const V3_2::StreamConfiguration& requestedConfiguration, + V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override { + return mParent->configureStreams(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests, + const hidl_vec<V3_2::BufferCache>& cachesToRemove, + V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override { + return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb); + } + + virtual Return<void> getCaptureRequestMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureRequestMetadataQueue(_hidl_cb); + } + + virtual Return<void> getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return<Status> flush() override { + return mParent->flush(); + } + + virtual Return<void> close() override { + return mParent->close(); + } + + virtual Return<void> configureStreams_3_3( + const V3_2::StreamConfiguration& requestedConfiguration, + configureStreams_3_3_cb _hidl_cb) override { + return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> configureStreams_3_4( + const V3_4::StreamConfiguration& requestedConfiguration, + configureStreams_3_4_cb _hidl_cb) override { + return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests, + const hidl_vec<V3_2::BufferCache>& cachesToRemove, + ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override { + return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb); + } + + virtual Return<void> configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + configureStreams_3_5_cb _hidl_cb) override { + return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb); + } + + virtual Return<void> signalStreamFlush( + const hidl_vec<int32_t>& requests, + uint32_t streamConfigCounter) override { + return mParent->signalStreamFlush(requests, streamConfigCounter); + } + + private: + sp<ExternalCameraDeviceSession> mParent; + }; +}; + +} // namespace implementation +} // namespace V3_5 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h new file mode 100644 index 0000000000..b73490cb47 --- /dev/null +++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h @@ -0,0 +1,142 @@ +/* + * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE_H + +#include "utils/Mutex.h" +#include "CameraMetadata.h" + +#include <android/hardware/camera/device/3.5/ICameraDevice.h> +#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h> +#include <hidl/Status.h> +#include <hidl/MQDescriptor.h> +#include "ExternalCameraDeviceSession.h" +#include <../../../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +using namespace ::android::hardware::camera::device; +using ::android::hardware::camera::device::V3_5::ICameraDevice; +using ::android::hardware::camera::common::V1_0::CameraResourceCost; +using ::android::hardware::camera::common::V1_0::TorchMode; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::external::common::ExternalCameraConfig; +using ::android::hardware::camera::external::common::Size; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * The camera device HAL implementation is opened lazily (via the open call) + */ +struct ExternalCameraDevice : public V3_4::implementation::ExternalCameraDevice { + + // 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& cameraId, const ExternalCameraConfig& cfg); + virtual ~ExternalCameraDevice(); + + virtual sp<V3_2::ICameraDevice> getInterface() override { + return new TrampolineDeviceInterface_3_5(this); + } + + Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb); + + Return<void> isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb); + +protected: + virtual sp<V3_4::implementation::ExternalCameraDeviceSession> createSession( + const sp<V3_2::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) override; + + virtual status_t initDefaultCharsKeys( + ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override; + + const std::vector<int32_t> EXTRA_CHARACTERISTICS_KEYS_3_5 = { + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION + }; + +private: + struct TrampolineDeviceInterface_3_5 : public ICameraDevice { + TrampolineDeviceInterface_3_5(sp<ExternalCameraDevice> parent) : + mParent(parent) {} + + virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return<void> getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return<Status> setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return<void> dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + virtual Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override { + return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb); + } + + virtual Return<void> isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override { + return mParent->isStreamCombinationSupported(streams, _hidl_cb); + } + + private: + sp<ExternalCameraDevice> mParent; + }; +}; + +} // namespace implementation +} // namespace V3_5 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE_H diff --git a/camera/device/3.5/types.hal b/camera/device/3.5/types.hal new file mode 100644 index 0000000000..613187d96e --- /dev/null +++ b/camera/device/3.5/types.hal @@ -0,0 +1,131 @@ +/* + * 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. + */ + +package android.hardware.camera.device@3.5; + +import @3.2::StreamBuffer; +import @3.4::StreamConfiguration; + +/** + * StreamConfiguration: + * + * Identical to @3.4::StreamConfiguration, except that it contains streamConfigCounter + */ +struct StreamConfiguration { + @3.4::StreamConfiguration v3_4; + + /** + * An incrementing counter used for HAL to keep track of the stream + * configuration and the paired oneway signalStreamFlush call. When the + * counter in signalStreamFlush call is less than the counter here, that + * signalStreamFlush call is stale. + */ + uint32_t streamConfigCounter; +}; + +enum StreamBufferRequestError : uint32_t { + /** + * Get buffer failed due to timeout waiting for an available buffer. This is + * likely due to the client application holding too many buffers, or the + * system is under memory pressure. + * This is not a fatal error. HAL may try to request buffer for this stream + * later. If HAL cannot get a buffer for certain capture request in time + * due to this error, HAL can send an ERROR_REQUEST to camera service and + * drop processing that request. + */ + NO_BUFFER_AVAILABLE = 1, + + /** + * Get buffer failed due to HAL has reached its maxBuffer count. This is not + * a fatal error. HAL may try to request buffer for this stream again after + * it returns at least one buffer of that stream to camera service. + */ + MAX_BUFFER_EXCEEDED = 2, + + /** + * Get buffer failed due to the stream is disconnected by client + * application, has been removed, or not recognized by camera service. + * This means application is no longer interested in this stream. + * Requesting buffer for this stream must never succeed after this error is + * returned. HAL must safely return all buffers of this stream after + * getting this error. If HAL gets another capture request later targeting + * a disconnected stream, HAL must send an ERROR_REQUEST to camera service + * and drop processing that request. + */ + STREAM_DISCONNECTED = 3, + + /** + * Get buffer failed for unknown reasons. This is a fatal error and HAL must + * send ERROR_DEVICE to camera service and be ready to be closed. + */ + UNKNOWN_ERROR = 4 +}; + +/** + * Per-stream return value for requestStreamBuffers. + * For each stream, either an StreamBufferRequestError error code, or all + * requested buffers for this stream is returned, so buffers.size() must be + * equal to BufferRequest::numBuffersRequested of corresponding stream. + */ +safe_union StreamBuffersVal { + StreamBufferRequestError error; + vec<@3.2::StreamBuffer> buffers; +}; + +struct StreamBufferRet { + int32_t streamId; + StreamBuffersVal val; +}; + +enum BufferRequestStatus : uint32_t { + /** + * Method call succeeded and all requested buffers are returned. + */ + OK = 0, + + /** + * Method call failed for some streams. Check per stream status for each + * returned StreamBufferRet. + */ + FAILED_PARTIAL = 1, + + /** + * Method call failed for all streams and no buffers are returned at all. + * Camera service is about to or is performing configureStreams. HAL must + * wait until next configureStreams call is finished before requesting + * buffers again. + */ + FAILED_CONFIGURING = 2, + + /** + * Method call failed for all streams and no buffers are returned at all. + * Failure due to bad BufferRequest input, eg: unknown streamId or repeated + * streamId. + */ + FAILED_ILLEGAL_ARGUMENTS = 3, + + /** + * Method call failed for all streams and no buffers are returned at all. + * Failure due to unknown reason. + */ + FAILED_UNKNOWN = 4, +}; + +struct BufferRequest { + int32_t streamId; + uint32_t numBuffersRequested; +}; + diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal index 67b4e447d5..cef0397931 100644 --- a/camera/metadata/3.2/types.hal +++ b/camera/metadata/3.2/types.hal @@ -1396,7 +1396,8 @@ enum CameraMetadataTag : uint32_t { * * <p>The arrangement of color filters on sensor; * represents the colors in the top-left 2x2 section of - * the sensor, in reading order.</p> + * the sensor, in reading order, for a Bayer camera, or the + * light spectrum it captures for MONOCHROME camera.</p> */ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal index 04edfe9fb4..27d82b991a 100644 --- a/camera/metadata/3.3/types.hal +++ b/camera/metadata/3.3/types.hal @@ -100,7 +100,7 @@ enum CameraMetadataTag : @3.2::CameraMetadataTag { /** android.request.availablePhysicalCameraRequestKeys [static, int32[], hidden] * - * <p>A subset of the available request keys that can be overriden for + * <p>A subset of the available request keys that can be overridden for * physical devices backing a logical multi-camera.</p> */ ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS, @@ -109,8 +109,8 @@ enum CameraMetadataTag : @3.2::CameraMetadataTag { /** android.statistics.oisDataMode [dynamic, enum, public] * - * <p>A control for selecting whether OIS position information is included in output - * result metadata.</p> + * <p>A control for selecting whether optical stabilization (OIS) position + * information is included in output result metadata.</p> */ ANDROID_STATISTICS_OIS_DATA_MODE = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_STATISTICS_END, @@ -154,7 +154,7 @@ enum CameraMetadataTag : @3.2::CameraMetadataTag { ANDROID_INFO_END_3_3, - /** android.logicalMultiCamera.physicalIds [static, byte[], hidden] + /** android.logicalMultiCamera.physicalIds [static, byte[], ndk_public] * * <p>String containing the ids of the underlying physical cameras.</p> */ diff --git a/camera/metadata/3.4/Android.bp b/camera/metadata/3.4/Android.bp new file mode 100644 index 0000000000..388df6848c --- /dev/null +++ b/camera/metadata/3.4/Android.bp @@ -0,0 +1,22 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.camera.metadata@3.4", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + ], + interfaces: [ + "android.hardware.camera.metadata@3.2", + "android.hardware.camera.metadata@3.3", + ], + types: [ + "CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion", + "CameraMetadataTag", + ], + gen_java: true, +} + diff --git a/camera/metadata/3.4/types.hal b/camera/metadata/3.4/types.hal new file mode 100644 index 0000000000..9bbc90dc28 --- /dev/null +++ b/camera/metadata/3.4/types.hal @@ -0,0 +1,168 @@ +/* + * 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. + */ + +/* + * Autogenerated from camera metadata definitions in + * /system/media/camera/docs/metadata_definitions.xml + * *** DO NOT EDIT BY HAND *** + */ + +package android.hardware.camera.metadata@3.4; + +/* Include definitions from all prior minor HAL metadata revisions */ +import android.hardware.camera.metadata@3.2; +import android.hardware.camera.metadata@3.3; + +// No new metadata sections added in this revision + +/** + * Main enumeration for defining camera metadata tags added in this revision + * + * <p>Partial documentation is included for each tag; for complete documentation, reference + * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p> + */ +enum CameraMetadataTag : @3.3::CameraMetadataTag { + /** android.request.characteristicKeysNeedingPermission [static, int32[], hidden] + * + * <p>A list of camera characteristics keys that are only available + * in case the camera client has camera permission.</p> + */ + ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_REQUEST_END_3_3, + + ANDROID_REQUEST_END_3_4, + + /** android.scaler.availableRecommendedStreamConfigurations [static, enum[], ndk_public] + * + * <p>Recommended stream configurations for common client use cases.</p> + */ + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_SCALER_END, + + /** android.scaler.availableRecommendedInputOutputFormatsMap [static, int32, ndk_public] + * + * <p>Recommended mappings of image formats that are supported by this + * camera device for input streams, to their corresponding output formats.</p> + */ + ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP, + + ANDROID_SCALER_END_3_4, + + /** android.info.supportedBufferManagementVersion [static, enum, system] + * + * <p>The version of buffer management API this camera device supports and opts into.</p> + */ + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_INFO_END_3_3, + + ANDROID_INFO_END_3_4, + + /** android.depth.availableRecommendedDepthStreamConfigurations [static, int32[], ndk_public] + * + * <p>Recommended depth stream configurations for common client use cases.</p> + */ + ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_DEPTH_END, + + /** android.depth.availableDynamicDepthStreamConfigurations [static, enum[], ndk_public] + * + * <p>The available dynamic depth dataspace stream + * configurations that this camera device supports + * (i.e. format, width, height, output/input stream).</p> + */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, + + /** android.depth.availableDynamicDepthMinFrameDurations [static, int64[], ndk_public] + * + * <p>This lists the minimum frame duration for each + * format/size combination for dynamic depth output streams.</p> + */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, + + /** android.depth.availableDynamicDepthStallDurations [static, int64[], ndk_public] + * + * <p>This lists the maximum stall duration for each + * output format/size combination for dynamic depth streams.</p> + */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, + + ANDROID_DEPTH_END_3_4, + + /** android.logicalMultiCamera.activePhysicalId [dynamic, byte, public] + * + * <p>String containing the ID of the underlying active physical camera.</p> + */ + ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_LOGICAL_MULTI_CAMERA_END_3_3, + + ANDROID_LOGICAL_MULTI_CAMERA_END_3_4, + +}; + +/* + * Enumeration definitions for the various entries that need them + */ + +/** android.scaler.availableFormats enumeration values added since v3.2 + * @see ANDROID_SCALER_AVAILABLE_FORMATS + */ +enum CameraMetadataEnumAndroidScalerAvailableFormats : + @3.2::CameraMetadataEnumAndroidScalerAvailableFormats { + ANDROID_SCALER_AVAILABLE_FORMATS_RAW10 = 0x25, + ANDROID_SCALER_AVAILABLE_FORMATS_RAW12 = 0x26, + ANDROID_SCALER_AVAILABLE_FORMATS_Y8 = 0x20203859, +}; + +/** android.scaler.availableRecommendedStreamConfigurations enumeration values + * @see ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS + */ +enum CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations : uint32_t { + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PREVIEW + = 0x0, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RECORD + = 0x1, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VIDEO_SNAPSHOT + = 0x2, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_SNAPSHOT + = 0x3, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_ZSL + = 0x4, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RAW + = 0x5, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END + = 0x6, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START + = 0x18, +}; + +/** android.sensor.info.colorFilterArrangement enumeration values added since v3.2 + * @see ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT + */ +enum CameraMetadataEnumAndroidSensorInfoColorFilterArrangement : + @3.2::CameraMetadataEnumAndroidSensorInfoColorFilterArrangement { + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO, + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR, +}; + +/** android.info.supportedBufferManagementVersion enumeration values + * @see ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION + */ +enum CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion : uint32_t { + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5, +}; + +/** android.depth.availableDynamicDepthStreamConfigurations enumeration values + * @see ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS + */ +enum CameraMetadataEnumAndroidDepthAvailableDynamicDepthStreamConfigurations : uint32_t { + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_OUTPUT, + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_INPUT, +}; diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp index ae24d78143..81e5738cee 100644 --- a/camera/provider/2.4/default/Android.bp +++ b/camera/provider/2.4/default/Android.bp @@ -14,11 +14,14 @@ cc_library_shared { "android.hardware.camera.device@3.2", "android.hardware.camera.device@3.3", "android.hardware.camera.device@3.4", + "android.hardware.camera.device@3.5", "camera.device@1.0-impl", "camera.device@3.2-impl", "camera.device@3.3-impl", "camera.device@3.4-impl", + "camera.device@3.5-impl", "camera.device@3.4-external-impl", + "camera.device@3.5-external-impl", "android.hardware.camera.provider@2.4", "android.hardware.camera.common@1.0", "android.hardware.graphics.mapper@2.0", @@ -31,21 +34,21 @@ cc_library_shared { ], header_libs: [ "camera.device@3.4-impl_headers", - "camera.device@3.4-external-impl_headers" + "camera.device@3.5-impl_headers", + "camera.device@3.4-external-impl_headers", + "camera.device@3.5-external-impl_headers" ], static_libs: [ "android.hardware.camera.common@1.0-helper", ], } -cc_binary { - name: "android.hardware.camera.provider@2.4-service", +cc_defaults { + name: "camera_service_defaults", defaults: ["hidl_defaults"], proprietary: true, relative_install_path: "hw", srcs: ["service.cpp"], - compile_multilib: "32", - init_rc: ["android.hardware.camera.provider@2.4-service.rc"], shared_libs: [ "libhidlbase", "libhidltransport", @@ -56,33 +59,42 @@ cc_binary { "android.hardware.camera.device@3.2", "android.hardware.camera.device@3.3", "android.hardware.camera.device@3.4", + "android.hardware.camera.device@3.5", "android.hardware.camera.provider@2.4", "android.hardware.camera.common@1.0", ], } +cc_binary { + name: "android.hardware.camera.provider@2.4-service", + defaults: ["camera_service_defaults"], + compile_multilib: "32", + init_rc: ["android.hardware.camera.provider@2.4-service.rc"], +} cc_binary { name: "android.hardware.camera.provider@2.4-service_64", - defaults: ["hidl_defaults"], - proprietary: true, - relative_install_path: "hw", - srcs: ["service.cpp"], + defaults: ["camera_service_defaults"], compile_multilib: "64", init_rc: ["android.hardware.camera.provider@2.4-service_64.rc"], - shared_libs: [ - "libhidlbase", - "libhidltransport", - "libbinder", - "liblog", - "libutils", - "android.hardware.camera.device@1.0", - "android.hardware.camera.device@3.2", - "android.hardware.camera.device@3.3", - "android.hardware.camera.device@3.4", - "android.hardware.camera.provider@2.4", - "android.hardware.camera.common@1.0", - ], +} + +cc_binary { + name: "android.hardware.camera.provider@2.4-service-lazy", + overrides: ["android.hardware.camera.provider@2.4-service"], + defaults: ["camera_service_defaults"], + compile_multilib: "32", + init_rc: ["android.hardware.camera.provider@2.4-service-lazy.rc"], + cflags: ["-DLAZY_SERVICE"], +} + +cc_binary { + name: "android.hardware.camera.provider@2.4-service-lazy_64", + overrides: ["android.hardware.camera.provider@2.4-service_64"], + defaults: ["camera_service_defaults"], + compile_multilib: "64", + init_rc: ["android.hardware.camera.provider@2.4-service-lazy_64.rc"], + cflags: ["-DLAZY_SERVICE"], } cc_binary { @@ -102,6 +114,8 @@ cc_binary { "android.hardware.camera.device@1.0", "android.hardware.camera.device@3.2", "android.hardware.camera.device@3.3", + "android.hardware.camera.device@3.4", + "android.hardware.camera.device@3.5", "android.hardware.camera.provider@2.4", "android.hardware.camera.common@1.0", ], diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp index 63139390cb..e02cc7e490 100644 --- a/camera/provider/2.4/default/CameraProvider.cpp +++ b/camera/provider/2.4/default/CameraProvider.cpp @@ -23,6 +23,7 @@ #include "CameraDevice_1_0.h" #include "CameraDevice_3_3.h" #include "CameraDevice_3_4.h" +#include "CameraDevice_3_5.h" #include <cutils/properties.h> #include <string.h> #include <utils/Trace.h> @@ -40,10 +41,8 @@ const char *kLegacyProviderName = "legacy/0"; const char *kExternalProviderName = "external/0"; // "device@<version>/legacy/<id>" const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)"); -const char *kHAL3_2 = "3.2"; -const char *kHAL3_3 = "3.3"; const char *kHAL3_4 = "3.4"; -const char *kHAL1_0 = "1.0"; +const char *kHAL3_5 = "3.5"; const int kMaxCameraDeviceNameLen = 128; const int kMaxCameraIdLen = 16; @@ -141,7 +140,6 @@ void CameraProvider::sCameraDeviceStatusChange( int new_status) { CameraProvider* cp = const_cast<CameraProvider*>( static_cast<const CameraProvider*>(callbacks)); - bool found = false; if (cp == nullptr) { ALOGE("%s: callback ops is null", __FUNCTION__); @@ -153,17 +151,23 @@ void CameraProvider::sCameraDeviceStatusChange( snprintf(cameraId, sizeof(cameraId), "%d", camera_id); std::string cameraIdStr(cameraId); cp->mCameraStatusMap[cameraIdStr] = (camera_device_status_t) new_status; - if (cp->mCallbacks != nullptr) { - CameraDeviceStatus status = (CameraDeviceStatus) new_status; - for (auto const& deviceNamePair : cp->mCameraDeviceNames) { - if (cameraIdStr.compare(deviceNamePair.first) == 0) { - cp->mCallbacks->cameraDeviceStatusChange( - deviceNamePair.second, status); - found = true; - } + + if (cp->mCallbacks == nullptr) { + // For camera connected before mCallbacks is set, the corresponding + // addDeviceNames() would be called later in setCallbacks(). + return; + } + + bool found = false; + CameraDeviceStatus status = (CameraDeviceStatus)new_status; + for (auto const& deviceNamePair : cp->mCameraDeviceNames) { + if (cameraIdStr.compare(deviceNamePair.first) == 0) { + cp->mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status); + found = true; } + } - switch (status) { + switch (status) { case CameraDeviceStatus::PRESENT: case CameraDeviceStatus::ENUMERATING: if (!found) { @@ -174,7 +178,6 @@ void CameraProvider::sCameraDeviceStatusChange( if (found) { cp->removeDeviceNames(camera_id); } - } } } @@ -220,22 +223,6 @@ std::string CameraProvider::getLegacyCameraId(const hidl_string& deviceName) { return cameraId; } -int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) { - std::string deviceVersion; - bool match = matchDeviceName(deviceName, &deviceVersion, nullptr); - if (!match) { - return -1; - } - if (deviceVersion == kHAL3_3) { - return CAMERA_DEVICE_API_VERSION_3_3; - } else if (deviceVersion == kHAL3_2) { - return CAMERA_DEVICE_API_VERSION_3_2; - } else if (deviceVersion == kHAL1_0) { - return CAMERA_DEVICE_API_VERSION_1_0; - } - return 0; -} - std::string CameraProvider::getHidlDeviceName( std::string cameraId, int deviceVersion) { // Maybe consider create a version check method and SortedVec to speed up? @@ -243,14 +230,27 @@ std::string CameraProvider::getHidlDeviceName( deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 && - deviceVersion != CAMERA_DEVICE_API_VERSION_3_5) { + deviceVersion != CAMERA_DEVICE_API_VERSION_3_5 && + deviceVersion != CAMERA_DEVICE_API_VERSION_3_6) { return hidl_string(""); } + + // Supported combinations: + // CAMERA_DEVICE_API_VERSION_1_0 -> ICameraDevice@1.0 + // CAMERA_DEVICE_API_VERSION_3_[2-4] -> ICameraDevice@[3.2|3.3] + // CAMERA_DEVICE_API_VERSION_3_5 + CAMERA_MODULE_API_VERSION_2_4 -> ICameraDevice@3.4 + // CAMERA_DEVICE_API_VERSION_3_[5-6] + CAMERA_MODULE_API_VERSION_2_5 -> ICameraDevice@3.5 bool isV1 = deviceVersion == CAMERA_DEVICE_API_VERSION_1_0; int versionMajor = isV1 ? 1 : 3; int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion; if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) { - versionMinor = 4; + if (mModule->getModuleApiVersion() == CAMERA_MODULE_API_VERSION_2_5) { + versionMinor = 5; + } else { + versionMinor = 4; + } + } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) { + versionMinor = 5; } char deviceName[kMaxCameraDeviceNameLen]; snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s", @@ -350,7 +350,8 @@ int CameraProvider::checkCameraVersion(int id, camera_info info) { // device_version undefined in CAMERA_MODULE_API_VERSION_1_0, // All CAMERA_MODULE_API_VERSION_1_0 devices are backward-compatible - if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) { + uint16_t moduleVersion = mModule->getModuleApiVersion(); + if (moduleVersion >= CAMERA_MODULE_API_VERSION_2_0) { // Verify the device version is in the supported range switch (info.device_version) { case CAMERA_DEVICE_API_VERSION_1_0: @@ -360,6 +361,20 @@ int CameraProvider::checkCameraVersion(int id, camera_info info) { case CAMERA_DEVICE_API_VERSION_3_5: // in support break; + case CAMERA_DEVICE_API_VERSION_3_6: + /** + * ICameraDevice@3.5 contains APIs from both + * CAMERA_DEVICE_API_VERSION_3_6 and CAMERA_MODULE_API_VERSION_2_5 + * so we require HALs to uprev both for simplified supported combinations. + * HAL can still opt in individual new APIs indepedently. + */ + if (moduleVersion < CAMERA_MODULE_API_VERSION_2_5) { + ALOGE("%s: Device %d has unsupported version combination:" + "HAL version %x and module version %x", + __FUNCTION__, id, info.device_version, moduleVersion); + return NO_INIT; + } + break; case CAMERA_DEVICE_API_VERSION_2_0: case CAMERA_DEVICE_API_VERSION_2_1: case CAMERA_DEVICE_API_VERSION_3_0: @@ -433,8 +448,22 @@ bool CameraProvider::setUpVendorTags() { // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. Return<Status> CameraProvider::setCallback(const sp<ICameraProviderCallback>& callback) { + if (callback == nullptr) { + return Status::ILLEGAL_ARGUMENT; + } + Mutex::Autolock _l(mCbLock); mCallbacks = callback; + + // Add and report all presenting external cameras. + for (auto const& statusPair : mCameraStatusMap) { + int id = std::stoi(statusPair.first); + auto status = static_cast<CameraDeviceStatus>(statusPair.second); + if (id >= mNumberOfLegacyCameras && status != CameraDeviceStatus::NOT_PRESENT) { + addDeviceNames(id, status, true); + } + } + return Status::OK; } @@ -446,6 +475,11 @@ Return<void> CameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) { Return<void> CameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) { std::vector<hidl_string> deviceNameList; for (auto const& deviceNamePair : mCameraDeviceNames) { + if (std::stoi(deviceNamePair.first) >= mNumberOfLegacyCameras) { + // External camera devices must be reported through the device status change callback, + // not in this list. + continue; + } if (mCameraStatusMap[deviceNamePair.first] == CAMERA_DEVICE_STATUS_PRESENT) { deviceNameList.push_back(deviceNamePair.second); } @@ -546,63 +580,70 @@ Return<void> CameraProvider::getCameraDeviceInterface_V3_x( return Void(); } - sp<android::hardware::camera::device::V3_2::ICameraDevice> device; - if (deviceVersion == kHAL3_4) { - ALOGV("Constructing v3.4 camera device"); - sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl = - new android::hardware::camera::device::V3_4::implementation::CameraDevice( + sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl; + + // ICameraDevice 3.4 or upper + if (deviceVersion >= kHAL3_4) { + ALOGV("Constructing v3.4+ camera device"); + if (deviceVersion == kHAL3_4) { + deviceImpl = new android::hardware::camera::device::V3_4::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); + } else if (deviceVersion == kHAL3_5) { + deviceImpl = new android::hardware::camera::device::V3_5::implementation::CameraDevice( + mModule, cameraId, mCameraDeviceNames); + } if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); - device = nullptr; _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } - - device = deviceImpl; - _hidl_cb (Status::OK, device); + IF_ALOGV() { + deviceImpl->getInterface()->interfaceChain([]( + ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) { + ALOGV("Device interface chain:"); + for (auto iface : interfaceChain) { + ALOGV(" %s", iface.c_str()); + } + }); + } + _hidl_cb (Status::OK, deviceImpl->getInterface()); return Void(); } + // ICameraDevice 3.2 and 3.3 // Since some Treble HAL revisions can map to the same legacy HAL version(s), we default // to the newest possible Treble HAL revision, but allow for override if needed via // system property. switch (mPreferredHal3MinorVersion) { case 2: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.2 ALOGV("Constructing v3.2 camera device"); - sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl = - new android::hardware::camera::device::V3_2::implementation::CameraDevice( + deviceImpl = new android::hardware::camera::device::V3_2::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); - device = nullptr; _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } - device = deviceImpl; break; } case 3: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.3 ALOGV("Constructing v3.3 camera device"); - sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl = - new android::hardware::camera::device::V3_3::implementation::CameraDevice( + deviceImpl = new android::hardware::camera::device::V3_3::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); - device = nullptr; _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } - device = deviceImpl; break; } default: ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion); - device = nullptr; _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } - _hidl_cb (Status::OK, device); + + _hidl_cb (Status::OK, deviceImpl->getInterface()); return Void(); } diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h index 0f0959f1f0..10e9b0d276 100644 --- a/camera/provider/2.4/default/CameraProvider.h +++ b/camera/provider/2.4/default/CameraProvider.h @@ -98,7 +98,6 @@ private: // extract legacy camera ID/device version from a HIDL device name static std::string getLegacyCameraId(const hidl_string& deviceName); - static int getCameraDeviceVersion(const hidl_string& deviceName); // convert conventional HAL status to HIDL Status static Status getHidlStatus(int); diff --git a/camera/provider/2.4/default/ExternalCameraProvider.cpp b/camera/provider/2.4/default/ExternalCameraProvider.cpp index 1cec0e5d97..604df5c0cf 100644 --- a/camera/provider/2.4/default/ExternalCameraProvider.cpp +++ b/camera/provider/2.4/default/ExternalCameraProvider.cpp @@ -24,6 +24,8 @@ #include <linux/videodev2.h> #include "ExternalCameraProvider.h" #include "ExternalCameraDevice_3_4.h" +#include "ExternalCameraDevice_3_5.h" +#include <cutils/properties.h> namespace android { namespace hardware { @@ -62,6 +64,21 @@ ExternalCameraProvider::ExternalCameraProvider() : mCfg(ExternalCameraConfig::loadFromCfg()), mHotPlugThread(this) { mHotPlugThread.run("ExtCamHotPlug", PRIORITY_BACKGROUND); + + mPreferredHal3MinorVersion = + property_get_int32("ro.vendor.camera.external.hal3TrebleMinorVersion", 4); + ALOGV("Preferred HAL 3 minor version is %d", mPreferredHal3MinorVersion); + switch(mPreferredHal3MinorVersion) { + case 4: + case 5: + // OK + break; + default: + ALOGW("Unknown minor camera device HAL version %d in property " + "'camera.external.hal3TrebleMinorVersion', defaulting to 4", + mPreferredHal3MinorVersion); + mPreferredHal3MinorVersion = 4; + } } ExternalCameraProvider::~ExternalCameraProvider() { @@ -136,20 +153,43 @@ Return<void> ExternalCameraProvider::getCameraDeviceInterface_V3_x( return Void(); } - ALOGV("Constructing v3.4 external camera device"); - sp<device::V3_2::ICameraDevice> device; - sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl = - new device::V3_4::implementation::ExternalCameraDevice( + sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl; + switch (mPreferredHal3MinorVersion) { + case 4: { + ALOGV("Constructing v3.4 external camera device"); + deviceImpl = new device::V3_4::implementation::ExternalCameraDevice( + cameraId, mCfg); + break; + } + case 5: { + ALOGV("Constructing v3.5 external camera device"); + deviceImpl = new device::V3_5::implementation::ExternalCameraDevice( cameraId, mCfg); + break; + } + default: + ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion); + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); - device = nullptr; _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } - device = deviceImpl; - _hidl_cb (Status::OK, device); + IF_ALOGV() { + deviceImpl->getInterface()->interfaceChain([]( + ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) { + ALOGV("Device interface chain:"); + for (auto iface : interfaceChain) { + ALOGV(" %s", iface.c_str()); + } + }); + } + + _hidl_cb (Status::OK, deviceImpl->getInterface()); return Void(); } @@ -157,7 +197,12 @@ Return<void> ExternalCameraProvider::getCameraDeviceInterface_V3_x( void ExternalCameraProvider::addExternalCamera(const char* devName) { ALOGI("ExtCam: adding %s to External Camera HAL!", devName); Mutex::Autolock _l(mLock); - std::string deviceName = std::string("device@3.4/external/") + devName; + std::string deviceName; + if (mPreferredHal3MinorVersion == 5) { + deviceName = std::string("device@3.5/external/") + devName; + } else { + deviceName = std::string("device@3.4/external/") + devName; + } mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT; if (mCallbacks != nullptr) { mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT); @@ -199,7 +244,12 @@ void ExternalCameraProvider::deviceAdded(const char* devName) { void ExternalCameraProvider::deviceRemoved(const char* devName) { Mutex::Autolock _l(mLock); - std::string deviceName = std::string("device@3.4/external/") + devName; + std::string deviceName; + if (mPreferredHal3MinorVersion == 5) { + deviceName = std::string("device@3.5/external/") + devName; + } else { + deviceName = std::string("device@3.4/external/") + devName; + } if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) { mCameraStatusMap.erase(deviceName); if (mCallbacks != nullptr) { diff --git a/camera/provider/2.4/default/ExternalCameraProvider.h b/camera/provider/2.4/default/ExternalCameraProvider.h index c83cc708bf..a69cf8bcf1 100644 --- a/camera/provider/2.4/default/ExternalCameraProvider.h +++ b/camera/provider/2.4/default/ExternalCameraProvider.h @@ -95,6 +95,7 @@ private: std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status const ExternalCameraConfig mCfg; HotplugThread mHotPlugThread; + int mPreferredHal3MinorVersion; }; diff --git a/camera/provider/2.4/default/OWNERS b/camera/provider/2.4/default/OWNERS index 18acfee145..369b2048cb 100644 --- a/camera/provider/2.4/default/OWNERS +++ b/camera/provider/2.4/default/OWNERS @@ -1,6 +1,7 @@ cychen@google.com epeev@google.com etalvala@google.com +jchowdhary@google.com shuzhenwang@google.com yinchiayeh@google.com zhijunhe@google.com diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc index acdb2007a5..64cf321d83 100644 --- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc @@ -1,4 +1,5 @@ service vendor.camera-provider-2-4-ext /vendor/bin/hw/android.hardware.camera.provider@2.4-external-service + interface android.hardware.camera.provider@2.4::ICameraProvider external/0 class hal user cameraserver group audio camera input drmrpc usb diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy.rc new file mode 100644 index 0000000000..e8549ed82d --- /dev/null +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy.rc @@ -0,0 +1,10 @@ +service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service-lazy + interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0 + oneshot + disabled + class hal + user cameraserver + group audio camera input drmrpc + ioprio rt 4 + capabilities SYS_NICE + writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy_64.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy_64.rc new file mode 100644 index 0000000000..2dfac764eb --- /dev/null +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service-lazy_64.rc @@ -0,0 +1,10 @@ +service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service-lazy_64 + interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0 + oneshot + disabled + class hal + user cameraserver + group audio camera input drmrpc + ioprio rt 4 + capabilities SYS_NICE + writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc index c9196284ee..913561b1fe 100644 --- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc @@ -1,4 +1,5 @@ service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service + interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0 class hal user cameraserver group audio camera input drmrpc diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc index 4c721ecb88..fd4826ec2c 100644 --- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc @@ -1,4 +1,5 @@ service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service_64 + interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0 class hal user cameraserver group audio camera input drmrpc diff --git a/camera/provider/2.4/default/service.cpp b/camera/provider/2.4/default/service.cpp index 7eeb6379c9..15d0ea6371 100644 --- a/camera/provider/2.4/default/service.cpp +++ b/camera/provider/2.4/default/service.cpp @@ -14,15 +14,27 @@ * limitations under the License. */ +#ifdef LAZY_SERVICE +#define LOG_TAG "android.hardware.camera.provider@2.4-service-lazy" +#else #define LOG_TAG "android.hardware.camera.provider@2.4-service" +#endif #include <android/hardware/camera/provider/2.4/ICameraProvider.h> #include <hidl/LegacySupport.h> #include <binder/ProcessState.h> -using android::hardware::camera::provider::V2_4::ICameraProvider; +using android::status_t; +using android::hardware::defaultLazyPassthroughServiceImplementation; using android::hardware::defaultPassthroughServiceImplementation; +using android::hardware::camera::provider::V2_4::ICameraProvider; + +#ifdef LAZY_SERVICE +const bool kLazyService = true; +#else +const bool kLazyService = false; +#endif int main() { @@ -30,5 +42,13 @@ int main() // The camera HAL may communicate to other vendor components via // /dev/vndbinder android::ProcessState::initWithDriver("/dev/vndbinder"); - return defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0", /*maxThreads*/ 6); + status_t status; + if (kLazyService) { + status = defaultLazyPassthroughServiceImplementation<ICameraProvider>("legacy/0", + /*maxThreads*/ 6); + } else { + status = defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0", + /*maxThreads*/ 6); + } + return status; } diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index c71ce2f967..f8f058e26b 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -37,6 +37,8 @@ cc_test { "android.hardware.camera.device@3.2", "android.hardware.camera.device@3.3", "android.hardware.camera.device@3.4", + "android.hardware.camera.device@3.5", + "android.hardware.camera.metadata@3.4", "android.hardware.camera.provider@2.4", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.common@1.0", diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 22b738256d..211240a06b 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -28,10 +28,14 @@ #include <android/hardware/camera/device/1.0/ICameraDevice.h> #include <android/hardware/camera/device/3.2/ICameraDevice.h> +#include <android/hardware/camera/device/3.5/ICameraDevice.h> #include <android/hardware/camera/device/3.3/ICameraDeviceSession.h> #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h> +#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h> #include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h> +#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h> #include <android/hardware/camera/provider/2.4/ICameraProvider.h> +#include <android/hardware/camera/metadata/3.4/types.h> #include <android/hidl/manager/1.0/IServiceManager.h> #include <binder/MemoryHeapBase.h> #include <CameraMetadata.h> @@ -109,6 +113,9 @@ using ::android::hardware::camera::device::V1_0::CameraFrameMetadata; using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback; using ::android::hardware::camera::device::V1_0::FrameCallbackFlag; using ::android::hardware::camera::device::V1_0::HandleTimestampMessage; +using ::android::hardware::camera::metadata::V3_4::CameraMetadataEnumAndroidSensorInfoColorFilterArrangement; +using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag; +using ::android::hardware::camera::device::V3_4::PhysicalCameraMetadata; using ::android::hardware::MessageQueue; using ::android::hardware::kSynchronizedReadWrite; using ::android::hidl::allocator::V1_0::IAllocator; @@ -129,6 +136,7 @@ const int64_t kTorchTimeoutSec = 1; const int64_t kEmptyFlushTimeoutMSec = 200; const char kDumpOutput[] = "/dev/null"; const uint32_t kBurstFrameCount = 10; +const int64_t kBufferReturnTimeoutSec = 1; struct AvailableStream { int32_t width; @@ -141,13 +149,20 @@ struct AvailableZSLInputOutput { int32_t outputFormat; }; +enum ReprocessType { + PRIV_REPROCESS, + YUV_REPROCESS, +}; + namespace { // "device@<version>/legacy/<id>" const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)"; + const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305; const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304; const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303; const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302; const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100; + const char *kHAL3_5 = "3.5"; const char *kHAL3_4 = "3.4"; const char *kHAL3_3 = "3.3"; const char *kHAL3_2 = "3.2"; @@ -182,7 +197,9 @@ namespace { return -1; } - if (version.compare(kHAL3_4) == 0) { + if (version.compare(kHAL3_5) == 0) { + return CAMERA_DEVICE_API_VERSION_3_5; + } else if (version.compare(kHAL3_4) == 0) { return CAMERA_DEVICE_API_VERSION_3_4; } else if (version.compare(kHAL3_3) == 0) { return CAMERA_DEVICE_API_VERSION_3_3; @@ -531,7 +548,7 @@ public: hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider); - struct EmptyDeviceCb : public V3_4::ICameraDeviceCallback { + struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback { virtual Return<void> processCaptureResult( const hidl_vec<CaptureResult>& /*results*/) override { ALOGI("processCaptureResult callback"); @@ -551,19 +568,65 @@ public: ADD_FAILURE(); // Empty callback should not reach here return Void(); } + + virtual Return<void> requestStreamBuffers( + const hidl_vec<V3_5::BufferRequest>&, + requestStreamBuffers_cb _hidl_cb) override { + ALOGI("requestStreamBuffers callback"); + // HAL might want to request buffer after configureStreams, but tests with EmptyDeviceCb + // doesn't actually need to send capture requests, so just return an error. + hidl_vec<V3_5::StreamBufferRet> emptyBufRets; + _hidl_cb(V3_5::BufferRequestStatus::FAILED_UNKNOWN, emptyBufRets); + return Void(); + } + + virtual Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>&) override { + ALOGI("returnStreamBuffers"); + ADD_FAILURE(); // Empty callback should not reach here + return Void(); + } + }; - struct DeviceCb : public V3_4::ICameraDeviceCallback { - DeviceCb(CameraHidlTest *parent) : mParent(parent) {} + struct DeviceCb : public V3_5::ICameraDeviceCallback { + DeviceCb(CameraHidlTest *parent, int deviceVersion, const camera_metadata_t *staticMeta) : + mParent(parent), mDeviceVersion(deviceVersion), mStaticMetadata(staticMeta) {} + Return<void> processCaptureResult_3_4( const hidl_vec<V3_4::CaptureResult>& results) override; Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override; Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override; - private: - bool processCaptureResultLocked(const CaptureResult& results); + Return<void> requestStreamBuffers( + const hidl_vec<V3_5::BufferRequest>& bufReqs, + requestStreamBuffers_cb _hidl_cb) override; - CameraHidlTest *mParent; // Parent object + Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>& buffers) override; + + void setCurrentStreamConfig(const hidl_vec<V3_2::Stream>& streams, + const hidl_vec<V3_2::HalStream>& halStreams); + + void waitForBuffersReturned(); + + private: + bool processCaptureResultLocked(const CaptureResult& results, + hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata); + + CameraHidlTest *mParent; // Parent object + int mDeviceVersion; + const camera_metadata_t *mStaticMetadata; + bool hasOutstandingBuffersLocked(); + + /* members for requestStreamBuffers() and returnStreamBuffers()*/ + std::mutex mLock; // protecting members below + bool mUseHalBufManager = false; + hidl_vec<V3_2::Stream> mStreams; + hidl_vec<V3_2::HalStream> mHalStreams; + uint64_t mNextBufferId = 1; + using OutstandingBuffers = std::unordered_map<uint64_t, hidl_handle>; + // size == mStreams.size(). Tracking each streams outstanding buffers + std::vector<OutstandingBuffers> mOutstandingBufferIds; + std::condition_variable mFlushedCondition; }; struct TorchProviderCb : public ICameraProviderCallback { @@ -644,14 +707,19 @@ public: void openEmptyDeviceSession(const std::string &name, sp<ICameraProvider> provider, sp<ICameraDeviceSession> *session /*out*/, - camera_metadata_t **staticMeta /*out*/); + camera_metadata_t **staticMeta /*out*/, + ::android::sp<ICameraDevice> *device = nullptr/*out*/); void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion, sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/, - sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/); + sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/, + sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/); + void castDevice(const sp<device::V3_2::ICameraDevice> &device, int32_t deviceVersion, + sp<device::V3_5::ICameraDevice> *device3_5/*out*/); void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2, StreamConfigurationMode configMode, ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2, ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4, + ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5, uint32_t jpegBufferSize = 0); void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion, @@ -659,10 +727,14 @@ public: const AvailableStream *previewThreshold, const std::unordered_set<std::string>& physicalIds, sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/, + sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/, V3_2::Stream* previewStream /*out*/, device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, - uint32_t *partialResultCount /*out*/); + uint32_t *partialResultCount /*out*/, + bool *useHalBufManager /*out*/, + sp<DeviceCb> *cb /*out*/, + uint32_t streamConfigCounter = 0); void configurePreviewStream(const std::string &name, int32_t deviceVersion, sp<ICameraProvider> provider, const AvailableStream *previewThreshold, @@ -670,15 +742,42 @@ public: V3_2::Stream *previewStream /*out*/, HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, - uint32_t *partialResultCount /*out*/); + uint32_t *partialResultCount /*out*/, + bool *useHalBufManager /*out*/, + sp<DeviceCb> *cb /*out*/, + uint32_t streamConfigCounter = 0); + + void verifyLogicalCameraMetadata(const std::string& cameraName, + const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device, + const CameraMetadata& chars, int deviceVersion, + const hidl_vec<hidl_string>& deviceNames); + void verifyCameraCharacteristics(Status status, const CameraMetadata& chars); + void verifyRecommendedConfigs(const CameraMetadata& metadata); + void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion); + void verifyMonochromeCameraResult( + const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata); + void verifyStreamCombination(sp<device::V3_5::ICameraDevice> cameraDevice3_5, + const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4, + bool expectedStatus); + void verifyLogicalCameraResult(const camera_metadata_t* staticMetadata, + const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& resultMetadata); + + void verifyBuffersReturned(sp<device::V3_2::ICameraDeviceSession> session, + int deviceVerison, int32_t streamId, sp<DeviceCb> cb, + uint32_t streamConfigCounter = 0); + + void verifyBuffersReturned(sp<device::V3_4::ICameraDeviceSession> session, + hidl_vec<int32_t> streamIds, sp<DeviceCb> cb, + uint32_t streamConfigCounter = 0); + static Status getAvailableOutputStreams(camera_metadata_t *staticMeta, std::vector<AvailableStream> &outputStreams, const AvailableStream *threshold = nullptr); static Status getJpegBufferSize(camera_metadata_t *staticMeta, uint32_t* outBufSize); static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta); - static Status isLogicalMultiCamera(camera_metadata_t *staticMeta); - static Status getPhysicalCameraIds(camera_metadata_t *staticMeta, + static Status isLogicalMultiCamera(const camera_metadata_t *staticMeta); + static Status getPhysicalCameraIds(const camera_metadata_t *staticMeta, std::unordered_set<std::string> *physicalIds/*out*/); static Status getSupportedKeys(camera_metadata_t *staticMeta, uint32_t tagId, std::unordered_set<int32_t> *requestIDs/*out*/); @@ -689,7 +788,8 @@ public: /*out*/); static Status pickConstrainedModeSize(camera_metadata_t *staticMeta, AvailableStream &hfrStream); - static Status isZSLModeAvailable(camera_metadata_t *staticMeta); + static Status isZSLModeAvailable(const camera_metadata_t *staticMeta); + static Status isZSLModeAvailable(const camera_metadata_t *staticMeta, ReprocessType reprocType); static Status getZSLInputOutputMap(camera_metadata_t *staticMeta, std::vector<AvailableZSLInputOutput> &inputOutputMap); static Status findLargestSize( @@ -697,6 +797,7 @@ public: int32_t format, AvailableStream &result); static Status isAutoFocusModeAvailable( CameraParameters &cameraParams, const char *mode) ; + static Status isMonochromeCamera(const camera_metadata_t *staticMeta); protected: @@ -913,7 +1014,7 @@ Return<void> CameraHidlTest::DeviceCb::processCaptureResult_3_4( bool notify = false; std::unique_lock<std::mutex> l(mParent->mLock); for (size_t i = 0 ; i < results.size(); i++) { - notify = processCaptureResultLocked(results[i].v3_2); + notify = processCaptureResultLocked(results[i].v3_2, results[i].physicalCameraMetadata); } l.unlock(); @@ -932,8 +1033,9 @@ Return<void> CameraHidlTest::DeviceCb::processCaptureResult( bool notify = false; std::unique_lock<std::mutex> l(mParent->mLock); + ::android::hardware::hidl_vec<PhysicalCameraMetadata> noPhysMetadata; for (size_t i = 0 ; i < results.size(); i++) { - notify = processCaptureResultLocked(results[i]); + notify = processCaptureResultLocked(results[i], noPhysMetadata); } l.unlock(); @@ -944,7 +1046,8 @@ Return<void> CameraHidlTest::DeviceCb::processCaptureResult( return Void(); } -bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results) { +bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results, + hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata) { bool notify = false; uint32_t frameNumber = results.frameNumber; @@ -985,6 +1088,20 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r ADD_FAILURE(); return notify; } + + std::vector<::android::hardware::camera::device::V3_2::CameraMetadata> physResultMetadata; + physResultMetadata.resize(physicalCameraMetadata.size()); + for (size_t i = 0; i < physicalCameraMetadata.size(); i++) { + physResultMetadata[i].resize(physicalCameraMetadata[i].fmqMetadataSize); + if (!request->resultQueue->read(physResultMetadata[i].data(), + physicalCameraMetadata[i].fmqMetadataSize)) { + ALOGE("%s: Frame %d: Cannot read physical camera metadata from fmq," + "size = %" PRIu64, __func__, frameNumber, + physicalCameraMetadata[i].fmqMetadataSize); + ADD_FAILURE(); + return notify; + } + } resultSize = resultMetadata.size(); } else if (results.result.size() > 0) { resultMetadata.setToExternal(const_cast<uint8_t *>( @@ -1040,6 +1157,23 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r } request->haveResultMetadata = true; request->collectedResult.sort(); + + // Verify final result metadata + bool isAtLeast_3_5 = mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_5; + if (isAtLeast_3_5) { + bool isMonochrome = Status::OK == + CameraHidlTest::isMonochromeCamera(mStaticMetadata); + if (isMonochrome) { + mParent->verifyMonochromeCameraResult(request->collectedResult); + } + + // Verify logical camera result metadata + bool isLogicalCamera = + Status::OK == CameraHidlTest::isLogicalMultiCamera(mStaticMetadata); + if (isLogicalCamera) { + mParent->verifyLogicalCameraResult(mStaticMetadata, request->collectedResult); + } + } } uint32_t numBuffersReturned = results.outputBuffers.size(); @@ -1065,9 +1199,51 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r if (request->shutterTimestamp != 0) { notify = true; } + + if (mUseHalBufManager) { + returnStreamBuffers(results.outputBuffers); + } return notify; } +void CameraHidlTest::DeviceCb::setCurrentStreamConfig( + const hidl_vec<V3_2::Stream>& streams, const hidl_vec<V3_2::HalStream>& halStreams) { + ASSERT_EQ(streams.size(), halStreams.size()); + ASSERT_NE(streams.size(), 0); + for (size_t i = 0; i < streams.size(); i++) { + ASSERT_EQ(streams[i].id, halStreams[i].id); + } + std::lock_guard<std::mutex> l(mLock); + mUseHalBufManager = true; + mStreams = streams; + mHalStreams = halStreams; + mOutstandingBufferIds.clear(); + for (size_t i = 0; i < streams.size(); i++) { + mOutstandingBufferIds.emplace_back(); + } +} + +bool CameraHidlTest::DeviceCb::hasOutstandingBuffersLocked() { + if (!mUseHalBufManager) { + return false; + } + for (const auto& outstandingBuffers : mOutstandingBufferIds) { + if (!outstandingBuffers.empty()) { + return true; + } + } + return false; +} + +void CameraHidlTest::DeviceCb::waitForBuffersReturned() { + std::unique_lock<std::mutex> lk(mLock); + if (hasOutstandingBuffersLocked()) { + auto timeout = std::chrono::seconds(kBufferReturnTimeoutSec); + auto st = mFlushedCondition.wait_for(lk, timeout); + ASSERT_NE(std::cv_status::timeout, st); + } +} + Return<void> CameraHidlTest::DeviceCb::notify( const hidl_vec<NotifyMsg>& messages) { std::lock_guard<std::mutex> l(mParent->mLock); @@ -1110,6 +1286,124 @@ Return<void> CameraHidlTest::DeviceCb::notify( return Void(); } +Return<void> CameraHidlTest::DeviceCb::requestStreamBuffers( + const hidl_vec<V3_5::BufferRequest>& bufReqs, + requestStreamBuffers_cb _hidl_cb) { + using V3_5::BufferRequestStatus; + using V3_5::StreamBufferRet; + using V3_5::StreamBufferRequestError; + hidl_vec<StreamBufferRet> bufRets; + std::unique_lock<std::mutex> l(mLock); + + if (!mUseHalBufManager) { + ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__); + ADD_FAILURE(); + _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); + return Void(); + } + + if (bufReqs.size() > mStreams.size()) { + ALOGE("%s: illegal buffer request: too many requests!", __FUNCTION__); + ADD_FAILURE(); + _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); + return Void(); + } + + std::vector<int32_t> indexes(bufReqs.size()); + for (size_t i = 0; i < bufReqs.size(); i++) { + bool found = false; + for (size_t idx = 0; idx < mStreams.size(); idx++) { + if (bufReqs[i].streamId == mStreams[idx].id) { + found = true; + indexes[i] = idx; + break; + } + } + if (!found) { + ALOGE("%s: illegal buffer request: unknown streamId %d!", + __FUNCTION__, bufReqs[i].streamId); + ADD_FAILURE(); + _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); + return Void(); + } + } + + bool allStreamOk = true; + bool atLeastOneStreamOk = false; + bufRets.resize(bufReqs.size()); + for (size_t i = 0; i < bufReqs.size(); i++) { + int32_t idx = indexes[i]; + const auto& stream = mStreams[idx]; + const auto& halStream = mHalStreams[idx]; + const V3_5::BufferRequest& bufReq = bufReqs[i]; + if (mOutstandingBufferIds[idx].size() + bufReq.numBuffersRequested > halStream.maxBuffers) { + bufRets[i].streamId = stream.id; + bufRets[i].val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED); + allStreamOk = false; + continue; + } + + hidl_vec<StreamBuffer> tmpRetBuffers(bufReq.numBuffersRequested); + for (size_t i = 0; i < bufReq.numBuffersRequested; i++) { + hidl_handle buffer_handle; + mParent->allocateGraphicBuffer(stream.width, stream.height, + android_convertGralloc1To0Usage( + halStream.producerUsage, halStream.consumerUsage), + halStream.overrideFormat, &buffer_handle); + + tmpRetBuffers[i] = {stream.id, mNextBufferId, buffer_handle, BufferStatus::OK, + nullptr, nullptr}; + mOutstandingBufferIds[idx].insert(std::make_pair(mNextBufferId++, buffer_handle)); + } + atLeastOneStreamOk = true; + bufRets[0].val.buffers(std::move(tmpRetBuffers)); + } + + if (allStreamOk) { + _hidl_cb(BufferRequestStatus::OK, bufRets); + } else if (atLeastOneStreamOk) { + _hidl_cb(BufferRequestStatus::FAILED_PARTIAL, bufRets); + } else { + _hidl_cb(BufferRequestStatus::FAILED_UNKNOWN, bufRets); + } + + if (!hasOutstandingBuffersLocked()) { + l.unlock(); + mFlushedCondition.notify_one(); + } + return Void(); +} + +Return<void> CameraHidlTest::DeviceCb::returnStreamBuffers( + const hidl_vec<StreamBuffer>& buffers) { + if (!mUseHalBufManager) { + ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__); + ADD_FAILURE(); + } + + std::lock_guard<std::mutex> l(mLock); + for (const auto& buf : buffers) { + bool found = false; + for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) { + if (mStreams[idx].id == buf.streamId && + mOutstandingBufferIds[idx].count(buf.bufferId) == 1) { + mOutstandingBufferIds[idx].erase(buf.bufferId); + // TODO: check do we need to close/delete native handle or assume we have enough + // memory to run till the test finish? since we do not capture much requests (and + // most of time one buffer is sufficient) + found = true; + break; + } + } + if (found) { + continue; + } + ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId); + ADD_FAILURE(); + } + return Void(); +} + hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames(sp<ICameraProvider> provider) { std::vector<std::string> cameraDeviceNames; Return<void> ret; @@ -1269,6 +1563,7 @@ TEST_F(CameraHidlTest, getCameraDeviceInterface) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { @@ -1310,6 +1605,7 @@ TEST_F(CameraHidlTest, getResourceCost) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { @@ -2050,6 +2346,7 @@ TEST_F(CameraHidlTest, getCameraCharacteristics) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { @@ -2066,33 +2363,32 @@ TEST_F(CameraHidlTest, getCameraCharacteristics) { ASSERT_TRUE(ret.isOk()); ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) { - ALOGI("getCameraCharacteristics returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); - size_t expectedSize = chars.size(); - int result = validate_camera_metadata_structure(metadata, &expectedSize); - ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED)); - size_t entryCount = get_camera_metadata_entry_count(metadata); - // TODO: we can do better than 0 here. Need to check how many required - // characteristics keys we've defined. - ASSERT_GT(entryCount, 0u); - ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount); - - camera_metadata_ro_entry entry; - int retcode = find_camera_metadata_ro_entry(metadata, - ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry); - if ((0 == retcode) && (entry.count > 0)) { - uint8_t hardwareLevel = entry.data.u8[0]; - ASSERT_TRUE( - hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED || - hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL || - hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3 || - hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); - } else { - ADD_FAILURE() << "Get camera hardware level failed!"; - } + verifyCameraCharacteristics(status, chars); + verifyMonochromeCharacteristics(chars, deviceVersion); + verifyRecommendedConfigs(chars); + verifyLogicalCameraMetadata(name, device3_x, chars, deviceVersion, + cameraDeviceNames); }); ASSERT_TRUE(ret.isOk()); + + //getPhysicalCameraCharacteristics will fail for publicly + //advertised camera IDs. + if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) { + auto castResult = device::V3_5::ICameraDevice::castFrom(device3_x); + ASSERT_TRUE(castResult.isOk()); + ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice> + device3_5 = castResult; + ASSERT_NE(device3_5, nullptr); + + std::string version, cameraId; + ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &cameraId)); + Return<void> ret = device3_5->getPhysicalCameraCharacteristics(cameraId, + [&](auto status, const auto& chars) { + ASSERT_TRUE(Status::ILLEGAL_ARGUMENT == status); + ASSERT_EQ(0, chars.size()); + }); + ASSERT_TRUE(ret.isOk()); + } } break; case CAMERA_DEVICE_API_VERSION_1_0: { @@ -2129,6 +2425,7 @@ TEST_F(CameraHidlTest, setTorchMode) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { @@ -2254,6 +2551,7 @@ TEST_F(CameraHidlTest, dumpState) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { @@ -2318,6 +2616,7 @@ TEST_F(CameraHidlTest, openClose) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { @@ -2345,13 +2644,18 @@ TEST_F(CameraHidlTest, openClose) { // cast the 3.3/3.4 interface, and that lower versions can't be cast to it. sp<device::V3_3::ICameraDeviceSession> sessionV3_3; sp<device::V3_4::ICameraDeviceSession> sessionV3_4; - castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4); - if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) { + sp<device::V3_5::ICameraDeviceSession> sessionV3_5; + castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4, &sessionV3_5); + if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) { + ASSERT_TRUE(sessionV3_5.get() != nullptr); + } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) { ASSERT_TRUE(sessionV3_4.get() != nullptr); } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) { ASSERT_TRUE(sessionV3_3.get() != nullptr); - } else { + } else { //V3_2 ASSERT_TRUE(sessionV3_3.get() == nullptr); + ASSERT_TRUE(sessionV3_4.get() == nullptr); + ASSERT_TRUE(sessionV3_5.get() == nullptr); } native_handle_t* raw_handle = native_handle_create(1, 0); raw_handle->data[0] = open(kDumpOutput, O_RDWR); @@ -2404,6 +2708,7 @@ TEST_F(CameraHidlTest, constructDefaultRequestSettings) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_5: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_2: { @@ -2506,9 +2811,13 @@ TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { sp<ICameraDeviceSession> session; sp<device::V3_3::ICameraDeviceSession> session3_3; sp<device::V3_4::ICameraDeviceSession> session3_4; + sp<device::V3_5::ICameraDeviceSession> session3_5; + sp<device::V3_2::ICameraDevice> cameraDevice; + sp<device::V3_5::ICameraDevice> cameraDevice3_5; openEmptyDeviceSession(name, mProvider, - &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); outputStreams.clear(); ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams)); @@ -2519,6 +2828,7 @@ TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { ASSERT_NE(0u, jpegBufferSize); int32_t streamId = 0; + uint32_t streamConfigCounter = 0; for (auto& it : outputStreams) { V3_2::Stream stream3_2; bool isJpeg = static_cast<PixelFormat>(it.format) == PixelFormat::BLOB; @@ -2531,11 +2841,22 @@ TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { (isJpeg) ? static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF) : 0, StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2}; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2; createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + verifyStreamCombination(cameraDevice3_5, config3_4, + /*expectedStatus*/ true); + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + ASSERT_EQ(halConfig.streams[0].v3_3.v3_2.id, streamId); + }); + } else if (session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) { ASSERT_EQ(Status::OK, s); @@ -2587,8 +2908,13 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { sp<ICameraDeviceSession> session; sp<device::V3_3::ICameraDeviceSession> session3_3; sp<device::V3_4::ICameraDeviceSession> session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp<device::V3_5::ICameraDeviceSession> session3_5; + sp<device::V3_2::ICameraDevice> cameraDevice; + sp<device::V3_5::ICameraDevice> cameraDevice3_5; + openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, + &cameraDevice /*out*/); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); outputStreams.clear(); ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams)); @@ -2607,29 +2933,39 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0}; + uint32_t streamConfigCounter = 0; ::android::hardware::hidl_vec<V3_2::Stream> streams = {stream3_2}; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2; createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if(session3_4 != nullptr) { - ret = session3_4->configureStreams_3_4(config3_4, - [](Status s, device::V3_4::HalStreamConfiguration) { - ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + verifyStreamCombination(cameraDevice3_5, config3_4, /*expectedStatus*/ false); + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || (Status::INTERNAL_ERROR == s)); - }); + }); + } else if (session3_4 != nullptr) { + ret = session3_4->configureStreams_3_4(config3_4, + [](Status s, device::V3_4::HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); } else if(session3_3 != nullptr) { ret = session3_3->configureStreams_3_3(config3_2, - [](Status s, device::V3_3::HalStreamConfiguration) { - ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || - (Status::INTERNAL_ERROR == s)); - }); + [](Status s, device::V3_3::HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); } else { ret = session->configureStreams(config3_2, - [](Status s, HalStreamConfiguration) { - ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || - (Status::INTERNAL_ERROR == s)); - }); + [](Status s, HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); } ASSERT_TRUE(ret.isOk()); @@ -2643,8 +2979,14 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { StreamRotation::ROTATION_0}; streams[0] = stream3_2; createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if(session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, [](Status s, + device::V3_4::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else if(session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration) { ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); @@ -2673,8 +3015,14 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { StreamRotation::ROTATION_0}; streams[0] = stream3_2; createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if(session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else if(session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration) { ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); @@ -2702,8 +3050,14 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { static_cast<StreamRotation>(UINT32_MAX)}; streams[0] = stream3_2; createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if(session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else if(session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration) { ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); @@ -2750,8 +3104,13 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { sp<ICameraDeviceSession> session; sp<device::V3_3::ICameraDeviceSession> session3_3; sp<device::V3_4::ICameraDeviceSession> session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp<device::V3_5::ICameraDeviceSession> session3_5; + sp<device::V3_2::ICameraDevice> cameraDevice; + sp<device::V3_5::ICameraDevice> cameraDevice3_5; + openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, + &cameraDevice /*out*/); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); Status rc = isZSLModeAvailable(staticMeta); if (Status::METHOD_NOT_SUPPORTED == rc) { @@ -2769,17 +3128,39 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap)); ASSERT_NE(0u, inputOutputMap.size()); + bool supportMonoY8 = false; + if (Status::OK == isMonochromeCamera(staticMeta)) { + for (auto& it : inputStreams) { + if (it.format == static_cast<uint32_t>(PixelFormat::Y8)) { + supportMonoY8 = true; + break; + } + } + } + uint32_t jpegBufferSize = 0; ASSERT_EQ(Status::OK, getJpegBufferSize(staticMeta, &jpegBufferSize)); ASSERT_NE(0u, jpegBufferSize); int32_t streamId = 0; + bool hasPrivToY8 = false, hasY8ToY8 = false, hasY8ToBlob = false; + uint32_t streamConfigCounter = 0; for (auto& inputIter : inputOutputMap) { AvailableStream input; ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat, input)); ASSERT_NE(0u, inputStreams.size()); + if (inputIter.inputFormat == static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED) + && inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::Y8)) { + hasPrivToY8 = true; + } else if (inputIter.inputFormat == static_cast<uint32_t>(PixelFormat::Y8)) { + if (inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::BLOB)) { + hasY8ToBlob = true; + } else if (inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::Y8)) { + hasY8ToY8 = true; + } + } AvailableStream outputThreshold = {INT32_MAX, INT32_MAX, inputIter.outputFormat}; std::vector<AvailableStream> outputStreams; @@ -2814,11 +3195,21 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { ::android::hardware::hidl_vec<V3_2::Stream> streams = {inputStream, zslStream, outputStream}; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2; createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + verifyStreamCombination(cameraDevice3_5, config3_4, + /*expectedStatus*/ true); + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(3u, halConfig.streams.size()); + }); + } else if (session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration halConfig) { ASSERT_EQ(Status::OK, s); @@ -2841,6 +3232,16 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { } } + if (supportMonoY8) { + if (Status::OK == isZSLModeAvailable(staticMeta, PRIV_REPROCESS)) { + ASSERT_TRUE(hasPrivToY8); + } + if (Status::OK == isZSLModeAvailable(staticMeta, YUV_REPROCESS)) { + ASSERT_TRUE(hasY8ToY8); + ASSERT_TRUE(hasY8ToBlob); + } + } + free_camera_metadata(staticMeta); ret = session->close(); ASSERT_TRUE(ret.isOk()); @@ -2870,9 +3271,14 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) { sp<ICameraDeviceSession> session; sp<device::V3_3::ICameraDeviceSession> session3_3; sp<device::V3_4::ICameraDeviceSession> session3_4; + sp<device::V3_5::ICameraDeviceSession> session3_5; openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); - ASSERT_NE(session3_4, nullptr); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) { + ASSERT_NE(session3_4, nullptr); + } else { + ASSERT_NE(session3_5, nullptr); + } std::unordered_set<int32_t> availableSessionKeys; auto rc = getSupportedKeys(staticMetaBuffer, ANDROID_REQUEST_AVAILABLE_SESSION_KEYS, @@ -2914,17 +3320,29 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) { previewStream.bufferSize = 0; ::android::hardware::hidl_vec<V3_4::Stream> streams = {previewStream}; ::android::hardware::camera::device::V3_4::StreamConfiguration config; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; config.streams = streams; config.operationMode = StreamConfigurationMode::NORMAL_MODE; const camera_metadata_t *sessionParamsBuffer = sessionParams.getAndLock(); config.sessionParams.setToExternal( reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (sessionParamsBuffer)), get_camera_metadata_size(sessionParamsBuffer)); - ret = session3_4->configureStreams_3_4(config, - [](Status s, device::V3_4::HalStreamConfiguration halConfig) { - ASSERT_EQ(Status::OK, s); - ASSERT_EQ(1u, halConfig.streams.size()); - }); + config3_5.v3_4 = config; + config3_5.streamConfigCounter = 0; + if (session3_5 != nullptr) { + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + }); + } else { + ret = session3_4->configureStreams_3_4(config, + [](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + }); + } + ASSERT_TRUE(ret.isOk()); free_camera_metadata(staticMetaBuffer); @@ -2959,8 +3377,13 @@ TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { sp<ICameraDeviceSession> session; sp<device::V3_3::ICameraDeviceSession> session3_3; sp<device::V3_4::ICameraDeviceSession> session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp<device::V3_5::ICameraDeviceSession> session3_5; + sp<device::V3_2::ICameraDevice> cameraDevice; + sp<device::V3_5::ICameraDevice> cameraDevice3_5; + openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, + &cameraDevice /*out*/); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); outputBlobStreams.clear(); ASSERT_EQ(Status::OK, @@ -2978,6 +3401,7 @@ TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { ASSERT_NE(0u, jpegBufferSize); int32_t streamId = 0; + uint32_t streamConfigCounter = 0; for (auto& blobIter : outputBlobStreams) { for (auto& previewIter : outputPreviewStreams) { V3_2::Stream previewStream = {streamId++, @@ -2998,11 +3422,21 @@ TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec<V3_2::Stream> streams = {previewStream, blobStream}; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2; createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + verifyStreamCombination(cameraDevice3_5, config3_4, + /*expectedStatus*/ true); + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(2u, halConfig.streams.size()); + }); + } else if (session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration halConfig) { ASSERT_EQ(Status::OK, s); @@ -3052,8 +3486,13 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { sp<ICameraDeviceSession> session; sp<device::V3_3::ICameraDeviceSession> session3_3; sp<device::V3_4::ICameraDeviceSession> session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp<device::V3_5::ICameraDeviceSession> session3_5; + sp<device::V3_2::ICameraDevice> cameraDevice; + sp<device::V3_5::ICameraDevice> cameraDevice3_5; + openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, + &cameraDevice /*out*/); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); Status rc = isConstrainedModeAvailable(staticMeta); if (Status::METHOD_NOT_SUPPORTED == rc) { @@ -3068,6 +3507,7 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { ASSERT_EQ(Status::OK, rc); int32_t streamId = 0; + uint32_t streamConfigCounter = 0; V3_2::Stream stream = {streamId, StreamType::OUTPUT, static_cast<uint32_t>(hfrStream.width), @@ -3077,11 +3517,22 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { 0, StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec<V3_2::Stream> streams = {stream}; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2; createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE, - &config3_2, &config3_4); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5); + if (session3_5 != nullptr) { + verifyStreamCombination(cameraDevice3_5, config3_4, + /*expectedStatus*/ true); + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + ASSERT_EQ(halConfig.streams[0].v3_3.v3_2.id, streamId); + }); + } else if (session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) { ASSERT_EQ(Status::OK, s); @@ -3115,8 +3566,15 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { StreamRotation::ROTATION_0}; streams[0] = stream; createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE, - &config3_2, &config3_4); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5); + if (session3_5 != nullptr) { + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); + } else if (session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration) { ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || @@ -3147,8 +3605,14 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { StreamRotation::ROTATION_0}; streams[0] = stream; createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE, - &config3_2, &config3_4); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5); + if (session3_5 != nullptr) { + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else if (session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration) { ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); @@ -3176,8 +3640,14 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { StreamRotation::ROTATION_0}; streams[0] = stream; createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE, - &config3_2, &config3_4); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5); + if (session3_5 != nullptr) { + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + } else if (session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration) { ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); @@ -3227,8 +3697,13 @@ TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { sp<ICameraDeviceSession> session; sp<device::V3_3::ICameraDeviceSession> session3_3; sp<device::V3_4::ICameraDeviceSession> session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp<device::V3_5::ICameraDeviceSession> session3_5; + sp<device::V3_2::ICameraDevice> cameraDevice; + sp<device::V3_5::ICameraDevice> cameraDevice3_5; + openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/, + &cameraDevice /*out*/); + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + castDevice(cameraDevice, deviceVersion, &cameraDevice3_5); outputBlobStreams.clear(); ASSERT_EQ(Status::OK, @@ -3247,6 +3722,7 @@ TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { ASSERT_NE(0u, jpegBufferSize); int32_t streamId = 0; + uint32_t streamConfigCounter = 0; for (auto& blobIter : outputBlobStreams) { for (auto& videoIter : outputVideoStreams) { V3_2::Stream videoStream = {streamId++, @@ -3266,11 +3742,21 @@ TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF), StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec<V3_2::Stream> streams = {videoStream, blobStream}; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2; createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + verifyStreamCombination(cameraDevice3_5, config3_4, + /*expectedStatus*/ true); + config3_5.streamConfigCounter = streamConfigCounter++; + ret = session3_5->configureStreams_3_5(config3_5, + [](Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(2u, halConfig.streams.size()); + }); + } else if (session3_4 != nullptr) { ret = session3_4->configureStreams_3_4(config3_4, [](Status s, device::V3_4::HalStreamConfiguration halConfig) { ASSERT_EQ(Status::OK, s); @@ -3321,12 +3807,14 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; + sp<DeviceCb> cb; bool supportsPartialResults = false; + bool useHalBufManager = false; uint32_t partialResultCount = 0; configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount /*out*/); + &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/); std::shared_ptr<ResultMetadataQueue> resultQueue; auto resultQueueRet = @@ -3357,17 +3845,26 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { ASSERT_TRUE(ret.isOk()); hidl_handle buffer_handle; - allocateGraphicBuffer(previewStream.width, previewStream.height, - android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, - halStreamConfig.streams[0].consumerUsage), - halStreamConfig.streams[0].overrideFormat, &buffer_handle); - - StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, - bufferId, - buffer_handle, - BufferStatus::OK, - nullptr, - nullptr}; + StreamBuffer outputBuffer; + if (useHalBufManager) { + outputBuffer = {halStreamConfig.streams[0].id, + /*bufferId*/ 0, + buffer_handle, + BufferStatus::OK, + nullptr, + nullptr}; + } else { + allocateGraphicBuffer(previewStream.width, previewStream.height, + android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage), + halStreamConfig.streams[0].overrideFormat, &buffer_handle); + outputBuffer = {halStreamConfig.streams[0].id, + bufferId, + buffer_handle, + BufferStatus::OK, + nullptr, + nullptr}; + } ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer}; StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr}; @@ -3447,6 +3944,10 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId); } + if (useHalBufManager) { + verifyBuffersReturned(session, deviceVersion, previewStream.id, cb); + } + ret = session->close(); ASSERT_TRUE(ret.isOk()); } @@ -3528,12 +4029,16 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { V3_4::HalStreamConfiguration halStreamConfig; bool supportsPartialResults = false; + bool useHalBufManager = false; uint32_t partialResultCount = 0; V3_2::Stream previewStream; sp<device::V3_4::ICameraDeviceSession> session3_4; + sp<device::V3_5::ICameraDeviceSession> session3_5; + sp<DeviceCb> cb; configurePreviewStreams3_4(name, deviceVersion, mProvider, &previewThreshold, physicalIds, - &session3_4, &previewStream, &halStreamConfig /*out*/, - &supportsPartialResults /*out*/, &partialResultCount /*out*/); + &session3_4, &session3_5, &previewStream, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, &partialResultCount /*out*/, + &useHalBufManager /*out*/, &cb /*out*/); ASSERT_NE(session3_4, nullptr); std::shared_ptr<ResultMetadataQueue> resultQueue; @@ -3562,14 +4067,19 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { size_t k = 0; for (const auto& halStream : halStreamConfig.streams) { hidl_handle buffer_handle; - allocateGraphicBuffer(previewStream.width, previewStream.height, - android_convertGralloc1To0Usage(halStream.v3_3.v3_2.producerUsage, - halStream.v3_3.v3_2.consumerUsage), - halStream.v3_3.v3_2.overrideFormat, &buffer_handle); - graphicBuffers.push_back(buffer_handle); - outputBuffers[k] = {halStream.v3_3.v3_2.id, bufferId, buffer_handle, - BufferStatus::OK, nullptr, nullptr}; - bufferId++; + if (useHalBufManager) { + outputBuffers[k] = {halStream.v3_3.v3_2.id, /*bufferId*/0, buffer_handle, + BufferStatus::OK, nullptr, nullptr}; + } else { + allocateGraphicBuffer(previewStream.width, previewStream.height, + android_convertGralloc1To0Usage(halStream.v3_3.v3_2.producerUsage, + halStream.v3_3.v3_2.consumerUsage), + halStream.v3_3.v3_2.overrideFormat, &buffer_handle); + graphicBuffers.push_back(buffer_handle); + outputBuffers[k] = {halStream.v3_3.v3_2.id, bufferId, buffer_handle, + BufferStatus::OK, nullptr, nullptr}; + bufferId++; + } k++; } hidl_vec<V3_4::PhysicalCameraSetting> camSettings(1); @@ -3671,6 +4181,15 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { defaultPreviewSettings.unlock(settingsBuffer); filteredSettings.unlock(filteredSettingsBuffer); + + if (useHalBufManager) { + hidl_vec<int32_t> streamIds(halStreamConfig.streams.size()); + for (size_t i = 0; i < streamIds.size(); i++) { + streamIds[i] = halStreamConfig.streams[i].v3_3.v3_2.id; + } + verifyBuffersReturned(session3_4, streamIds, cb); + } + ret = session3_4->close(); ASSERT_TRUE(ret.isOk()); } @@ -3719,12 +4238,15 @@ TEST_F(CameraHidlTest, processCaptureRequestBurstISO) { ASSERT_TRUE(ret.isOk()); bool supportsPartialResults = false; + bool useHalBufManager = false; uint32_t partialResultCount = 0; V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; + sp<DeviceCb> cb; configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/, - &supportsPartialResults /*out*/, &partialResultCount /*out*/); + &supportsPartialResults /*out*/, &partialResultCount /*out*/, + &useHalBufManager /*out*/, &cb /*out*/); std::shared_ptr<ResultMetadataQueue> resultQueue; auto resultQueueRet = session->getCaptureResultMetadataQueue( @@ -3758,13 +4280,18 @@ TEST_F(CameraHidlTest, processCaptureRequestBurstISO) { std::unique_lock<std::mutex> l(mLock); isoValues[i] = ((i % 2) == 0) ? isoRange.data.i32[0] : isoRange.data.i32[1]; - allocateGraphicBuffer(previewStream.width, previewStream.height, - android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, - halStreamConfig.streams[0].consumerUsage), - halStreamConfig.streams[0].overrideFormat, &buffers[i]); + if (useHalBufManager) { + outputBuffers[i] = {halStreamConfig.streams[0].id, /*bufferId*/0, + nullptr, BufferStatus::OK, nullptr, nullptr}; + } else { + allocateGraphicBuffer(previewStream.width, previewStream.height, + android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage), + halStreamConfig.streams[0].overrideFormat, &buffers[i]); + outputBuffers[i] = {halStreamConfig.streams[0].id, bufferId + i, + buffers[i], BufferStatus::OK, nullptr, nullptr}; + } - outputBuffers[i] = {halStreamConfig.streams[0].id, bufferId + i, - buffers[i], BufferStatus::OK, nullptr, nullptr}; requestMeta.append(reinterpret_cast<camera_metadata_t *> (settings.data())); // Disable all 3A routines @@ -3817,6 +4344,9 @@ TEST_F(CameraHidlTest, processCaptureRequestBurstISO) { std::round(isoValues[i]*isoTol)); } + if (useHalBufManager) { + verifyBuffersReturned(session, deviceVersion, previewStream.id, cb); + } ret = session->close(); ASSERT_TRUE(ret.isOk()); } @@ -3846,18 +4376,25 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; + sp<DeviceCb> cb; bool supportsPartialResults = false; + bool useHalBufManager = false; uint32_t partialResultCount = 0; configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount /*out*/); + &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/); hidl_handle buffer_handle; - allocateGraphicBuffer(previewStream.width, previewStream.height, - android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, - halStreamConfig.streams[0].consumerUsage), - halStreamConfig.streams[0].overrideFormat, &buffer_handle); + + if (useHalBufManager) { + bufferId = 0; + } else { + allocateGraphicBuffer(previewStream.width, previewStream.height, + android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage), + halStreamConfig.streams[0].overrideFormat, &buffer_handle); + } StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, bufferId, @@ -3913,12 +4450,14 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; + sp<DeviceCb> cb; bool supportsPartialResults = false; + bool useHalBufManager = false; uint32_t partialResultCount = 0; configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount /*out*/); + &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/); RequestTemplate reqTemplate = RequestTemplate::PREVIEW; Return<void> ret; @@ -3977,12 +4516,14 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; + sp<DeviceCb> cb; bool supportsPartialResults = false; + bool useHalBufManager = false; uint32_t partialResultCount = 0; configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount /*out*/); + &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/); std::shared_ptr<ResultMetadataQueue> resultQueue; auto resultQueueRet = @@ -4012,10 +4553,14 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { ASSERT_TRUE(ret.isOk()); hidl_handle buffer_handle; - allocateGraphicBuffer(previewStream.width, previewStream.height, - android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, - halStreamConfig.streams[0].consumerUsage), - halStreamConfig.streams[0].overrideFormat, &buffer_handle); + if (useHalBufManager) { + bufferId = 0; + } else { + allocateGraphicBuffer(previewStream.width, previewStream.height, + android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage), + halStreamConfig.streams[0].overrideFormat, &buffer_handle); + } StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, bufferId, @@ -4082,6 +4627,10 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { } } + if (useHalBufManager) { + verifyBuffersReturned(session, deviceVersion, previewStream.id, cb); + } + ret = session->close(); ASSERT_TRUE(ret.isOk()); } @@ -4107,12 +4656,14 @@ TEST_F(CameraHidlTest, flushEmpty) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp<ICameraDeviceSession> session; + sp<DeviceCb> cb; bool supportsPartialResults = false; + bool useHalBufManager = false; uint32_t partialResultCount = 0; configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/, &previewStream /*out*/, &halStreamConfig /*out*/, &supportsPartialResults /*out*/, - &partialResultCount /*out*/); + &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/); Return<Status> returnStatus = session->flush(); ASSERT_TRUE(returnStatus.isOk()); @@ -4187,7 +4738,7 @@ Status CameraHidlTest::getJpegBufferSize(camera_metadata_t *staticMeta, uint32_t } // Check if the camera device has logical multi-camera capability. -Status CameraHidlTest::isLogicalMultiCamera(camera_metadata_t *staticMeta) { +Status CameraHidlTest::isLogicalMultiCamera(const camera_metadata_t *staticMeta) { Status ret = Status::METHOD_NOT_SUPPORTED; if (nullptr == staticMeta) { return Status::ILLEGAL_ARGUMENT; @@ -4211,7 +4762,7 @@ Status CameraHidlTest::isLogicalMultiCamera(camera_metadata_t *staticMeta) { } // Generate a list of physical camera ids backing a logical multi-camera. -Status CameraHidlTest::getPhysicalCameraIds(camera_metadata_t *staticMeta, +Status CameraHidlTest::getPhysicalCameraIds(const camera_metadata_t *staticMeta, std::unordered_set<std::string> *physicalIds) { if ((nullptr == staticMeta) || (nullptr == physicalIds)) { return Status::ILLEGAL_ARGUMENT; @@ -4348,7 +4899,44 @@ Status CameraHidlTest::pickConstrainedModeSize(camera_metadata_t *staticMeta, // Check whether ZSL is available using the static camera // characteristics. -Status CameraHidlTest::isZSLModeAvailable(camera_metadata_t *staticMeta) { +Status CameraHidlTest::isZSLModeAvailable(const camera_metadata_t *staticMeta) { + if (Status::OK == isZSLModeAvailable(staticMeta, PRIV_REPROCESS)) { + return Status::OK; + } else { + return isZSLModeAvailable(staticMeta, YUV_REPROCESS); + } +} + +Status CameraHidlTest::isZSLModeAvailable(const camera_metadata_t *staticMeta, + ReprocessType reprocType) { + + Status ret = Status::METHOD_NOT_SUPPORTED; + if (nullptr == staticMeta) { + return Status::ILLEGAL_ARGUMENT; + } + + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(staticMeta, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry); + if (0 != rc) { + return Status::ILLEGAL_ARGUMENT; + } + + for (size_t i = 0; i < entry.count; i++) { + if ((reprocType == PRIV_REPROCESS && + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING == entry.data.u8[i]) || + (reprocType == YUV_REPROCESS && + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING == entry.data.u8[i])) { + ret = Status::OK; + break; + } + } + + return ret; +} + +// Check whether this is a monochrome camera using the static camera characteristics. +Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) { Status ret = Status::METHOD_NOT_SUPPORTED; if (nullptr == staticMeta) { return Status::ILLEGAL_ARGUMENT; @@ -4362,10 +4950,7 @@ Status CameraHidlTest::isZSLModeAvailable(camera_metadata_t *staticMeta) { } for (size_t i = 0; i < entry.count; i++) { - if ((ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING == - entry.data.u8[i]) || - (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING == - entry.data.u8[i]) ){ + if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME == entry.data.u8[i]) { ret = Status::OK; break; } @@ -4438,9 +5023,11 @@ void CameraHidlTest::createStreamConfiguration( StreamConfigurationMode configMode, ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2 /*out*/, ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4 /*out*/, + ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5 /*out*/, uint32_t jpegBufferSize) { ASSERT_NE(nullptr, config3_2); ASSERT_NE(nullptr, config3_4); + ASSERT_NE(nullptr, config3_5); ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(streams3_2.size()); size_t idx = 0; @@ -4454,7 +5041,9 @@ void CameraHidlTest::createStreamConfiguration( } streams3_4[idx++] = stream; } - *config3_4 = {streams3_4, configMode, {}}; + // Caller is responsible to fill in non-zero config3_5->streamConfigCounter after this returns + *config3_5 = {{streams3_4, configMode, {}}, 0}; + *config3_4 = config3_5->v3_4; *config3_2 = {streams3_2, configMode}; } @@ -4464,15 +5053,22 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t const AvailableStream *previewThreshold, const std::unordered_set<std::string>& physicalIds, sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/, + sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/, V3_2::Stream *previewStream /*out*/, device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, - uint32_t *partialResultCount /*out*/) { + uint32_t *partialResultCount /*out*/, + bool *useHalBufManager /*out*/, + sp<DeviceCb> *outCb /*out*/, + uint32_t streamConfigCounter) { ASSERT_NE(nullptr, session3_4); + ASSERT_NE(nullptr, session3_5); ASSERT_NE(nullptr, halStreamConfig); ASSERT_NE(nullptr, previewStream); ASSERT_NE(nullptr, supportsPartialResults); ASSERT_NE(nullptr, partialResultCount); + ASSERT_NE(nullptr, useHalBufManager); + ASSERT_NE(nullptr, outCb); ASSERT_FALSE(physicalIds.empty()); std::vector<AvailableStream> outputPreviewStreams; @@ -4490,29 +5086,13 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t }); ASSERT_TRUE(ret.isOk()); - sp<DeviceCb> cb = new DeviceCb(this); - sp<ICameraDeviceSession> session; - ret = device3_x->open( - cb, - [&session](auto status, const auto& newSession) { - ALOGI("device::open returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - ASSERT_NE(newSession, nullptr); - session = newSession; - }); - ASSERT_TRUE(ret.isOk()); - - sp<device::V3_3::ICameraDeviceSession> session3_3; - castSession(session, deviceVersion, &session3_3, session3_4); - ASSERT_NE(nullptr, session3_4); - camera_metadata_t *staticMeta; ret = device3_x->getCameraCharacteristics([&] (Status s, CameraMetadata metadata) { ASSERT_EQ(Status::OK, s); staticMeta = clone_camera_metadata( reinterpret_cast<const camera_metadata_t*>(metadata.data())); - ASSERT_NE(nullptr, staticMeta); + ASSERT_NE(nullptr, staticMeta); }); ASSERT_TRUE(ret.isOk()); @@ -4524,6 +5104,31 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t *supportsPartialResults = (*partialResultCount > 1); } + sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta); + sp<ICameraDeviceSession> session; + ret = device3_x->open( + cb, + [&session](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + session = newSession; + }); + ASSERT_TRUE(ret.isOk()); + *outCb = cb; + + sp<device::V3_3::ICameraDeviceSession> session3_3; + castSession(session, deviceVersion, &session3_3, session3_4, session3_5); + ASSERT_NE(nullptr, (*session3_4).get()); + + *useHalBufManager = false; + status = find_camera_metadata_ro_entry(staticMeta, + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry); + if ((0 == status) && (entry.count == 1)) { + *useHalBufManager = (entry.data.u8[0] == + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5); + } + outputPreviewStreams.clear(); auto rc = getAvailableOutputStreams(staticMeta, outputPreviewStreams, previewThreshold); @@ -4544,6 +5149,7 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t } ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}}; RequestTemplate reqTemplate = RequestTemplate::PREVIEW; ret = (*session3_4)->constructDefaultRequestSettings(reqTemplate, @@ -4553,12 +5159,32 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t }); ASSERT_TRUE(ret.isOk()); - ret = (*session3_4)->configureStreams_3_4(config3_4, - [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) { - ASSERT_EQ(Status::OK, s); - ASSERT_EQ(physicalIds.size(), halConfig.streams.size()); - *halStreamConfig = halConfig; - }); + if (*session3_5 != nullptr) { + config3_5.v3_4 = config3_4; + config3_5.streamConfigCounter = streamConfigCounter; + ret = (*session3_5)->configureStreams_3_5(config3_5, + [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(physicalIds.size(), halConfig.streams.size()); + *halStreamConfig = halConfig; + if (*useHalBufManager) { + hidl_vec<V3_2::Stream> streams(physicalIds.size()); + hidl_vec<V3_2::HalStream> halStreams(physicalIds.size()); + for (size_t i = 0; i < physicalIds.size(); i++) { + streams[i] = streams3_4[i].v3_2; + halStreams[i] = halConfig.streams[i].v3_3.v3_2; + } + cb->setCurrentStreamConfig(streams, halStreams); + } + }); + } else { + ret = (*session3_4)->configureStreams_3_4(config3_4, + [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(physicalIds.size(), halConfig.streams.size()); + *halStreamConfig = halConfig; + }); + } *previewStream = streams3_4[0].v3_2; ASSERT_TRUE(ret.isOk()); } @@ -4571,12 +5197,17 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev V3_2::Stream *previewStream /*out*/, HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, - uint32_t *partialResultCount /*out*/) { + uint32_t *partialResultCount /*out*/, + bool *useHalBufManager /*out*/, + sp<DeviceCb> *outCb /*out*/, + uint32_t streamConfigCounter) { ASSERT_NE(nullptr, session); ASSERT_NE(nullptr, previewStream); ASSERT_NE(nullptr, halStreamConfig); ASSERT_NE(nullptr, supportsPartialResults); ASSERT_NE(nullptr, partialResultCount); + ASSERT_NE(nullptr, useHalBufManager); + ASSERT_NE(nullptr, outCb); std::vector<AvailableStream> outputPreviewStreams; ::android::sp<ICameraDevice> device3_x; @@ -4593,21 +5224,6 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev }); ASSERT_TRUE(ret.isOk()); - sp<DeviceCb> cb = new DeviceCb(this); - ret = device3_x->open( - cb, - [&](auto status, const auto& newSession) { - ALOGI("device::open returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - ASSERT_NE(newSession, nullptr); - *session = newSession; - }); - ASSERT_TRUE(ret.isOk()); - - sp<device::V3_3::ICameraDeviceSession> session3_3; - sp<device::V3_4::ICameraDeviceSession> session3_4; - castSession(*session, deviceVersion, &session3_3, &session3_4); - camera_metadata_t *staticMeta; ret = device3_x->getCameraCharacteristics([&] (Status s, CameraMetadata metadata) { @@ -4626,6 +5242,31 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev *supportsPartialResults = (*partialResultCount > 1); } + sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta); + ret = device3_x->open( + cb, + [&](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + *session = newSession; + }); + ASSERT_TRUE(ret.isOk()); + *outCb = cb; + + sp<device::V3_3::ICameraDeviceSession> session3_3; + sp<device::V3_4::ICameraDeviceSession> session3_4; + sp<device::V3_5::ICameraDeviceSession> session3_5; + castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5); + + *useHalBufManager = false; + status = find_camera_metadata_ro_entry(staticMeta, + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry); + if ((0 == status) && (entry.count == 1)) { + *useHalBufManager = (entry.data.u8[0] == + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5); + } + outputPreviewStreams.clear(); auto rc = getAvailableOutputStreams(staticMeta, outputPreviewStreams, previewThreshold); @@ -4646,9 +5287,33 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2}; ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2; ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4; + ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5; createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE, - &config3_2, &config3_4, jpegBufferSize); - if (session3_4 != nullptr) { + &config3_2, &config3_4, &config3_5, jpegBufferSize); + if (session3_5 != nullptr) { + RequestTemplate reqTemplate = RequestTemplate::PREVIEW; + ret = session3_5->constructDefaultRequestSettings(reqTemplate, + [&config3_5](auto status, const auto& req) { + ASSERT_EQ(Status::OK, status); + config3_5.v3_4.sessionParams = req; + }); + ASSERT_TRUE(ret.isOk()); + config3_5.streamConfigCounter = streamConfigCounter; + ret = session3_5->configureStreams_3_5(config3_5, + [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + halStreamConfig->streams.resize(1); + halStreamConfig->streams[0] = halConfig.streams[0].v3_3.v3_2; + if (*useHalBufManager) { + hidl_vec<V3_2::Stream> streams(1); + hidl_vec<V3_2::HalStream> halStreams(1); + streams[0] = stream3_2; + halStreams[0] = halConfig.streams[0].v3_3.v3_2; + cb->setCurrentStreamConfig(streams, halStreams); + } + }); + } else if (session3_4 != nullptr) { RequestTemplate reqTemplate = RequestTemplate::PREVIEW; ret = session3_4->constructDefaultRequestSettings(reqTemplate, [&config3_4](auto status, const auto& req) { @@ -4687,20 +5352,38 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev ASSERT_TRUE(ret.isOk()); } +void CameraHidlTest::castDevice(const sp<device::V3_2::ICameraDevice> &device, + int32_t deviceVersion, sp<device::V3_5::ICameraDevice> *device3_5/*out*/) { + ASSERT_NE(nullptr, device3_5); + if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) { + auto castResult = device::V3_5::ICameraDevice::castFrom(device); + ASSERT_TRUE(castResult.isOk()); + *device3_5 = castResult; + } +} + //Cast camera device session to corresponding version void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion, sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/, - sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/) { + sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/, + sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/) { ASSERT_NE(nullptr, session3_3); ASSERT_NE(nullptr, session3_4); + ASSERT_NE(nullptr, session3_5); switch (deviceVersion) { + case CAMERA_DEVICE_API_VERSION_3_5: { + auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session); + ASSERT_TRUE(castResult.isOk()); + *session3_5 = castResult; + } + [[fallthrough]]; case CAMERA_DEVICE_API_VERSION_3_4: { auto castResult = device::V3_4::ICameraDeviceSession::castFrom(session); ASSERT_TRUE(castResult.isOk()); *session3_4 = castResult; - break; } + [[fallthrough]]; case CAMERA_DEVICE_API_VERSION_3_3: { auto castResult = device::V3_3::ICameraDeviceSession::castFrom(session); ASSERT_TRUE(castResult.isOk()); @@ -4713,11 +5396,345 @@ void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_ } } +void CameraHidlTest::verifyStreamCombination(sp<device::V3_5::ICameraDevice> cameraDevice3_5, + const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4, + bool expectedStatus) { + if (cameraDevice3_5.get() != nullptr) { + auto ret = cameraDevice3_5->isStreamCombinationSupported(config3_4, + [expectedStatus] (Status s, bool combStatus) { + ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s)); + if (Status::OK == s) { + ASSERT_TRUE(combStatus == expectedStatus); + } + }); + ASSERT_TRUE(ret.isOk()); + } +} + +// Verify logical camera static metadata +void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName, + const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device, + const CameraMetadata &chars, int deviceVersion, + const hidl_vec<hidl_string>& deviceNames) { + const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); + ASSERT_NE(nullptr, metadata); + + Status rc = isLogicalMultiCamera(metadata); + ASSERT_TRUE(Status::OK == rc || Status::METHOD_NOT_SUPPORTED == rc); + if (Status::METHOD_NOT_SUPPORTED == rc) { + return; + } + + std::string version, cameraId; + ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId)); + std::unordered_set<std::string> physicalIds; + ASSERT_TRUE(Status::OK == getPhysicalCameraIds(metadata, &physicalIds)); + for (auto physicalId : physicalIds) { + ASSERT_NE(physicalId, cameraId); + bool isPublicId = false; + for (auto& deviceName : deviceNames) { + std::string publicVersion, publicId; + ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId)); + if (physicalId == publicId) { + isPublicId = true; + break; + } + } + if (isPublicId) { + continue; + } + + ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5); + auto castResult = device::V3_5::ICameraDevice::castFrom(device); + ASSERT_TRUE(castResult.isOk()); + ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice> device3_5 = + castResult; + ASSERT_NE(device3_5, nullptr); + + // Check camera characteristics for hidden camera id + Return<void> ret = device3_5->getPhysicalCameraCharacteristics(physicalId, + [&](auto status, const auto& chars) { + verifyCameraCharacteristics(status, chars); + verifyMonochromeCharacteristics(chars, deviceVersion); + }); + ASSERT_TRUE(ret.isOk()); + + // Check calling getCameraDeviceInterface_V3_x() on hidden camera id returns + // ILLEGAL_ARGUMENT. + std::stringstream s; + s << "device@" << version << "/" << mProviderType << "/" << physicalId; + hidl_string fullPhysicalId(s.str()); + ret = mProvider->getCameraDeviceInterface_V3_x(fullPhysicalId, + [&](auto status, const auto& device3_x) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status); + ASSERT_EQ(device3_x, nullptr); + }); + ASSERT_TRUE(ret.isOk()); + } + + // Make sure ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID is available in + // result keys. + if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) { + camera_metadata_ro_entry entry; + int retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry); + if ((0 == retcode) && (entry.count > 0)) { + ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count, + static_cast<int32_t>( + CameraMetadataTag::ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID)), + entry.data.i32 + entry.count); + } else { + ADD_FAILURE() << "Get camera availableResultKeys failed!"; + } + } +} + +void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMetadata& chars) { + ASSERT_EQ(Status::OK, status); + const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); + size_t expectedSize = chars.size(); + int result = validate_camera_metadata_structure(metadata, &expectedSize); + ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED)); + size_t entryCount = get_camera_metadata_entry_count(metadata); + // TODO: we can do better than 0 here. Need to check how many required + // characteristics keys we've defined. + ASSERT_GT(entryCount, 0u); + + camera_metadata_ro_entry entry; + int retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry); + if ((0 == retcode) && (entry.count > 0)) { + uint8_t hardwareLevel = entry.data.u8[0]; + ASSERT_TRUE( + hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED || + hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL || + hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3 || + hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); + } else { + ADD_FAILURE() << "Get camera hardware level failed!"; + } + + entry.count = 0; + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION, &entry); + if ((0 == retcode) || (entry.count > 0)) { + ADD_FAILURE() << "ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION " + << " per API contract should never be set by Hal!"; + } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, &entry); + if ((0 == retcode) || (entry.count > 0)) { + ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS" + << " per API contract should never be set by Hal!"; + } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, &entry); + if ((0 == retcode) || (entry.count > 0)) { + ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS" + << " per API contract should never be set by Hal!"; + } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, &entry); + if ((0 == retcode) || (entry.count > 0)) { + ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS" + << " per API contract should never be set by Hal!"; + } +} + +void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars, + int deviceVersion) { + const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); + Status rc = isMonochromeCamera(metadata); + if (Status::METHOD_NOT_SUPPORTED == rc) { + return; + } + ASSERT_EQ(Status::OK, rc); + + camera_metadata_ro_entry entry; + // Check capabilities + int retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry); + if ((0 == retcode) && (entry.count > 0)) { + ASSERT_EQ(std::find(entry.data.u8, entry.data.u8 + entry.count, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING), + entry.data.u8 + entry.count); + if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_5) { + ASSERT_EQ(std::find(entry.data.u8, entry.data.u8 + entry.count, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW), + entry.data.u8 + entry.count); + } + } + + if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) { + // Check Cfa + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, &entry); + if ((0 == retcode) && (entry.count == 1)) { + ASSERT_TRUE(entry.data.i32[0] == static_cast<int32_t>( + CameraMetadataEnumAndroidSensorInfoColorFilterArrangement::ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO) + || entry.data.i32[0] == static_cast<int32_t>( + CameraMetadataEnumAndroidSensorInfoColorFilterArrangement::ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR)); + } + + // Check availableRequestKeys + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry); + if ((0 == retcode) && (entry.count > 0)) { + for (size_t i = 0; i < entry.count; i++) { + ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_MODE); + ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_TRANSFORM); + ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_GAINS); + } + } else { + ADD_FAILURE() << "Get camera availableRequestKeys failed!"; + } + + // Check availableResultKeys + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry); + if ((0 == retcode) && (entry.count > 0)) { + for (size_t i = 0; i < entry.count; i++) { + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_GREEN_SPLIT); + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_NEUTRAL_COLOR_POINT); + ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_MODE); + ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_TRANSFORM); + ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_GAINS); + } + } else { + ADD_FAILURE() << "Get camera availableResultKeys failed!"; + } + + // Check availableCharacteristicKeys + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry); + if ((0 == retcode) && (entry.count > 0)) { + for (size_t i = 0; i < entry.count; i++) { + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_REFERENCE_ILLUMINANT1); + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_REFERENCE_ILLUMINANT2); + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_CALIBRATION_TRANSFORM1); + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_CALIBRATION_TRANSFORM2); + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_COLOR_TRANSFORM1); + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_COLOR_TRANSFORM2); + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_FORWARD_MATRIX1); + ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_FORWARD_MATRIX2); + } + } else { + ADD_FAILURE() << "Get camera availableResultKeys failed!"; + } + + // Check blackLevelPattern + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_SENSOR_BLACK_LEVEL_PATTERN, &entry); + if ((0 == retcode) && (entry.count > 0)) { + ASSERT_EQ(entry.count, 4); + for (size_t i = 1; i < entry.count; i++) { + ASSERT_EQ(entry.data.i32[i], entry.data.i32[0]); + } + } + } +} + +void CameraHidlTest::verifyMonochromeCameraResult( + const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata) { + camera_metadata_ro_entry entry; + + // Check tags that are not applicable for monochrome camera + ASSERT_FALSE(metadata.exists(ANDROID_SENSOR_GREEN_SPLIT)); + ASSERT_FALSE(metadata.exists(ANDROID_SENSOR_NEUTRAL_COLOR_POINT)); + ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_MODE)); + ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_TRANSFORM)); + ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_GAINS)); + + // Check dynamicBlackLevel + entry = metadata.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL); + if (entry.count > 0) { + ASSERT_EQ(entry.count, 4); + for (size_t i = 1; i < entry.count; i++) { + ASSERT_FLOAT_EQ(entry.data.f[i], entry.data.f[0]); + } + } + + // Check noiseProfile + entry = metadata.find(ANDROID_SENSOR_NOISE_PROFILE); + if (entry.count > 0) { + ASSERT_EQ(entry.count, 2); + } + + // Check lensShadingMap + entry = metadata.find(ANDROID_STATISTICS_LENS_SHADING_MAP); + if (entry.count > 0) { + ASSERT_EQ(entry.count % 4, 0); + for (size_t i = 0; i < entry.count/4; i++) { + ASSERT_FLOAT_EQ(entry.data.f[i*4+1], entry.data.f[i*4]); + ASSERT_FLOAT_EQ(entry.data.f[i*4+2], entry.data.f[i*4]); + ASSERT_FLOAT_EQ(entry.data.f[i*4+3], entry.data.f[i*4]); + } + } + + // Check tonemapCurve + camera_metadata_ro_entry curveRed = metadata.find(ANDROID_TONEMAP_CURVE_RED); + camera_metadata_ro_entry curveGreen = metadata.find(ANDROID_TONEMAP_CURVE_GREEN); + camera_metadata_ro_entry curveBlue = metadata.find(ANDROID_TONEMAP_CURVE_BLUE); + if (curveRed.count > 0 && curveGreen.count > 0 && curveBlue.count > 0) { + ASSERT_EQ(curveRed.count, curveGreen.count); + ASSERT_EQ(curveRed.count, curveBlue.count); + for (size_t i = 0; i < curveRed.count; i++) { + ASSERT_FLOAT_EQ(curveGreen.data.f[i], curveRed.data.f[i]); + ASSERT_FLOAT_EQ(curveBlue.data.f[i], curveRed.data.f[i]); + } + } +} + +void CameraHidlTest::verifyBuffersReturned( + sp<device::V3_2::ICameraDeviceSession> session, + int deviceVersion, int32_t streamId, + sp<DeviceCb> cb, uint32_t streamConfigCounter) { + sp<device::V3_3::ICameraDeviceSession> session3_3; + sp<device::V3_4::ICameraDeviceSession> session3_4; + sp<device::V3_5::ICameraDeviceSession> session3_5; + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + ASSERT_NE(nullptr, session3_5.get()); + + hidl_vec<int32_t> streamIds(1); + streamIds[0] = streamId; + session3_5->signalStreamFlush(streamIds, /*streamConfigCounter*/streamConfigCounter); + cb->waitForBuffersReturned(); +} + +void CameraHidlTest::verifyBuffersReturned( + sp<device::V3_4::ICameraDeviceSession> session3_4, + hidl_vec<int32_t> streamIds, sp<DeviceCb> cb, uint32_t streamConfigCounter) { + auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session3_4); + ASSERT_TRUE(castResult.isOk()); + sp<device::V3_5::ICameraDeviceSession> session3_5 = castResult; + ASSERT_NE(nullptr, session3_5.get()); + + session3_5->signalStreamFlush(streamIds, /*streamConfigCounter*/streamConfigCounter); + cb->waitForBuffersReturned(); +} + +void CameraHidlTest::verifyLogicalCameraResult(const camera_metadata_t* staticMetadata, + const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& resultMetadata) { + std::unordered_set<std::string> physicalIds; + Status rc = getPhysicalCameraIds(staticMetadata, &physicalIds); + ASSERT_TRUE(Status::OK == rc); + ASSERT_TRUE(physicalIds.size() > 1); + + camera_metadata_ro_entry entry; + // Check mainPhysicalId + entry = resultMetadata.find(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID); + if (entry.count > 0) { + std::string mainPhysicalId(reinterpret_cast<const char *>(entry.data.u8)); + ASSERT_NE(physicalIds.find(mainPhysicalId), physicalIds.end()); + } else { + ADD_FAILURE() << "Get LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID failed!"; + } +} + // Open a device session with empty callbacks and return static metadata. -void CameraHidlTest::openEmptyDeviceSession(const std::string &name, - sp<ICameraProvider> provider, - sp<ICameraDeviceSession> *session /*out*/, - camera_metadata_t **staticMeta /*out*/) { +void CameraHidlTest::openEmptyDeviceSession(const std::string &name, sp<ICameraProvider> provider, + sp<ICameraDeviceSession> *session /*out*/, camera_metadata_t **staticMeta /*out*/, + ::android::sp<ICameraDevice> *cameraDevice /*out*/) { ASSERT_NE(nullptr, session); ASSERT_NE(nullptr, staticMeta); @@ -4734,6 +5751,9 @@ void CameraHidlTest::openEmptyDeviceSession(const std::string &name, device3_x = device; }); ASSERT_TRUE(ret.isOk()); + if (cameraDevice != nullptr) { + *cameraDevice = device3_x; + } sp<EmptyDeviceCb> cb = new EmptyDeviceCb(); ret = device3_x->open(cb, [&](auto status, const auto& newSession) { @@ -4918,6 +5938,94 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint ASSERT_TRUE(ret.isOk()); } +void CameraHidlTest::verifyRecommendedConfigs(const CameraMetadata& chars) { + size_t CONFIG_ENTRY_SIZE = 5; + size_t CONFIG_ENTRY_TYPE_OFFSET = 3; + size_t CONFIG_ENTRY_BITFIELD_OFFSET = 4; + uint32_t maxPublicUsecase = + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END; + uint32_t vendorUsecaseStart = + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START; + uint32_t usecaseMask = (1 << vendorUsecaseStart) - 1; + usecaseMask &= ~((1 << maxPublicUsecase) - 1); + + const camera_metadata_t* metadata = reinterpret_cast<const camera_metadata_t*> (chars.data()); + + camera_metadata_ro_entry recommendedConfigsEntry, recommendedDepthConfigsEntry, ioMapEntry; + recommendedConfigsEntry.count = recommendedDepthConfigsEntry.count = ioMapEntry.count = 0; + int retCode = find_camera_metadata_ro_entry(metadata, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS, &recommendedConfigsEntry); + int depthRetCode = find_camera_metadata_ro_entry(metadata, + ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS, + &recommendedDepthConfigsEntry); + int ioRetCode = find_camera_metadata_ro_entry(metadata, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP, &ioMapEntry); + if ((0 != retCode) && (0 != depthRetCode)) { + //In case both regular and depth recommended configurations are absent, + //I/O should be absent as well. + ASSERT_NE(ioRetCode, 0); + return; + } + + camera_metadata_ro_entry availableKeysEntry; + retCode = find_camera_metadata_ro_entry(metadata, + ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &availableKeysEntry); + ASSERT_TRUE((0 == retCode) && (availableKeysEntry.count > 0)); + std::vector<int32_t> availableKeys; + availableKeys.reserve(availableKeysEntry.count); + availableKeys.insert(availableKeys.end(), availableKeysEntry.data.i32, + availableKeysEntry.data.i32 + availableKeysEntry.count); + + if (recommendedConfigsEntry.count > 0) { + ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(), + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS), + availableKeys.end()); + ASSERT_EQ((recommendedConfigsEntry.count % CONFIG_ENTRY_SIZE), 0); + for (size_t i = 0; i < recommendedConfigsEntry.count; i += CONFIG_ENTRY_SIZE) { + int32_t entryType = + recommendedConfigsEntry.data.i32[i + CONFIG_ENTRY_TYPE_OFFSET]; + uint32_t bitfield = + recommendedConfigsEntry.data.i32[i + CONFIG_ENTRY_BITFIELD_OFFSET]; + ASSERT_TRUE((entryType == + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) || + (entryType == + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT)); + ASSERT_TRUE((bitfield & usecaseMask) == 0); + } + } + + if (recommendedDepthConfigsEntry.count > 0) { + ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(), + ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS), + availableKeys.end()); + ASSERT_EQ((recommendedDepthConfigsEntry.count % CONFIG_ENTRY_SIZE), 0); + for (size_t i = 0; i < recommendedDepthConfigsEntry.count; i += CONFIG_ENTRY_SIZE) { + int32_t entryType = + recommendedDepthConfigsEntry.data.i32[i + CONFIG_ENTRY_TYPE_OFFSET]; + uint32_t bitfield = + recommendedDepthConfigsEntry.data.i32[i + CONFIG_ENTRY_BITFIELD_OFFSET]; + ASSERT_TRUE((entryType == + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) || + (entryType == + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT)); + ASSERT_TRUE((bitfield & usecaseMask) == 0); + } + + if (recommendedConfigsEntry.count == 0) { + //In case regular recommended configurations are absent but suggested depth + //configurations are present, I/O should be absent. + ASSERT_NE(ioRetCode, 0); + } + } + + if ((ioRetCode == 0) && (ioMapEntry.count > 0)) { + ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(), + ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP), + availableKeys.end()); + ASSERT_EQ(isZSLModeAvailable(metadata), Status::OK); + } +} + int main(int argc, char **argv) { ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp index debb3e5bed..aa080f4581 100644 --- a/cas/1.0/default/Android.bp +++ b/cas/1.0/default/Android.bp @@ -23,10 +23,10 @@ cc_defaults { "libhidlmemory", "libhidltransport", "liblog", + "libstagefright_foundation", "libutils", ], header_libs: [ - "libstagefright_foundation_headers", "media_plugin_headers", ], } diff --git a/cas/1.0/default/DescramblerImpl.cpp b/cas/1.0/default/DescramblerImpl.cpp index 6d5e2d5e32..9b09751d72 100644 --- a/cas/1.0/default/DescramblerImpl.cpp +++ b/cas/1.0/default/DescramblerImpl.cpp @@ -20,6 +20,7 @@ #include <hidlmemory/mapping.h> #include <media/cas/DescramblerAPI.h> #include <media/hardware/CryptoAPI.h> +#include <media/stagefright/foundation/AString.h> #include <media/stagefright/foundation/AUtils.h> #include <utils/Log.h> @@ -177,6 +178,7 @@ Return<void> DescramblerImpl::descramble( // Casting hidl SubSample to DescramblerPlugin::SubSample, but need // to ensure structs are actually idential + AString detailedError; int32_t result = holder->descramble( dstBuffer.type != BufferType::SHARED_MEMORY, (DescramblerPlugin::ScramblingControl)scramblingControl, @@ -186,10 +188,10 @@ Return<void> DescramblerImpl::descramble( srcOffset, dstPtr, dstOffset, - NULL); + &detailedError); holder.reset(); - _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL); + _hidl_cb(toStatus(result >= 0 ? OK : result), result, detailedError.c_str()); return Void(); } diff --git a/compatibility_matrices/compatibility_matrix.3.xml b/compatibility_matrices/compatibility_matrix.3.xml index e13d293b75..4cb3776b16 100644 --- a/compatibility_matrices/compatibility_matrix.3.xml +++ b/compatibility_matrices/compatibility_matrix.3.xml @@ -193,7 +193,7 @@ </hal> <hal format="hidl" optional="false"> <name>android.hardware.graphics.composer</name> - <version>2.1-2</version> + <version>2.1-3</version> <interface> <name>IComposer</name> <instance>default</instance> diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index d9f5ebb5fd..94ffe80aab 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -9,7 +9,7 @@ </hal> <hal format="hidl" optional="false"> <name>android.hardware.audio</name> - <version>4.0</version> + <version>5.0</version> <interface> <name>IDevicesFactory</name> <instance>default</instance> @@ -17,7 +17,7 @@ </hal> <hal format="hidl" optional="false"> <name>android.hardware.audio.effect</name> - <version>4.0</version> + <version>5.0</version> <interface> <name>IEffectsFactory</name> <instance>default</instance> @@ -56,6 +56,14 @@ </interface> </hal> <hal format="hidl" optional="true"> + <name>android.hardware.biometrics.face</name> + <version>1.0</version> + <interface> + <name>IBiometricsFace</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> <name>android.hardware.biometrics.fingerprint</name> <version>2.1</version> <interface> @@ -121,7 +129,7 @@ </hal> <hal format="hidl" optional="false"> <name>android.hardware.configstore</name> - <version>1.1</version> + <version>1.2</version> <interface> <name>ISurfaceFlingerConfigs</name> <instance>default</instance> @@ -145,7 +153,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.drm</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>ICryptoFactory</name> <regex-instance>.*</regex-instance> @@ -157,7 +165,7 @@ </hal> <hal format="hidl" optional="false"> <name>android.hardware.drm</name> - <version>1.1</version> + <version>1.2</version> <interface> <name>ICryptoFactory</name> <regex-instance>.*</regex-instance> @@ -186,6 +194,7 @@ <hal format="hidl" optional="true"> <name>android.hardware.gnss</name> <version>1.0-1</version> + <version>2.0</version> <interface> <name>IGnss</name> <instance>default</instance> @@ -194,6 +203,7 @@ <hal format="hidl" optional="false"> <name>android.hardware.graphics.allocator</name> <version>2.0</version> + <version>3.0</version> <interface> <name>IAllocator</name> <instance>default</instance> @@ -201,7 +211,7 @@ </hal> <hal format="hidl" optional="false"> <name>android.hardware.graphics.composer</name> - <version>2.1</version> + <version>2.1-3</version> <interface> <name>IComposer</name> <instance>default</instance> @@ -209,7 +219,8 @@ </hal> <hal format="hidl" optional="false"> <name>android.hardware.graphics.mapper</name> - <version>2.0</version> + <version>2.0-1</version> + <version>3.0</version> <interface> <name>IMapper</name> <instance>default</instance> @@ -224,16 +235,28 @@ </interface> </hal> <hal format="hidl" optional="true"> - <name>android.hardware.health.filesystem</name> + <name>android.hardware.health.storage</name> <version>1.0</version> <interface> - <name>IFileSystem</name> + <name>IStorage</name> <instance>default</instance> </interface> </hal> <hal format="hidl" optional="true"> <name>android.hardware.ir</name> <version>1.0</version> + <interface> + <name>IConsumerIr</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl" optional="true"> + <name>android.hardware.input.classifier</name> + <version>1.0</version> + <interface> + <name>IInputClassifier</name> + <instance>default</instance> + </interface> </hal> <hal format="hidl" optional="false"> <name>android.hardware.keymaster</name> @@ -363,6 +386,7 @@ <hal format="hidl" optional="true"> <name>android.hardware.sensors</name> <version>1.0</version> + <version>2.0</version> <interface> <name>ISensors</name> <instance>default</instance> @@ -370,7 +394,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.soundtrigger</name> - <version>2.0-1</version> + <version>2.0-2</version> <interface> <name>ISoundTriggerHw</name> <instance>default</instance> @@ -395,6 +419,7 @@ <hal format="hidl" optional="true"> <name>android.hardware.thermal</name> <version>1.0-1</version> + <version>2.0</version> <interface> <name>IThermal</name> <instance>default</instance> @@ -418,7 +443,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.usb</name> - <version>1.0-1</version> + <version>1.0-2</version> <interface> <name>IUsb</name> <instance>default</instance> @@ -434,7 +459,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.vibrator</name> - <version>1.0-2</version> + <version>1.0-3</version> <interface> <name>IVibrator</name> <instance>default</instance> @@ -458,7 +483,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.wifi</name> - <version>1.0-2</version> + <version>1.0-3</version> <interface> <name>IWifi</name> <instance>default</instance> @@ -466,7 +491,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.wifi.hostapd</name> - <version>1.0</version> + <version>1.0-1</version> <interface> <name>IHostapd</name> <instance>default</instance> @@ -482,7 +507,7 @@ </hal> <hal format="hidl" optional="true"> <name>android.hardware.wifi.supplicant</name> - <version>1.0-1</version> + <version>1.0-2</version> <interface> <name>ISupplicant</name> <instance>default</instance> diff --git a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp index a1676be2b7..70b5830c77 100644 --- a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp +++ b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp @@ -131,6 +131,27 @@ TEST_F(ConfigstoreHidlTest, TestSameReturnValue) { } } +/** + * Make sure the constrains of hasWideColorDisplay, hasHDRDisplay + * are enforced. + */ +TEST_F(ConfigstoreHidlTest, TestColorConstrainsBasic) { + bool hasWideColorDisplay; + bool hasHDRDisplay; + + Return<void> status = sfConfigs->hasWideColorDisplay( + [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; }); + EXPECT_OK(status); + + status = sfConfigs->hasHDRDisplay([&](OptionalBool arg) { hasHDRDisplay = arg.specified; }); + EXPECT_OK(status); + + // When hasHDRDisplay returns true, hasWideColorDisplay must also return true. + if (hasHDRDisplay) { + ASSERT_TRUE(hasWideColorDisplay); + } +} + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(ConfigstoreHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); diff --git a/configstore/1.1/default/surfaceflinger.mk b/configstore/1.1/default/surfaceflinger.mk deleted file mode 100644 index 35922ebb09..0000000000 --- a/configstore/1.1/default/surfaceflinger.mk +++ /dev/null @@ -1,56 +0,0 @@ - -LOCAL_SRC_FILES += SurfaceFlingerConfigs.cpp - -ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),) - LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS) -endif - -ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),) - LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS) -endif - -ifeq ($(TARGET_USE_CONTEXT_PRIORITY),true) - LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1 -endif - -ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY),true) - LOCAL_CFLAGS += -DHAS_WIDE_COLOR_DISPLAY -endif - -ifeq ($(TARGET_HAS_HDR_DISPLAY),true) - LOCAL_CFLAGS += -DHAS_HDR_DISPLAY -endif - -ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),) - LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS) -else - LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0 -endif - -ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true) - LOCAL_CFLAGS += -DFORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS -endif - -ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),) - LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=$(MAX_VIRTUAL_DISPLAY_DIMENSION) -endif - -ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true) - LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK -endif - -ifneq ($(USE_VR_FLINGER),) - LOCAL_CFLAGS += -DUSE_VR_FLINGER -endif - -ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),) - LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) -endif - -ifneq ($(SF_START_GRAPHICS_ALLOCATOR_SERVICE),) - LOCAL_CFLAGS += -DSTART_GRAPHICS_ALLOCATOR_SERVICE -endif - -ifneq ($(SF_PRIMARY_DISPLAY_ORIENTATION),) - LOCAL_CFLAGS += -DPRIMARY_DISPLAY_ORIENTATION=$(SF_PRIMARY_DISPLAY_ORIENTATION) -endif diff --git a/configstore/1.2/Android.bp b/configstore/1.2/Android.bp new file mode 100644 index 0000000000..a3976b649f --- /dev/null +++ b/configstore/1.2/Android.bp @@ -0,0 +1,27 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.configstore@1.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ISurfaceFlingerConfigs.hal", + ], + interfaces: [ + "android.hardware.configstore@1.0", + "android.hardware.configstore@1.1", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hidl.base@1.0", + ], + types: [ + "CieXyz", + "DisplayPrimaries", + ], + gen_java: true, +} + diff --git a/configstore/1.2/ISurfaceFlingerConfigs.hal b/configstore/1.2/ISurfaceFlingerConfigs.hal new file mode 100644 index 0000000000..431b3fc479 --- /dev/null +++ b/configstore/1.2/ISurfaceFlingerConfigs.hal @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.1 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.configstore@1.2; + +import android.hardware.graphics.common@1.2::PixelFormat; +import android.hardware.graphics.common@1.2::Dataspace; +import @1.1::ISurfaceFlingerConfigs; +import @1.0::OptionalBool; + +/** + * New revision of ISurfaceFlingerConfigs + */ +interface ISurfaceFlingerConfigs extends @1.1::ISurfaceFlingerConfigs { + /** + * useColorManagement indicates whether SurfaceFlinger should manage color + * by switching to appropriate color mode automatically depending on the + * Dataspace of the surfaces on screen. + * This function must return true when hasWideColorDisplay or hasHDRDisplay + * return true. + */ + useColorManagement() generates (OptionalBool value); + + /** + * Returns the default data space and pixel format that SurfaceFlinger + * expects to receive and output as well as the wide color gamut data space + * and pixel format for wide color gamut surfaces. + * To determine the data space and pixel format, there are a few things + * we recommend to consider: + * + * 1. Hardware composer's capability to composite contents with the chosen + * data space and pixel format efficiently; + * 2. Hardware composer's ability to composite contents when sRGB contents + * and the chosen wide color gamut data space contents coexist; + * 3. For better blending, consider using pixel format where the alpha + * channel has as many bits as the RGB color channel. + * 4. Memory consumption and efficient buffer compression when considering + * more bits in pixel format. + * + * @return dataspace is the default data space that SurfaceFlinger expects. + * The data space must not be Dataspace::UNKNOWN, if unspecified, + * the default data space is Dataspace::V0_SRGB; + * @return pixelFormat is the default pixel format that SurfaceFlinger + * expects. If unspecified, the default pixel format is + * PixelFormat::RGBA_8888. + * @return wcgDataspace is the data space that SurfaceFlinger expects for + * wide color gamut surfaces. + * When hasWideColorDisplay returns true, this API must return a + * valid wide color gamut data space. + * The data space must not be UNKNOWN, if unspecified, the data space + * is V0_SRGB by default, which essentially indicates there's no wide + * color gamut, meaning hasWideColorDisplay returns false. + * @return wcgPixelFormat is the pixel format that SurfaceFlinger expects for + * wide color gamut surfaces. If unspecified, the pixel format is + * PixelFormat::RGBA_8888 by default. + */ + getCompositionPreference() + generates (Dataspace dataspace, PixelFormat pixelFormat, + Dataspace wcgDataspace, PixelFormat wcgPixelFormat); + + /** + * Returns the native panel primary data. The data includes red, green, + * blue and white. The primary format is CIE 1931 XYZ color space. If + * unspecified, the primaries is sRGB gamut by default. + */ + getDisplayNativePrimaries() generates (DisplayPrimaries primaries); +}; diff --git a/configstore/1.1/default/Android.mk b/configstore/1.2/default/Android.mk index 40f621b3ad..b807357876 100644 --- a/configstore/1.1/default/Android.mk +++ b/configstore/1.2/default/Android.mk @@ -2,15 +2,15 @@ LOCAL_PATH := $(call my-dir) ################################################################################ include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.configstore@1.1-service +LOCAL_MODULE := android.hardware.configstore@1.2-service # seccomp is not required for coverage build. ifneq ($(NATIVE_COVERAGE),true) -LOCAL_REQUIRED_MODULES_arm64 := configstore@1.1.policy +LOCAL_REQUIRED_MODULES_arm64 := configstore.policy endif -LOCAL_PROPRIETARY_MODULE := true +LOCAL_VENDOR_MODULE := true LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_INIT_RC := android.hardware.configstore@1.1-service.rc +LOCAL_INIT_RC := android.hardware.configstore@1.2-service.rc LOCAL_SRC_FILES:= service.cpp include $(LOCAL_PATH)/surfaceflinger.mk @@ -23,16 +23,17 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libutils \ android.hardware.configstore@1.0 \ - android.hardware.configstore@1.1 + android.hardware.configstore@1.1 \ + android.hardware.configstore@1.2 include $(BUILD_EXECUTABLE) # seccomp filter for configstore ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm64)) include $(CLEAR_VARS) -LOCAL_MODULE := configstore@1.1.policy +LOCAL_MODULE := configstore.policy LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy -LOCAL_SRC_FILES := seccomp_policy/configstore@1.1-$(TARGET_ARCH).policy +LOCAL_SRC_FILES := seccomp_policy/configstore-$(TARGET_ARCH).policy include $(BUILD_PREBUILT) endif diff --git a/configstore/1.1/default/SurfaceFlingerConfigs.cpp b/configstore/1.2/default/SurfaceFlingerConfigs.cpp index da3081c12f..714442bd22 100644 --- a/configstore/1.1/default/SurfaceFlingerConfigs.cpp +++ b/configstore/1.2/default/SurfaceFlingerConfigs.cpp @@ -17,16 +17,20 @@ #include "SurfaceFlingerConfigs.h" #include <android/hardware/configstore/1.1/types.h> +#include <android/hardware/configstore/1.2/types.h> +#include <android/hardware/graphics/common/1.1/types.h> #include <log/log.h> namespace android { namespace hardware { namespace configstore { -namespace V1_1 { +namespace V1_2 { namespace implementation { -// Methods from ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs -// follow. +using ::android::hardware::graphics::common::V1_2::Dataspace; +using ::android::hardware::graphics::common::V1_2::PixelFormat; + +// ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs implementation. Return<void> SurfaceFlingerConfigs::vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) { #ifdef VSYNC_EVENT_PHASE_OFFSET_NS _hidl_cb({true, VSYNC_EVENT_PHASE_OFFSET_NS}); @@ -142,8 +146,7 @@ Return<void> SurfaceFlingerConfigs::startGraphicsAllocatorService( return Void(); } -// Methods from ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs -// follow. +// ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs implementation. #ifdef PRIMARY_DISPLAY_ORIENTATION static_assert(PRIMARY_DISPLAY_ORIENTATION == 0 || PRIMARY_DISPLAY_ORIENTATION == 90 || @@ -191,10 +194,135 @@ Return<void> SurfaceFlingerConfigs::primaryDisplayOrientation( return Void(); } -// Methods from ::android::hidl::base::V1_0::IBase follow. +// ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs implementation. +Return<void> SurfaceFlingerConfigs::useColorManagement(useColorManagement_cb _hidl_cb) { +#if defined(USE_COLOR_MANAGEMENT) || defined(HAS_WIDE_COLOR_DISPLAY) || defined(HAS_HDR_DISPLAY) + _hidl_cb({true, true}); +#else + _hidl_cb({true, false}); +#endif + return Void(); +} + +#ifdef DEFAULT_COMPOSITION_DATA_SPACE +static_assert(DEFAULT_COMPOSITION_DATA_SPACE != 0, + "Default composition data space must not be UNKNOWN"); +#endif + +#ifdef WCG_COMPOSITION_DATA_SPACE +static_assert(WCG_COMPOSITION_DATA_SPACE != 0, + "Wide color gamut composition data space must not be UNKNOWN"); +#endif + +Return<void> SurfaceFlingerConfigs::getCompositionPreference(getCompositionPreference_cb _hidl_cb) { + Dataspace defaultDataspace = Dataspace::V0_SRGB; + PixelFormat defaultPixelFormat = PixelFormat::RGBA_8888; + +#ifdef DEFAULT_COMPOSITION_DATA_SPACE + defaultDataspace = static_cast<Dataspace>(DEFAULT_COMPOSITION_DATA_SPACE); +#endif + +#ifdef DEFAULT_COMPOSITION_PIXEL_FORMAT + defaultPixelFormat = static_cast<PixelFormat>(DEFAULT_COMPOSITION_PIXEL_FORMAT); +#endif + + Dataspace wideColorGamutDataspace = Dataspace::V0_SRGB; + PixelFormat wideColorGamutPixelFormat = PixelFormat::RGBA_8888; + +#ifdef WCG_COMPOSITION_DATA_SPACE + wideColorGamutDataspace = static_cast<Dataspace>(WCG_COMPOSITION_DATA_SPACE); +#endif + +#ifdef WCG_COMPOSITION_PIXEL_FORMAT + wideColorGamutPixelFormat = static_cast<PixelFormat>(WCG_COMPOSITION_PIXEL_FORMAT); +#endif + + _hidl_cb(defaultDataspace, defaultPixelFormat, wideColorGamutDataspace, + wideColorGamutPixelFormat); + return Void(); +} + +Return<void> SurfaceFlingerConfigs::getDisplayNativePrimaries(getDisplayNativePrimaries_cb _hidl_cb) { + DisplayPrimaries primaries; + // The default XYZ is sRGB gamut in CIE1931 color space +#ifdef TARGET_DISPLAY_PRIMARY_RED_X + primaries.red.X = TARGET_DISPLAY_PRIMARY_RED_X; +#else + primaries.red.X = 0.4123; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_RED_Y + primaries.red.Y = TARGET_DISPLAY_PRIMARY_RED_Y; +#else + primaries.red.Y = 0.2126; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_RED_Z + primaries.red.Z = TARGET_DISPLAY_PRIMARY_RED_Z; +#else + primaries.red.Z = 0.0193; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_GREEN_X + primaries.green.X = TARGET_DISPLAY_PRIMARY_GREEN_X; +#else + primaries.green.X = 0.3576; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_GREEN_Y + primaries.green.Y = TARGET_DISPLAY_PRIMARY_GREEN_Y; +#else + primaries.green.Y = 0.7152; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_GREEN_Z + primaries.green.Z = TARGET_DISPLAY_PRIMARY_GREEN_Z; +#else + primaries.green.Z = 0.1192; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_BLUE_X + primaries.blue.X = TARGET_DISPLAY_PRIMARY_BLUE_X; +#else + primaries.blue.X = 0.1805; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_BLUE_Y + primaries.blue.Y = TARGET_DISPLAY_PRIMARY_BLUE_Y; +#else + primaries.blue.Y = 0.0722; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_BLUE_Z + primaries.blue.Z = TARGET_DISPLAY_PRIMARY_BLUE_Z; +#else + primaries.blue.Z = 0.9506; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_WHITE_X + primaries.white.X = TARGET_DISPLAY_PRIMARY_WHITE_X; +#else + primaries.white.X = 0.9505; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_WHITE_Y + primaries.white.Y = TARGET_DISPLAY_PRIMARY_WHITE_Y; +#else + primaries.white.Y = 1.0000; +#endif + +#ifdef TARGET_DISPLAY_PRIMARY_WHITE_Z + primaries.white.Z = TARGET_DISPLAY_PRIMARY_WHITE_Z; +#else + primaries.white.Z = 1.0891; +#endif + + _hidl_cb(primaries); + return Void(); +} } // namespace implementation -} // namespace V1_1 +} // namespace V1_2 } // namespace configstore } // namespace hardware } // namespace android diff --git a/configstore/1.1/default/SurfaceFlingerConfigs.h b/configstore/1.2/default/SurfaceFlingerConfigs.h index 3714e81697..54a6e6211b 100644 --- a/configstore/1.1/default/SurfaceFlingerConfigs.h +++ b/configstore/1.2/default/SurfaceFlingerConfigs.h @@ -1,24 +1,39 @@ -#ifndef ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H -#define ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.1 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/configstore/1.1/ISurfaceFlingerConfigs.h> +#ifndef ANDROID_HARDWARE_CONFIGSTORE_V1_2_SURFACEFLINGERCONFIGS_H +#define ANDROID_HARDWARE_CONFIGSTORE_V1_2_SURFACEFLINGERCONFIGS_H + +#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> namespace android { namespace hardware { namespace configstore { -namespace V1_1 { +namespace V1_2 { namespace implementation { -using ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs; +using ::android::sp; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::sp; +using ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs; struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs { - // Methods from - // ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs follow. + // ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs implementation. Return<void> vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override; Return<void> vsyncSfEventPhaseOffsetNs(vsyncSfEventPhaseOffsetNs_cb _hidl_cb) override; Return<void> useContextPriority(useContextPriority_cb _hidl_cb) override; @@ -32,17 +47,19 @@ struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs { Return<void> maxFrameBufferAcquiredBuffers(maxFrameBufferAcquiredBuffers_cb _hidl_cb) override; Return<void> startGraphicsAllocatorService(startGraphicsAllocatorService_cb _hidl_cb) override; - // Methods from - // ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs follow. + // ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs follow implementation. Return<void> primaryDisplayOrientation(primaryDisplayOrientation_cb _hidl_cb) override; - // Methods from ::android::hidl::base::V1_0::IBase follow. + // ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs follow implementation. + Return<void> useColorManagement(useColorManagement_cb _hidl_cb) override; + Return<void> getCompositionPreference(getCompositionPreference_cb _hidl_cb) override; + Return<void> getDisplayNativePrimaries(getDisplayNativePrimaries_cb _hidl_cb) override; }; } // namespace implementation -} // namespace V1_1 +} // namespace V1_2 } // namespace configstore } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H +#endif // ANDROID_HARDWARE_CONFIGSTORE_V1_2_SURFACEFLINGERCONFIGS_H diff --git a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc b/configstore/1.2/default/android.hardware.configstore@1.2-service.rc index 105678acb2..d6c5d10a71 100644 --- a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc +++ b/configstore/1.2/default/android.hardware.configstore@1.2-service.rc @@ -1,4 +1,4 @@ -service vendor.configstore-hal /vendor/bin/hw/android.hardware.configstore@1.1-service +service vendor.configstore-hal /vendor/bin/hw/android.hardware.configstore@1.2-service class hal animation user system group system diff --git a/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy b/configstore/1.2/default/seccomp_policy/configstore-arm64.policy index 937fddd67b..937fddd67b 100644 --- a/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy +++ b/configstore/1.2/default/seccomp_policy/configstore-arm64.policy diff --git a/configstore/1.1/default/service.cpp b/configstore/1.2/default/service.cpp index 3b4e7745ee..65a42f5955 100644 --- a/configstore/1.1/default/service.cpp +++ b/configstore/1.2/default/service.cpp @@ -14,27 +14,27 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.configstore@1.1-service" +#define LOG_TAG "android.hardware.configstore@1.2-service" -#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> +#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h> #include <hidl/HidlTransportSupport.h> #include <hwminijail/HardwareMinijail.h> #include "SurfaceFlingerConfigs.h" +using android::OK; +using android::sp; +using android::status_t; using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; -using android::hardware::configstore::V1_1::ISurfaceFlingerConfigs; -using android::hardware::configstore::V1_1::implementation::SurfaceFlingerConfigs; using android::hardware::SetupMinijail; -using android::sp; -using android::status_t; -using android::OK; +using android::hardware::configstore::V1_2::ISurfaceFlingerConfigs; +using android::hardware::configstore::V1_2::implementation::SurfaceFlingerConfigs; int main() { configureRpcThreadpool(10, true); - SetupMinijail("/vendor/etc/seccomp_policy/configstore@1.1.policy"); + SetupMinijail("/vendor/etc/seccomp_policy/configstore.policy"); sp<ISurfaceFlingerConfigs> surfaceFlingerConfigs = new SurfaceFlingerConfigs; status_t status = surfaceFlingerConfigs->registerAsService(); diff --git a/configstore/1.2/default/surfaceflinger.mk b/configstore/1.2/default/surfaceflinger.mk new file mode 100644 index 0000000000..9a672564c1 --- /dev/null +++ b/configstore/1.2/default/surfaceflinger.mk @@ -0,0 +1,124 @@ + +LOCAL_SRC_FILES += SurfaceFlingerConfigs.cpp + +ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),) + LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS) +endif + +ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),) + LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS) +endif + +ifeq ($(TARGET_USE_CONTEXT_PRIORITY),true) + LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1 +endif + +ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY),true) + LOCAL_CFLAGS += -DHAS_WIDE_COLOR_DISPLAY +endif + +ifeq ($(TARGET_HAS_HDR_DISPLAY),true) + LOCAL_CFLAGS += -DHAS_HDR_DISPLAY +endif + +ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),) + LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS) +else + LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0 +endif + +ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true) + LOCAL_CFLAGS += -DFORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS +endif + +ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),) + LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=$(MAX_VIRTUAL_DISPLAY_DIMENSION) +endif + +ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true) + LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK +endif + +ifneq ($(USE_VR_FLINGER),) + LOCAL_CFLAGS += -DUSE_VR_FLINGER +endif + +ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),) + LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) +endif + +ifneq ($(SF_START_GRAPHICS_ALLOCATOR_SERVICE),) + LOCAL_CFLAGS += -DSTART_GRAPHICS_ALLOCATOR_SERVICE +endif + +ifneq ($(SF_PRIMARY_DISPLAY_ORIENTATION),) + LOCAL_CFLAGS += -DPRIMARY_DISPLAY_ORIENTATION=$(SF_PRIMARY_DISPLAY_ORIENTATION) +endif + +ifeq ($(TARGET_USE_COLOR_MANAGEMENT),true) + LOCAL_CFLAGS += -DUSE_COLOR_MANAGEMENT +endif + +ifneq ($(SF_DEFAULT_COMPOSITION_DATA_SPACE),) + LOCAL_CFLAGS += -DDEFAULT_COMPOSITION_DATA_SPACE=$(SF_DEFAULT_COMPOSITION_DATA_SPACE) +endif + +ifneq ($(SF_DEFAULT_COMPOSITION_PIXEL_FORMAT),) + LOCAL_CFLAGS += -DDEFAULT_COMPOSITION_PIXEL_FORMAT=$(SF_DEFAULT_COMPOSITION_PIXEL_FORMAT) +endif + +ifneq ($(SF_WCG_COMPOSITION_DATA_SPACE),) + LOCAL_CFLAGS += -DWCG_COMPOSITION_DATA_SPACE=$(SF_WCG_COMPOSITION_DATA_SPACE) +endif + +ifneq ($(SF_WCG_COMPOSITION_PIXEL_FORMAT),) + LOCAL_CFLAGS += -DWCG_COMPOSITION_PIXEL_FORMAT=$(SF_WCG_COMPOSITION_PIXEL_FORMAT) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_RED_X),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_RED_X=$(TARGET_DISPLAY_PRIMARY_RED_X) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_RED_Y),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_RED_Y=$(TARGET_DISPLAY_PRIMARY_RED_Y) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_RED_Z),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_RED_Z=$(TARGET_DISPLAY_PRIMARY_RED_Z) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_GREEN_X),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_GREEN_X=$(TARGET_DISPLAY_PRIMARY_GREEN_X) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_GREEN_Y),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_GREEN_Y=$(TARGET_DISPLAY_PRIMARY_GREEN_Y) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_GREEN_Z),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_GREEN_Z=$(TARGET_DISPLAY_PRIMARY_GREEN_Z) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_BLUE_X),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_BLUE_X=$(TARGET_DISPLAY_PRIMARY_BLUE_X) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_BLUE_Y),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_BLUE_Y=$(TARGET_DISPLAY_PRIMARY_BLUE_Y) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_BLUE_Z),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_BLUE_Z=$(TARGET_DISPLAY_PRIMARY_BLUE_Z) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_WHITE_X),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_WHITE_X=$(TARGET_DISPLAY_PRIMARY_WHITE_X) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_WHITE_Y),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_WHITE_Y=$(TARGET_DISPLAY_PRIMARY_WHITE_Y) +endif + +ifneq ($(TARGET_DISPLAY_PRIMARY_WHITE_Z),) + LOCAL_CFLAGS += -DTARGET_DISPLAY_PRIMARY_WHITE_Z=$(TARGET_DISPLAY_PRIMARY_WHITE_Z) +endif diff --git a/audio/common/2.0/default/HidlUtils.cpp b/configstore/1.2/types.hal index 9771b7bda2..5b2c9a60b3 100644 --- a/audio/common/2.0/default/HidlUtils.cpp +++ b/configstore/1.2/types.hal @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -13,9 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package android.hardware.configstore@1.2; -#include "HidlUtils.h" - -#define AUDIO_HAL_VERSION V2_0 -#include <common/all-versions/default/HidlUtils.impl.h> -#undef AUDIO_HAL_VERSION +struct CieXyz { + float X; + float Y; + float Z; +}; +struct DisplayPrimaries { + CieXyz red; + CieXyz green; + CieXyz blue; + CieXyz white; +}; diff --git a/configstore/1.2/vts/functional/Android.bp b/configstore/1.2/vts/functional/Android.bp new file mode 100644 index 0000000000..5f1eca6cdf --- /dev/null +++ b/configstore/1.2/vts/functional/Android.bp @@ -0,0 +1,27 @@ +// +// 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. +// + +cc_test { + name: "VtsHalConfigstoreV1_2TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalConfigstoreV1_2TargetTest.cpp"], + static_libs: [ + "android.hardware.configstore@1.0", + "android.hardware.configstore@1.1", + "android.hardware.configstore@1.2", + ], +} + diff --git a/configstore/1.2/vts/functional/OWNERS b/configstore/1.2/vts/functional/OWNERS new file mode 100644 index 0000000000..2b4fb8c70f --- /dev/null +++ b/configstore/1.2/vts/functional/OWNERS @@ -0,0 +1,7 @@ +# Graphics team +lpy@google.com +olv@google.com +stoza@google.com + +# VTS team +yim@google.com diff --git a/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp b/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp new file mode 100644 index 0000000000..d7f4dcf75f --- /dev/null +++ b/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp @@ -0,0 +1,174 @@ +/* + * 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. + */ + +#define LOG_TAG "ConfigstoreHidlHalTest" + +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> +#include <android-base/logging.h> +#include <android/hardware/configstore/1.0/types.h> +#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h> +#include <android/hardware/configstore/1.2/types.h> +#include <unistd.h> + +using ::android::sp; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::configstore::V1_0::OptionalBool; +using ::android::hardware::configstore::V1_0::OptionalInt64; +using ::android::hardware::configstore::V1_0::OptionalUInt64; +using ::android::hardware::configstore::V1_2::DisplayPrimaries; +using ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs; +using ::android::hardware::graphics::common::V1_2::Dataspace; +using ::android::hardware::graphics::common::V1_2::PixelFormat; + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) +#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) + +// Test environment for Configstore HIDL HAL. +class ConfigstoreHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static ConfigstoreHidlEnvironment* Instance() { + static ConfigstoreHidlEnvironment* instance = new ConfigstoreHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<ISurfaceFlingerConfigs>(); } +}; + +class ConfigstoreHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + sp<ISurfaceFlingerConfigs> sfConfigs; + + virtual void SetUp() override { + sfConfigs = ::testing::VtsHalHidlTargetTestBase::getService<ISurfaceFlingerConfigs>( + ConfigstoreHidlEnvironment::Instance()->getServiceName<ISurfaceFlingerConfigs>()); + ASSERT_NE(sfConfigs, nullptr); + } + + virtual void TearDown() override {} + + bool isSupportedWideColorGamut(Dataspace dataspace) { + Dataspace standard = static_cast<Dataspace>(dataspace & Dataspace::STANDARD_MASK); + return standard == Dataspace::STANDARD_DCI_P3 || standard == Dataspace::STANDARD_BT2020; + } +}; + +/** + * Make sure the constrains of hasWideColorDisplay, hasHDRDisplay + * and useColorManagement are enforced. + */ +TEST_F(ConfigstoreHidlTest, TestColorConstrainsWithColorManagement) { + bool hasWideColorDisplay; + bool hasHDRDisplay; + bool useColorManagement; + + Return<void> status = sfConfigs->hasWideColorDisplay( + [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; }); + EXPECT_OK(status); + + status = sfConfigs->hasHDRDisplay([&](OptionalBool arg) { hasHDRDisplay = arg.specified; }); + EXPECT_OK(status); + + status = sfConfigs->useColorManagement( + [&](OptionalBool arg) { useColorManagement = arg.specified; }); + EXPECT_OK(status); + + // When hasHDRDisplay returns true, hasWideColorDisplay must also return true. + if (hasHDRDisplay) { + ASSERT_TRUE(hasWideColorDisplay); + } + + // When hasWideColorDisplay returns true, useColorManagement + // must also return true. + if (hasWideColorDisplay) { + ASSERT_TRUE(useColorManagement); + } +} + +TEST_F(ConfigstoreHidlTest, TestGetCompositionPreference) { + bool hasWideColorDisplay; + + Return<void> status = sfConfigs->hasWideColorDisplay( + [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; }); + EXPECT_OK(status); + + Dataspace defaultDataspace, wcgDataspace; + + status = sfConfigs->getCompositionPreference( + [&](auto tmpDefaultDataspace, PixelFormat, auto tmpWcgDataspace, PixelFormat) { + defaultDataspace = tmpDefaultDataspace; + wcgDataspace = tmpWcgDataspace; + }); + EXPECT_OK(status); + + // Default data space and wide color gamut data space must not be UNKNOWN. + ASSERT_TRUE(defaultDataspace != Dataspace::UNKNOWN && wcgDataspace != Dataspace::UNKNOWN); + + // If hasWideColorDisplay returns true, the wide color gamut data space must be a valid wide + // color gamut. + if (hasWideColorDisplay) { + ASSERT_TRUE(isSupportedWideColorGamut(wcgDataspace)); + } +} + +TEST_F(ConfigstoreHidlTest, TestGetDisplayNativePrimaries) { + DisplayPrimaries primaries; + + Return<void> status = sfConfigs->getDisplayNativePrimaries( + [&](DisplayPrimaries tmpPrimaries) { + primaries.red = tmpPrimaries.red; + primaries.green = tmpPrimaries.green; + primaries.blue = tmpPrimaries.blue; + primaries.white = tmpPrimaries.white; + }); + EXPECT_OK(status); + + // Display primaries should be greater than or equal to zero. + // Or it returns defualt value if there is no definition. + // RED + EXPECT_GE(primaries.red.X, 0.0); + EXPECT_GE(primaries.red.Y, 0.0); + EXPECT_GE(primaries.red.Z, 0.0); + + // GREEN + EXPECT_GE(primaries.green.X, 0.0); + EXPECT_GE(primaries.green.Y, 0.0); + EXPECT_GE(primaries.green.Z, 0.0); + + + // BLUE + EXPECT_GE(primaries.blue.X, 0.0); + EXPECT_GE(primaries.blue.Y, 0.0); + EXPECT_GE(primaries.blue.Z, 0.0); + + + // WHITE + EXPECT_GE(primaries.white.X, 0.0); + EXPECT_GE(primaries.white.Y, 0.0); + EXPECT_GE(primaries.white.Z, 0.0); +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(ConfigstoreHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + ConfigstoreHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/configstore/utils/Android.bp b/configstore/utils/Android.bp index 178f245fd6..e0d4aa8192 100644 --- a/configstore/utils/Android.bp +++ b/configstore/utils/Android.bp @@ -30,12 +30,14 @@ cc_library_shared { shared_libs: [ "android.hardware.configstore@1.0", "android.hardware.configstore@1.1", + "android.hardware.configstore@1.2", "libbase", "libhidlbase" ], export_shared_lib_headers: [ "android.hardware.configstore@1.0", "android.hardware.configstore@1.1", + "android.hardware.configstore@1.2", "libbase", "libhidlbase" ], diff --git a/contexthub/1.0/default/OWNERS b/contexthub/1.0/default/OWNERS index 49a3204ac7..5373073cb8 100644 --- a/contexthub/1.0/default/OWNERS +++ b/contexthub/1.0/default/OWNERS @@ -1,2 +1,4 @@ -ashutoshj@google.com +aarossig@google.com +arthuri@google.com bduddie@google.com +bstack@google.com diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS index ad036b4215..ee01441e4f 100644 --- a/contexthub/1.0/vts/functional/OWNERS +++ b/contexthub/1.0/vts/functional/OWNERS @@ -1,6 +1,8 @@ #Context Hub team -ashutoshj@google.com +aarossig@google.com +arthuri@google.com bduddie@google.com +bstack@google.com #VTS team yim@google.com diff --git a/current.txt b/current.txt index 5dba85bc3e..3b873068d0 100644 --- a/current.txt +++ b/current.txt @@ -385,18 +385,23 @@ cd4330c3196bda1d642a32abfe23a7d64ebfbda721940643af6867af3b3f0aa9 android.hardwar 10ff2fae516346b86121368ce5790d5accdfcb73983246b813f3d488b66db45a android.hardware.wifi.supplicant@1.1::ISupplicantStaNetwork # ABI preserving changes to HALs during Android Q -f72d23278af99a2f6a9c1d40352b67dbf1f582282f799f88f7235dc7c13892b5 android.hardware.camera.device@3.2::ICameraDeviceSession +2a55e224aa9bc62c0387cd85ad3c97e33f0c33a4e1489cbae86b2523e6f9df35 android.hardware.camera.device@3.2::ICameraDevice +8caf9104dc6885852c0b117d853dd93f6d4b61a0a365138295eb8bcd41b36423 android.hardware.camera.device@3.2::ICameraDeviceSession +684702a60deef03a1e8093961dc0a18c555c857ad5a77ba7340b0635ae01eb70 android.hardware.camera.device@3.4::ICameraDeviceSession f8a19622cb0cc890913b1ef3e32b675ffb26089a09e02fef4056ebad324d2b5d android.hardware.camera.device@3.4::types +291638a1b6d4e63283e9e722ab5049d9351717ffa2b66162124f84d1aa7c2835 android.hardware.camera.metadata@3.2::types +8a075cf3a17fe99c6d23415a3e9a65612f1fee73ee052a3a8a0ca5b8877395a4 android.hardware.camera.metadata@3.3::types da33234403ff5d60f3473711917b9948e6484a4260b5247acdafb111193a9de2 android.hardware.configstore@1.0::ISurfaceFlingerConfigs 21165b8e30c4b2d52980e4728f661420adc16e38bbe73476c06b2085be908f4c android.hardware.gnss@1.0::IGnssCallback d702fb01dc2a0733aa820b7eb65435ee3334f75632ef880bafd2fb8803a20a58 android.hardware.gnss@1.0::IGnssMeasurementCallback b7ecf29927055ec422ec44bf776223f07d79ad9f92ccf9becf167e62c2607e7a android.hardware.keymaster@4.0::IKeymasterDevice 574e8f1499436fb4075894dcae0b36682427956ecb114f17f1fe22d116a83c6b android.hardware.neuralnetworks@1.0::IPreparedModel -1fb32361286b938d48a55c2539c846732afce0b99fe08590f556643125bc13d3 android.hardware.neuralnetworks@1.0::types +417ab60fe1ef786778047e4486f3d868ebce570d91addd8fe4251515213072de android.hardware.neuralnetworks@1.0::types e22e8135d061d0e9c4c1a70c25c19fdba10f4d3cda9795ef25b6392fc520317c android.hardware.neuralnetworks@1.1::types 1d4a5776614c08b5d794a5ec5ab04697260cbd4b3441d5935cd53ee71d19da02 android.hardware.radio@1.0::IRadioResponse 271187e261b30c01a33011aea257c07a2d2f05b72943ebee89e973e997849973 android.hardware.radio@1.0::types 1d19720d4fd38b1095f0f555a4bd92b3b12c9b1d0f560b0e9a474cd6dcc20db6 android.hardware.radio@1.2::IRadio e78cf871f9fd1c072874e481e06e18e2681763cf2aa38c1fd777d53bab4eb69b android.hardware.sensors@1.0::types +3d01e29e8129186f7567c4f9c8bee7480a0768e587b1be9b28adb0a6cbec6bf2 android.hardware.tv.cec@1.0::types 1722ad002317b1fae1400de709e90f442d94ef22864e05f7a12af48c32e8edc8 android.hardware.usb@1.1::types 29c8da7a13c40d488f569c812441d5754ee45bdcdb8ce6564f524b708d10a057 android.hardware.vibrator@1.1::types diff --git a/drm/1.0/default/Android.mk b/drm/1.0/default/Android.mk index 99773be385..d66f377b5b 100644 --- a/drm/1.0/default/Android.mk +++ b/drm/1.0/default/Android.mk @@ -19,39 +19,23 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) + +include $(LOCAL_PATH)/common_default_service.mk LOCAL_MODULE := android.hardware.drm@1.0-service LOCAL_INIT_RC := android.hardware.drm@1.0-service.rc -LOCAL_PROPRIETARY_MODULE := true -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_SRC_FILES := \ - service.cpp \ +LOCAL_SRC_FILES := service.cpp -LOCAL_SHARED_LIBRARIES := \ - android.hardware.drm@1.0 \ - android.hidl.memory@1.0 \ - libhidlbase \ - libhidltransport \ - libhardware \ - liblog \ - libutils \ - libbinder \ - -LOCAL_STATIC_LIBRARIES := \ - android.hardware.drm@1.0-helper \ +include $(BUILD_EXECUTABLE) -LOCAL_C_INCLUDES := \ - hardware/interfaces/drm +############# Build legacy drm lazy service ############ -LOCAL_HEADER_LIBRARIES := \ - media_plugin_headers +include $(CLEAR_VARS) -# TODO(b/18948909) Some legacy DRM plugins only support 32-bit. They need to be -# migrated to 64-bit. Once all of a device's legacy DRM plugins support 64-bit, -# that device can turn on TARGET_ENABLE_MEDIADRM_64 to build this service as -# 64-bit. -ifneq ($(TARGET_ENABLE_MEDIADRM_64), true) -LOCAL_32_BIT_ONLY := true -endif +include $(LOCAL_PATH)/common_default_service.mk +LOCAL_MODULE := android.hardware.drm@1.0-service-lazy +LOCAL_OVERRIDES_MODULES := android.hardware.drm@1.0-service +LOCAL_INIT_RC := android.hardware.drm@1.0-service-lazy.rc +LOCAL_SRC_FILES := serviceLazy.cpp include $(BUILD_EXECUTABLE) diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp index f9c868db8b..666653b261 100644 --- a/drm/1.0/default/CryptoPlugin.cpp +++ b/drm/1.0/default/CryptoPlugin.cpp @@ -52,7 +52,6 @@ namespace implementation { Return<void> CryptoPlugin::setSharedBufferBase(const hidl_memory& base, uint32_t bufferId) { sp<IMemory> hidlMemory = mapMemory(base); - ALOGE_IF(hidlMemory == nullptr, "mapMemory returns nullptr"); // allow mapMemory to return nullptr mSharedBufferMap[bufferId] = hidlMemory; diff --git a/drm/1.0/default/android.hardware.drm@1.0-service-lazy.rc b/drm/1.0/default/android.hardware.drm@1.0-service-lazy.rc new file mode 100644 index 0000000000..4b32f7f1f3 --- /dev/null +++ b/drm/1.0/default/android.hardware.drm@1.0-service-lazy.rc @@ -0,0 +1,10 @@ +service vendor.drm-hal-1-0 /vendor/bin/hw/android.hardware.drm@1.0-service-lazy + interface android.hardware.drm@1.0::ICryptoFactory default + interface android.hardware.drm@1.0::IDrmFactory default + oneshot + disabled + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/drm/1.0/default/android.hardware.drm@1.0-service.rc b/drm/1.0/default/android.hardware.drm@1.0-service.rc index a3457b5234..790ededbe7 100644 --- a/drm/1.0/default/android.hardware.drm@1.0-service.rc +++ b/drm/1.0/default/android.hardware.drm@1.0-service.rc @@ -1,4 +1,6 @@ service vendor.drm-hal-1-0 /vendor/bin/hw/android.hardware.drm@1.0-service + interface android.hardware.drm@1.0::ICryptoFactory default + interface android.hardware.drm@1.0::IDrmFactory default class hal user media group mediadrm drmrpc diff --git a/drm/1.0/default/common_default_service.mk b/drm/1.0/default/common_default_service.mk new file mode 100644 index 0000000000..28db567a9f --- /dev/null +++ b/drm/1.0/default/common_default_service.mk @@ -0,0 +1,45 @@ +# +# 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 $(CLEAR_VARS) +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.drm@1.0 \ + android.hidl.memory@1.0 \ + libhidlbase \ + libhidltransport \ + libhardware \ + liblog \ + libutils \ + libbinder \ + +LOCAL_STATIC_LIBRARIES := \ + android.hardware.drm@1.0-helper \ + +LOCAL_C_INCLUDES := \ + hardware/interfaces/drm + +LOCAL_HEADER_LIBRARIES := \ + media_plugin_headers + +# TODO(b/18948909) Some legacy DRM plugins only support 32-bit. They need to be +# migrated to 64-bit. Once all of a device's legacy DRM plugins support 64-bit, +# that device can turn on TARGET_ENABLE_MEDIADRM_64 to build this service as +# 64-bit. +ifneq ($(TARGET_ENABLE_MEDIADRM_64), true) +LOCAL_32_BIT_ONLY := true +endif diff --git a/drm/1.0/default/service.cpp b/drm/1.0/default/service.cpp index 1a44ce225e..98d2c3b545 100644 --- a/drm/1.0/default/service.cpp +++ b/drm/1.0/default/service.cpp @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "android.hardware.drm@1.0-service" #include <1.0/default/CryptoFactory.h> #include <1.0/default/DrmFactory.h> @@ -31,15 +30,8 @@ using android::hardware::drm::V1_0::ICryptoFactory; using android::hardware::drm::V1_0::IDrmFactory; int main() { - ALOGD("android.hardware.drm@1.0-service starting..."); - - // The DRM HAL may communicate to other vendor components via - // /dev/vndbinder - android::ProcessState::initWithDriver("/dev/vndbinder"); - configureRpcThreadpool(8, true /* callerWillJoin */); - android::status_t status = - registerPassthroughServiceImplementation<IDrmFactory>(); + android::status_t status = registerPassthroughServiceImplementation<IDrmFactory>(); LOG_ALWAYS_FATAL_IF( status != android::OK, "Error while registering drm service: %d", status); diff --git a/drm/1.0/default/serviceLazy.cpp b/drm/1.0/default/serviceLazy.cpp new file mode 100644 index 0000000000..e5068b5699 --- /dev/null +++ b/drm/1.0/default/serviceLazy.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 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 <1.0/default/CryptoFactory.h> +#include <1.0/default/DrmFactory.h> + +#include <hidl/HidlTransportSupport.h> +#include <hidl/LegacySupport.h> + +#include <binder/ProcessState.h> + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::registerLazyPassthroughServiceImplementation; + +using android::hardware::drm::V1_0::ICryptoFactory; +using android::hardware::drm::V1_0::IDrmFactory; + +int main() { + configureRpcThreadpool(8, true /* callerWillJoin */); + android::status_t status = registerLazyPassthroughServiceImplementation<IDrmFactory>(); + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering drm service: %d", status); + status = registerLazyPassthroughServiceImplementation<ICryptoFactory>(); + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering crypto service: %d", + status); + joinRpcThreadpool(); +} diff --git a/drm/1.2/Android.bp b/drm/1.2/Android.bp new file mode 100644 index 0000000000..fa2962ac75 --- /dev/null +++ b/drm/1.2/Android.bp @@ -0,0 +1,28 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.drm@1.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ICryptoFactory.hal", + "ICryptoPlugin.hal", + "IDrmFactory.hal", + "IDrmPlugin.hal", + "IDrmPluginListener.hal", + ], + interfaces: [ + "android.hardware.drm@1.0", + "android.hardware.drm@1.1", + "android.hidl.base@1.0", + ], + types: [ + "OfflineLicenseState", + "Status", + ], + gen_java: false, +} + diff --git a/audio/effect/4.0/default/AcousticEchoCancelerEffect.h b/drm/1.2/ICryptoFactory.hal index 0ac0a1e0df..c4a9b4b31e 100644 --- a/audio/effect/4.0/default/AcousticEchoCancelerEffect.h +++ b/drm/1.2/ICryptoFactory.hal @@ -13,16 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package android.hardware.drm@1.2; -#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_ACOUSTICECHOCANCELEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_ACOUSTICECHOCANCELEREFFECT_H +import @1.1::ICryptoFactory; -#include <android/hardware/audio/effect/4.0/IAcousticEchoCancelerEffect.h> - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/AcousticEchoCancelerEffect.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_ACOUSTICECHOCANCELEREFFECT_H +/** + * ICryptoFactory is the main entry point for interacting with a vendor's + * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions + * which are used by a codec to decrypt protected video content. + * + * The 1.2 factory must always create 1.2 ICryptoPlugin interfaces, which are + * returned via the 1.0 createPlugin method. + * + * To use 1.2 features the caller must cast the returned interface to a + * 1.2 HAL, using V1_2::IDrmPlugin::castFrom(). + * + * The ICryptoFactory hal is required because all top-level interfaces + * have to be updated in a minor uprev. + */ +interface ICryptoFactory extends @1.1::ICryptoFactory { +}; diff --git a/drm/1.2/ICryptoPlugin.hal b/drm/1.2/ICryptoPlugin.hal new file mode 100644 index 0000000000..07006768ce --- /dev/null +++ b/drm/1.2/ICryptoPlugin.hal @@ -0,0 +1,84 @@ +/** + * 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. + */ +package android.hardware.drm@1.2; + +import @1.0::DestinationBuffer; +import @1.0::ICryptoPlugin; +import @1.0::Mode; +import @1.0::Pattern; +import @1.0::SessionId; +import @1.0::SharedBuffer; +import @1.0::SubSample; + +/** + * ICryptoPlugin is the HAL for vendor-provided crypto plugins. + * It allows crypto sessions to be opened and operated on, to + * load crypto keys for a codec to decrypt protected video content. + */ +interface ICryptoPlugin extends @1.0::ICryptoPlugin { + + /** + * Decrypt an array of subsamples from the source memory buffer to the + * destination memory buffer. + * + * decrypt_1_2() only differs from decrypt() in that additional status + * codes must be returned. + * + * @param secure a flag to indicate if a secure decoder is being used. This + * enables the plugin to configure buffer modes to work consistently with + * a secure decoder. + * @param the keyId for the key that is used to do the the decryption. The + * keyId refers to a key in the associated MediaDrm instance. + * @param iv the initialization vector to use + * @param mode the crypto mode to use + * @param pattern the crypto pattern to use + * @param subSamples a vector of subsamples indicating the number + * of clear and encrypted bytes to process. This allows the decrypt + * call to operate on a range of subsamples in a single call + * @param source the input buffer for the decryption + * @param offset the offset of the first byte of encrypted data from + * the base of the source buffer + * @param destination the output buffer for the decryption + * @return status the status of the call. The status must be OK or one + * of the following errors: + * ERROR_DRM_NO_LICENSE if no license keys have been loaded + * ERROR_DRM_LICENSE_EXPIRED if the license keys have expired + * ERROR_DRM_RESOURCE_BUSY if the resources required to perform + * the decryption are not available + * ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION if required output + * protections are not active + * ERROR_DRM_INSUFFICIENT_SECURITY if the security level of the + * device is not sufficient to meet the requirements in + * the license policy + * ERROR_DRM_FRAME_TOO_LARGE if the frame being decrypted into + * the secure output buffer exceeds the size of the buffer + * ERROR_DRM_SESSION_NOT_OPENED if the decrypt session is not + * opened + * ERROR_DRM_DECRYPT if the decrypt operation fails + * ERROR_DRM_INVALID_STATE if the device is in a state where it + * is not able to perform decryption + * ERROR_DRM_CANNOT_HANDLE in other failure cases. + * + * @return bytesWritten the number of bytes output from the decryption + * @return detailedError if the error is a vendor-specific error, the + * vendor's crypto HAL may provide a detailed error string to help + * describe the error. + */ + decrypt_1_2(bool secure, uint8_t[16] keyId, uint8_t[16] iv, Mode mode, + Pattern pattern, vec<SubSample> subSamples, + SharedBuffer source, uint64_t offset, DestinationBuffer destination) + generates(Status status, uint32_t bytesWritten, string detailedError); +}; diff --git a/drm/1.2/IDrmFactory.hal b/drm/1.2/IDrmFactory.hal new file mode 100644 index 0000000000..682889c22a --- /dev/null +++ b/drm/1.2/IDrmFactory.hal @@ -0,0 +1,51 @@ +/* + * 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. + */ +package android.hardware.drm@1.2; + +import @1.1::IDrmFactory; +import @1.1::IDrmPlugin; +import @1.1::SecurityLevel; + +/** + * IDrmFactory is the main entry point for interacting with a vendor's + * drm HAL to create drm plugin instances. A drm plugin instance + * creates drm sessions which are used to obtain keys for a crypto + * session so it can decrypt protected video content. + * + * The 1.2 factory must always create 1.2 IDrmPlugin interfaces, which are + * returned via the 1.0 createPlugin method. + * + * To use 1.2 features the caller must cast the returned interface to a + * 1.2 HAL, using V1_2::IDrmPlugin::castFrom(). + * + * The IDrmFactory hal is required because all top-level interfaces + * have to be updated in a minor uprev. + */ + +interface IDrmFactory extends @1.1::IDrmFactory { + /** + * Determine if a specific security level is supported by the device. + * This method only differs from @1.0 isCryptoSchemeSupported + * by the addition of a security level. + * + * @param uuid identifies the crypto scheme in question + * @param mimeType identifies the mime type in question + * @param securityLevel specifies the security level required + * @return isSupported must be true only if the scheme is supported + */ + isCryptoSchemeSupported_1_2(uint8_t[16] uuid, string mimeType, + @1.1::SecurityLevel securityLevel) generates(bool isSupported); +}; diff --git a/drm/1.2/IDrmPlugin.hal b/drm/1.2/IDrmPlugin.hal new file mode 100644 index 0000000000..3c2181573c --- /dev/null +++ b/drm/1.2/IDrmPlugin.hal @@ -0,0 +1,229 @@ +/** + * 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. + */ +package android.hardware.drm@1.2; + +import @1.0::KeyedVector; +import @1.0::KeyType; +import @1.0::SessionId; +import @1.0::Status; +import @1.1::IDrmPlugin; +import @1.1::KeyRequestType; +import @1.2::IDrmPluginListener; + +/** + * IDrmPlugin is used to interact with a specific drm plugin that was + * created by IDrm::createPlugin. A drm plugin provides methods for + * obtaining drm keys to be used by a codec to decrypt protected video + * content. + */ +interface IDrmPlugin extends @1.1::IDrmPlugin { + + /** + * The keys in an offline license allow protected content to be + * played even if the device is not connected to a network. + * Offline licenses are stored on the device after a key + * request/response exchange when the key request KeyType is + * OFFLINE. Normally each app is responsible for keeping track of + * the KeySetIds it has created. In some situations however, it + * will be necessary to request the list of stored offline license + * KeySetIds. If an app loses the KeySetId for any stored licenses + * that it created, for example, it must be able to recover the + * stored KeySetIds so those licenses will be removed when they + * expire or when the app is uninstalled. + * <p> + * This method returns a list of the KeySetIds for all offline + * licenses. The offline license KeySetId allows an app to query + * the status of an offline license or remove it. + * + * @return status the status of the call. Must be OK or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the + * KeySetIds can't be returned. + * @return a list of offline license keySetIds. If there are no offline + * licenses, the list must be empty and OK must be returned as the + * status. + */ + getOfflineLicenseKeySetIds() generates (@1.0::Status status, + vec<KeySetId> keySetIds); + + /** + * Normally offline licenses are released using a key + * request/response exchange using getKeyRequest where the KeyType + * is RELEASE, followed by provideKeyResponse. This allows the + * server to cryptographically confirm that the license has been + * removed and then adjust the count of offline licenses allocated + * to the device. + * <p> + * In some exceptional situations it will be necessary to directly + * remove offline licenses without notifying the server, which is + * performed by this method. + * + * @param keySetId the id of the offline license to remove + * @return status the status of the call. Must be one of OK on + * success, BAD_VALUE if the license is not found or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the + * KeySetIds can't be returned. + */ + removeOfflineLicense(KeySetId keySetId) generates (@1.0::Status status); + + /** + * Request the state of an offline license. An offline license must + * be usable or inactive. The keys in a usable offline license are + * available for decryption. When the offline license state is + * inactive, the keys have been marked for release using + * getKeyRequest with KeyType RELEASE but the key response has not + * been received. The keys in an inactive offline license are not + * usable for decryption. + * + * @param keySetId the id of the offline license + * @return status the status of the call. Must be one of OK on + * success, BAD_VALUE if the license is not found or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the + * offline license state can't be queried. + * @return the offline license state, one of USABLE or INACTIVE. + * If the return status is not OK then state must be set to + * UNKNOWN. + */ + getOfflineLicenseState(KeySetId keySetId) generates ( + @1.0::Status status, OfflineLicenseState state); + + /** + * A key request/response exchange occurs between the app and a License + * Server to obtain the keys required to decrypt the content. + * getKeyRequest_1_2() is used to obtain an opaque key request blob that is + * delivered to the license server. + * + * getKeyRequest_1_2() only differs from getKeyRequest_1_1() in that + * additional status codes must be returned. + * + * @param scope either a sessionId or a keySetId, depending on the + * specified keyType. When the keyType is OFFLINE or STREAMING, scope + * must be set to the sessionId the keys will be provided to. When the + * keyType is RELEASE, scope must be set to the keySetId of the keys + * being released. + * @param initData container-specific data, its meaning is interpreted + * based on the mime type provided in the mimeType parameter. It could + * contain, for example, the content ID, key ID or other data obtained + * from the content metadata that is required to generate the key + * request. initData must be empty when keyType is RELEASE. + * @param mimeType identifies the mime type of the content + * @param keyType specifies if the keys are to be used for streaming, + * offline or a release + * @param optionalParameters included in the key request message to + * allow a client application to provide additional message parameters + * to the server. + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is + * not opened, ERROR_DRM_NOT_PROVISIONED if the device requires + * provisioning before it is able to generate a key request, + * ERROR_DRM_RESOURCE_CONTENTION if client applications using the hal + * are temporarily exceeding the available crypto resources such that a + * retry of the operation is likely to succeed, ERROR_DRM_CANNOT_HANDLE + * if getKeyRequest is not supported at the time of the call, BAD_VALUE + * if any parameters are invalid or ERROR_DRM_INVALID_STATE if the HAL + * is in a state where a key request cannot be generated. + * @return request if successful, the opaque key request blob is returned + * @return requestType indicates type information about the returned + * request. The type must be one of INITIAL, RENEWAL, RELEASE, NONE or + * UPDATE. An INITIAL request is the first key request for a + * license. RENEWAL is a subsequent key request used to refresh the + * keys in a license. RELEASE corresponds to a keyType of RELEASE, + * which indicates keys are being released. NONE indicates that no + * request is needed because the keys are already loaded. UPDATE + * indicates that the keys need to be refetched after the initial + * license request. + * @return defaultUrl the URL that the request may be sent to, if + * provided by the drm HAL. The app can choose to override this URL. + */ + getKeyRequest_1_2(vec<uint8_t> scope, vec<uint8_t> initData, + string mimeType, KeyType keyType, KeyedVector optionalParameters) + generates (Status status, vec<uint8_t> request, + KeyRequestType requestType, string defaultUrl); + + /** + * A provision request/response exchange occurs between the app and a + * provisioning server to retrieve a device certificate. getProvisionRequest + * is used to obtain an opaque provisioning request blob that is delivered + * to the provisioning server. + * + * getProvisionRequest_1_2() only differs from getProvisionRequest_1_0() in + * that additional status codes must be returned. + * + * @param certificateType the type of certificate requested, e.g. "X.509" + * @param certificateAuthority identifies the certificate authority. A + * certificate authority (CA) is an entity which issues digital + * certificates for use by other parties. It is an example of a trusted + * third party. + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_RESOURCE_CONTENTION if client + * applications using the hal are temporarily exceeding the available + * crypto resources such that a retry of the operation is likely to + * succeed, ERROR_DRM_CANNOT_HANDLE if the drm scheme does not require + * provisioning or ERROR_DRM_INVALID_STATE if the HAL is in a state + * where the provision request cannot be generated. + * @return request if successful the opaque certificate request blob + * is returned + * @return defaultUrl URL that the provisioning request may be + * sent to, if known by the HAL implementation. An app can choose to + * override this URL. If the HAL implementation does not provide a + * defaultUrl, the returned string must be empty. + */ + getProvisionRequest_1_2(string certificateType, string certificateAuthority) + generates (Status status, vec<uint8_t> request, string defaultUrl); + + /** + * Return the currently negotiated and max supported HDCP levels. + * + * This method only differs from @1.1 version by the addition of + * support for HDCP 2.3. + * + * The current level is based on the display(s) the device is connected to. + * If multiple HDCP-capable displays are simultaneously connected to + * separate interfaces, this method returns the lowest negotiated HDCP level + * of all interfaces. + * + * The maximum HDCP level is the highest level that can potentially be + * negotiated. It is a constant for any device, i.e. it does not depend on + * downstream receiving devices that could be connected. For example, if + * the device has HDCP 1.x keys and is capable of negotiating HDCP 1.x, but + * does not have HDCP 2.x keys, then the maximum HDCP capability would be + * reported as 1.x. If multiple HDCP-capable interfaces are present, it + * indicates the highest of the maximum HDCP levels of all interfaces. + * + * This method should only be used for informational purposes, not for + * enforcing compliance with HDCP requirements. Trusted enforcement of HDCP + * policies must be handled by the DRM system. + * + * @return status the status of the call. The status must be OK or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the HDCP + * level cannot be queried. + * @return connectedLevel the lowest HDCP level for any connected + * displays + * @return maxLevel the highest HDCP level that can be supported + * by the device + */ + getHdcpLevels_1_2() generates (Status status, HdcpLevel connectedLevel, + HdcpLevel maxLevel); + + /** + * Send a session lost state event to the listener. This event + * indicates that a session's state has become invalid because the + * device crypto hardware is incapable of retaining crypto session + * state across suspend and resume cycles. + * + * @param sessionId identifies the session the event originated from + */ + sendSessionLostState(SessionId sessionId); +}; diff --git a/drm/1.2/IDrmPluginListener.hal b/drm/1.2/IDrmPluginListener.hal new file mode 100644 index 0000000000..a6bd6c9ad4 --- /dev/null +++ b/drm/1.2/IDrmPluginListener.hal @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package android.hardware.drm@1.2; + +import @1.0::IDrmPluginListener; +import @1.0::SessionId; + +/** + * IDrmPluginListener is a listener interface for Drm events sent from an + * IDrmPlugin instance. + */ +interface IDrmPluginListener extends @1.0::IDrmPluginListener { + /** + * Some device crypto hardware is incapable of retaining crypto + * session state across suspend and resume cycles. A + * SessionLostState event must be signaled when a session has + * become invalid for this reason. This event must not be used to + * indicate a failure in the crypto system. Closing the session + * and opening a new one must allow the application to resume + * normal use of the drm hal module. + * + * @param sessionId identifies the session that has been invalidated + */ + oneway sendSessionLostState(SessionId sessionId); +}; diff --git a/drm/1.2/types.hal b/drm/1.2/types.hal new file mode 100644 index 0000000000..28c8e67b79 --- /dev/null +++ b/drm/1.2/types.hal @@ -0,0 +1,95 @@ +/** + * 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. + */ + +package android.hardware.drm@1.2; + +import @1.0::Status; +import @1.1::HdcpLevel; + +enum OfflineLicenseState : uint32_t { + /** + * Offline license state is unknown + */ + UNKNOWN, + + /** + * Offline license state is usable, the keys are usable for decryption. + */ + USABLE, + + /** + * Offline license state is inactive, the keys have been marked for + * release using {@link #getKeyRequest} with KEY_TYPE_RELEASE but the + * key response has not been received. + */ + INACTIVE +}; + +enum Status : @1.0::Status { + /** + * The drm HAL module must return ERROR_DRM_INSUFFICIENT_SECURITY + * from the crypto plugin decrypt method when the security level + * of the device is not sufficient to meet the requirements in the + * license policy. + */ + ERROR_DRM_INSUFFICIENT_SECURITY, + + /** + * The drm HAL module must return ERROR_FRAME_TOO_LARGE from the + * decrypt method when the frame being decrypted into the secure + * output buffer exceeds the size of the buffer. + */ + ERROR_DRM_FRAME_TOO_LARGE, + + /** + * This error must be returned from any session method when an + * attempt is made to use the session after the crypto hardware + * state has been invalidated. Some devices are not able to + * retain crypto session state across device suspend/resume which + * results in invalid session state. + */ + ERROR_DRM_SESSION_LOST_STATE, + + /** + * The drm HAL module must return this error if client + * applications using the hal are temporarily exceeding the + * capacity of available crypto resources such that a retry of + * the operation is likely to succeed. + */ + ERROR_DRM_RESOURCE_CONTENTION, +}; + +/** + * HDCP specifications are defined by Digital Content Protection LLC (DCP). + * "HDCP Specification Rev. 2.3 Interface Independent Adaptation" + * "HDCP 2.3 on HDMI Specification" + */ +enum HdcpLevel : @1.1::HdcpLevel { + /** + * HDCP version 2.3 Type 1. + */ + HDCP_V2_3 +}; + + +/** + * KeySetId is an identifier that references a set of keys in an + * offline license. The keySetId is created by the HAL implementation + * and returned from provideKeyResponse and getOfflineLicenseIds. The + * framework passes KeySetId back to the HAL when referring to the key + * set in methods that take a KeySetId as an input parameter. + */ +typedef vec<uint8_t> KeySetId; diff --git a/gnss/2.0/Android.bp b/gnss/2.0/Android.bp new file mode 100644 index 0000000000..9b04be0053 --- /dev/null +++ b/gnss/2.0/Android.bp @@ -0,0 +1,32 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.gnss@2.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IAGnss.hal", + "IAGnssCallback.hal", + "IAGnssRil.hal", + "IGnss.hal", + "IGnssCallback.hal", + "IGnssConfiguration.hal", + "IGnssMeasurement.hal", + "IGnssMeasurementCallback.hal", + ], + interfaces: [ + "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.visibility_control@1.0", + "android.hardware.gnss@1.0", + "android.hardware.gnss@1.1", + "android.hidl.base@1.0", + ], + types: [ + ], + gen_java: true, + gen_java_constants: true, +} + diff --git a/gnss/2.0/IAGnss.hal b/gnss/2.0/IAGnss.hal new file mode 100644 index 0000000000..d4e7d2fecb --- /dev/null +++ b/gnss/2.0/IAGnss.hal @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.0; + +import IAGnssCallback; + +/** + * Extended interface for Assisted GNSS support. + */ +interface IAGnss { + enum ApnIpType : uint8_t { + INVALID = 0, + IPV4 = 1, + IPV6 = 2, + IPV4V6 = 3 + }; + + /** + * Opens the AGNSS interface and provides the callback routines to the + * implementation of this interface. + * + * @param callback Handle to the AGNSS status callback interface. + */ + setCallback(IAGnssCallback callback); + + /** + * Notifies that the AGNSS data connection has been closed. + * + * @return success True if the operation is successful. + */ + dataConnClosed() generates (bool success); + + /** + * Notifies that a data connection is not available for AGNSS. + * + * @return success True if the operation is successful. + */ + dataConnFailed() generates (bool success); + + /** + * Sets the hostname and port for the AGNSS server. + * + * @param type Specifies if SUPL or C2K. + * @param hostname Hostname of the AGNSS server. + * @param port Port number associated with the server. + * + * @return success True if the operation is successful. + */ + setServer(AGnssType type, string hostname, int32_t port) + generates (bool success); + + /** + * Notifies GNSS that a data connection is available and sets the network handle, + * name of the APN, and its IP type to be used for SUPL connections. + * + * The HAL implementation must use the network handle to set the network for the + * SUPL connection sockets using the android_setsocknetwork function. This will ensure + * that there is a network path to the SUPL server. The network handle can also be used + * to get the IP address of SUPL FQDN using the android_getaddrinfofornetwork() function. + * + * @param networkHandle Handle representing the network for use with the NDK API. + * @param apn Access Point Name (follows regular APN naming convention). + * @param apnIpType Specifies IP type of APN. + * + * @return success True if the operation is successful. + */ + dataConnOpen(net_handle_t networkHandle, string apn, ApnIpType apnIpType) + generates (bool success); +};
\ No newline at end of file diff --git a/gnss/2.0/IAGnssCallback.hal b/gnss/2.0/IAGnssCallback.hal new file mode 100644 index 0000000000..896be1802f --- /dev/null +++ b/gnss/2.0/IAGnssCallback.hal @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.0; + +/** Callback structure for the AGNSS interface. */ +interface IAGnssCallback { + /** AGNSS service type **/ + enum AGnssType : uint8_t { + SUPL = 1, + C2K = 2, + SUPL_EIMS = 3, + SUPL_IMS = 4, + }; + + enum AGnssStatusValue : uint8_t { + /** GNSS requests data connection for AGNSS. */ + REQUEST_AGNSS_DATA_CONN = 1, + /** GNSS releases the AGNSS data connection. */ + RELEASE_AGNSS_DATA_CONN = 2, + /** AGNSS data connection initiated */ + AGNSS_DATA_CONNECTED = 3, + /** AGNSS data connection completed */ + AGNSS_DATA_CONN_DONE = 4, + /** AGNSS data connection failed */ + AGNSS_DATA_CONN_FAILED = 5 + }; + + /** + * Callback with AGNSS status information. + * + * The GNSS HAL implementation must use this method to request the framework to setup + * network connection for the specified AGNSS service and to update the connection + * status so that the framework can release the resources. + * + * @param type Type of AGNSS service. + * @parama status Status of the data connection. + */ + agnssStatusCb(AGnssType type, AGnssStatusValue status); +};
\ No newline at end of file diff --git a/gnss/2.0/IAGnssRil.hal b/gnss/2.0/IAGnssRil.hal new file mode 100644 index 0000000000..00a2e79b0f --- /dev/null +++ b/gnss/2.0/IAGnssRil.hal @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.0; + +import @1.0::IAGnssRil; + +/** + * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface + * Layer interface allows the GNSS chipset to request radio interface layer + * information from Android platform. Examples of such information are reference + * location, unique subscriber ID, phone number string and network availability changes. + */ +interface IAGnssRil extends @1.0::IAGnssRil { + /** Flags to indicate capabilities of the network */ + enum NetworkCapability : uint16_t { + /** Network is not metered. */ + NOT_METERED = 1 << 0, + /** Network is not roaming. */ + NOT_ROAMING = 1 << 1 + }; + + /** Represents network connection status and capabilities. */ + struct NetworkAttributes { + /** Network handle of the network for use with the NDK API. */ + net_handle_t networkHandle; + + /** + * True indicates that network connectivity exists and it is possible to + * establish connections and pass data. If false, only the networkHandle field + * is populated to indicate that this network has just disconnected. + */ + bool isConnected; + + /** A set of flags indicating the capabilities of this network. */ + bitfield<NetworkCapability> capabilities; + + /** + * Telephony preferred Access Point Name to use for carrier data connection when + * connected to a cellular network. Empty string, otherwise. + */ + string apn; + }; + + /** + * Notifies GNSS of network status changes. + * + * The framework calls this method to update the GNSS HAL implementation of network + * state changes. The methods updateNetworkState() and updateNetworkAvailability + * in @1.0::IAGnssRil are deprecated and are not called by the framework. + * + * @param attributes Updated network attributes. + * + * @return success True if all parameters were valid and the operation was + * successful. + */ + updateNetworkState_2_0(NetworkAttributes attributes) generates (bool success); +}; diff --git a/gnss/2.0/IGnss.hal b/gnss/2.0/IGnss.hal new file mode 100644 index 0000000000..1f1858e940 --- /dev/null +++ b/gnss/2.0/IGnss.hal @@ -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. + */ + +package android.hardware.gnss@2.0; + +import android.hardware.gnss.measurement_corrections@1.0::IMeasurementCorrections; +import android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControl; +import @1.1::IGnss; + +import IGnssCallback; +import IGnssConfiguration; +import IGnssMeasurement; +import IAGnss; +import IAGnssRil; + +/** + * Represents the standard GNSS (Global Navigation Satellite System) interface. + * + * Due to the introduction of new GNSS HAL package android.hardware.gnss.visibility_control@1.0 + * the interface @1.0::IGnssNi.hal and @1.0::IGnssNiCallback.hal are deprecated in this version + * and are not supported by the framework. The GNSS HAL implementation of this interface + * must return nullptr for the following @1.0::IGnss method. + * getExtensionGnssNi() generates (IGnssNi gnssNiIface); + */ +interface IGnss extends @1.1::IGnss { + /** + * Opens the interface and provides the callback routines to the implementation of this + * interface. + * + * @param callback Callback interface for IGnss. + * + * @return success Returns true on success. + */ + setCallback_2_0(IGnssCallback callback) generates (bool success); + + /** + * This method returns the IGnssConfiguration interface. + * + * @return gnssConfigurationIface Handle to the IGnssConfiguration interface. + */ + getExtensionGnssConfiguration_2_0() generates (IGnssConfiguration gnssConfigurationIface); + + /** + * This method returns the IAGnss Interface. + * + * The getExtensionAGnss() must return nullptr as the @1.0::IAGnss interface is + * deprecated. + * + * @return aGnssIface Handle to the IAGnss interface. + */ + getExtensionAGnss_2_0() generates (IAGnss aGnssIface); + + /** + * This method returns the IAGnssRil Interface. + * + * @return aGnssRilIface Handle to the IAGnssRil interface. + */ + getExtensionAGnssRil_2_0() generates (IAGnssRil aGnssRilIface); + + /** + * This method returns the IGnssMeasurement interface. + * + * Exactly one of getExtensionGnssMeasurement_1_1() and getExtensionGnssMeasurement_2_0() must + * return a non-null handle, and the other method must return nullptr. + * + * @return gnssMeasurementIface Handle to the IGnssMeasurement interface. + */ + getExtensionGnssMeasurement_2_0() generates (IGnssMeasurement gnssMeasurementIface); + + /** + * This method returns the IMeasurementCorrections interface. + * + * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface. + */ + getExtensionMeasurementCorrections() + generates (IMeasurementCorrections measurementCorrectionsIface); + + /** + * This method returns the IGnssVisibilityControl interface. + * + * @return visibilityControlIface Handle to the IGnssVisibilityControl interface. + */ + getExtensionVisibilityControl() generates (IGnssVisibilityControl visibilityControlIface); +};
\ No newline at end of file diff --git a/gnss/2.0/IGnssCallback.hal b/gnss/2.0/IGnssCallback.hal new file mode 100644 index 0000000000..6baff91a55 --- /dev/null +++ b/gnss/2.0/IGnssCallback.hal @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.0; + +import @1.0::IGnssCallback; +import @1.1::IGnssCallback; + +/** + * The interface is required for the HAL to communicate certain information + * like status and location info back to the platform, the platform implements + * the interfaces and passes a handle to the HAL. + */ +interface IGnssCallback extends @1.1::IGnssCallback { + + /** Flags for the gnssSetCapabilities callback. */ + @export(name="", value_prefix="GPS_CAPABILITY_") + enum Capabilities : @1.0::IGnssCallback.Capabilities { + /** GNSS supports line-of-sight satellite identification measurement Corrections */ + MEASUREMENT_CORRECTIONS_LOS_SATS = 1 << 8, + /** GNSS supports per satellite excess-path-length measurement Corrections */ + MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 1 << 9, + /** GNSS supports reflecting planes measurement Corrections */ + MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 1 << 10 + }; + + /** + * Callback to inform framework of the GNSS engine's capabilities. + * + * @param capabilities Capability parameter is a bit field of the Capabilities enum. + */ + gnssSetCapabilitiesCb_2_0(bitfield<Capabilities> capabilities); + +};
\ No newline at end of file diff --git a/gnss/2.0/IGnssConfiguration.hal b/gnss/2.0/IGnssConfiguration.hal new file mode 100644 index 0000000000..90c376ec6b --- /dev/null +++ b/gnss/2.0/IGnssConfiguration.hal @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.0; + +import @1.1::IGnssConfiguration; + +/** + * Extended interface for GNSS Configuration support. + * + * Due to the introduction of new GNSS HAL package android.hardware.gnss.visibility_control@1.0 + * the following methods in @1.0::IGnssConfiguration are deprecated in this version and not + * called by the framework. + * + * setGpsLock(bitfield<GpsLock> lock) generates (bool success); + * setSuplEs(bool enabled) generates (bool success); + */ +interface IGnssConfiguration extends @1.1::IGnssConfiguration { + /** + * This method sets the emergency session extension duration. The GNSS HAL + * implementation must serve emergency SUPL and Control Plane network initiated + * location requests for this extra duration after the user initiated emergency + * session ends. + * + * @param emergencyExtensionSeconds Number of seconds to extend the emergency + * session duration post emergency call. + * + * @return success True if the GNSS HAL implementation accepts and supports the + * extended duration for emergency SUPL and Control Plane location requests. + */ + setEsExtensionSec(uint32_t emergencyExtensionSeconds) generates (bool success); +};
\ No newline at end of file diff --git a/gnss/2.0/IGnssMeasurement.hal b/gnss/2.0/IGnssMeasurement.hal new file mode 100644 index 0000000000..108f3d29ed --- /dev/null +++ b/gnss/2.0/IGnssMeasurement.hal @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.0; + +import @1.0::IGnssMeasurement; +import @1.1::IGnssMeasurement; +import IGnssMeasurementCallback; + +/** + * Extended interface for GNSS Measurements support. + */ +interface IGnssMeasurement extends @1.1::IGnssMeasurement { + + /** + * Initializes the interface and registers the callback routines with the HAL. After a + * successful call to 'setCallback_2_0' the HAL must begin to provide updates at an average + * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec + * can be tolerated.) + * + * @param callback Handle to GnssMeasurement callback interface. + * @param enableFullTracking If true, GNSS chipset must switch off duty cycling. In such mode + * no clock discontinuities are expected and, when supported, carrier phase should be + * continuous in good signal conditions. All non-blacklisted, healthy constellations, + * satellites and frequency bands that the chipset supports must be reported in this mode. + * The GNSS chipset is allowed to consume more power in this mode. If false, API must behave + * as in HAL V1_0, optimizing power via duty cycling, constellations and frequency limits, + * etc. + * + * @return initRet Returns SUCCESS if successful. Returns ERROR_ALREADY_INIT if a callback has + * already been registered without a corresponding call to 'close'. Returns ERROR_GENERIC + * for any other error. The HAL must not generate any other updates upon returning this + * error code. + */ + setCallback_2_0(IGnssMeasurementCallback callback, bool enableFullTracking) + generates (GnssMeasurementStatus initRet); + +}; diff --git a/gnss/2.0/IGnssMeasurementCallback.hal b/gnss/2.0/IGnssMeasurementCallback.hal new file mode 100644 index 0000000000..226934e876 --- /dev/null +++ b/gnss/2.0/IGnssMeasurementCallback.hal @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package android.hardware.gnss@2.0; + +import @1.0::IGnssMeasurementCallback; +import @1.1::IGnssMeasurementCallback; + +/** The callback interface to report measurements from the HAL. */ +interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { + /** + * Enumeration of available values for the GNSS Measurement's code type. Similar to the + * Attribute field described in Rinex 3.03, e.g., in Tables 4-10, and Table A2 at the Rinex 3.03 + * Update 1 Document. + */ + enum GnssMeasurementCodeType : uint8_t { + /** GALILEO E1A, GALILEO E6A, IRNSS L5A, IRNSS SA. */ + CODE_TYPE_A = 0, + + /** GALILEO E1B, GALILEO E6B, IRNSS L5B, IRNSS SB. */ + CODE_TYPE_B = 1, + + /** + * GPS L1 C/A, GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS + * L1 C/A, QZSS L1 C/A, IRNSS L5C. + */ + CODE_TYPE_C = 2, + + /** + * GPS L5 I, GLONASS G3 I, GALILEO E5a I, GALILEO E5b I, GALILEO E5a+b I, SBAS L5 I, QZSS L5 + * I, BDS B1 I, BDS B2 I, BDS B3 I. + */ + CODE_TYPE_I = 3, + + /** GPS L1C (P), GPS L2C (L), QZSS L1C (P), QZSS L2C (L), LEX(6) L. */ + CODE_TYPE_L = 4, + + /** GPS L1M, GPS L2M. */ + CODE_TYPE_M = 5, + + /** GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P. */ + CODE_TYPE_P = 6, + + /** + * GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q, GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 + * Q, BDS B1 Q, BDS B2 Q, BDS B3 Q. + */ + CODE_TYPE_Q = 7, + + /** GPS L1C (D), GPS L2C (M), QZSS L1C (D), QZSS L2C (M), LEX(6) S. */ + CODE_TYPE_S = 8, + + /** GPS L1 Z-tracking, GPS L2 Z-tracking. */ + CODE_TYPE_W = 9, + + /** + * GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q), GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO + * E5a (I+Q), GALILEO E5b (I+Q), GALILEO E5a+b(I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS + * L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q), LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS + * B3 (I+Q), IRNSS L5 (B+C). + */ + CODE_TYPE_X = 10, + + /** GPS L1Y, GPS L2Y. */ + CODE_TYPE_Y = 11, + + /** GALILEO E1 (A+B+C), GALILEO E6 (A+B+C), QZSS L1-SAIF. */ + CODE_TYPE_Z = 12, + + /** GPS L1 codeless, GPS L2 codeless. */ + CODE_TYPE_CODELESS = 13 + }; + + /** + * Extends a GNSS Measurement, adding a GnssMeasurementCodeType. + */ + struct GnssMeasurement { + /** + * GNSS measurement information for a single satellite and frequency, as in the 1.1 + * version of the HAL with further clarification of the value reported in the + * accumulatedDeltaRangeM field, i.e., the alignment of the phase measurement will not be + * adjusted by the receiver so the in-phase and quadrature phase components will have a + * quarter cycle offset as they do when transmitted from the satellites. If the measurement + * is from a combination of the in-phase and quadrature phase components, then the alignment + * of the phase measurement will be aligned to the in-phase component. + */ + @1.1::IGnssMeasurementCallback.GnssMeasurement v1_1; + + /** + * The type of code that is currently being tracked in the GNSS measurement. + * + * For high precision applications the type of code being tracked needs to be considered + * in-order to properly apply code specific corrections to the psuedorange measurements. + */ + GnssMeasurementCodeType codeType; + }; + + /** + * Complete set of GNSS Measurement data, same as 1.1 with additional enum in measurements. + */ + struct GnssData { + /** The full set of satellite measurement observations. */ + vec<GnssMeasurement> measurements; + + /** The GNSS clock time reading. */ + GnssClock clock; + }; + + /** + * Callback for the hal to pass a GnssData structure back to the client. + * + * @param data Contains a reading of GNSS measurements. + */ + gnssMeasurementCb_2_0(GnssData data); +}; diff --git a/gnss/2.0/default/AGnss.cpp b/gnss/2.0/default/AGnss.cpp new file mode 100644 index 0000000000..c8e8bf17ad --- /dev/null +++ b/gnss/2.0/default/AGnss.cpp @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#define LOG_TAG "AGnss" + +#include "AGnss.h" +#include <log/log.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +// Methods from ::android::hardware::gnss::V2_0::IAGnss follow. +Return<void> AGnss::setCallback(const sp<V2_0::IAGnssCallback>&) { + // TODO implement + return Void(); +} + +Return<bool> AGnss::dataConnClosed() { + // TODO implement + return bool{}; +} + +Return<bool> AGnss::dataConnFailed() { + // TODO implement + return bool{}; +} + +Return<bool> AGnss::setServer(V2_0::IAGnssCallback::AGnssType type, const hidl_string& hostname, + int32_t port) { + ALOGD("setServer: type: %s, hostname: %s, port: %d", toString(type).c_str(), hostname.c_str(), + port); + return true; +} + +Return<bool> AGnss::dataConnOpen(uint64_t, const hidl_string&, V2_0::IAGnss::ApnIpType) { + // TODO implement + return bool{}; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.0/default/AGnss.h b/gnss/2.0/default/AGnss.h new file mode 100644 index 0000000000..244a2c6fe5 --- /dev/null +++ b/gnss/2.0/default/AGnss.h @@ -0,0 +1,55 @@ +/* + * 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 ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H +#define ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H + +#include <android/hardware/gnss/2.0/IAGnss.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct AGnss : public IAGnss { + // Methods from ::android::hardware::gnss::V2_0::IAGnss follow. + Return<void> setCallback(const sp<V2_0::IAGnssCallback>& callback) override; + Return<bool> dataConnClosed() override; + Return<bool> dataConnFailed() override; + Return<bool> setServer(V2_0::IAGnssCallback::AGnssType type, const hidl_string& hostname, + int32_t port) override; + Return<bool> dataConnOpen(uint64_t networkHandle, const hidl_string& apn, + V2_0::IAGnss::ApnIpType apnIpType) override; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
\ No newline at end of file diff --git a/gnss/2.0/default/AGnssRil.cpp b/gnss/2.0/default/AGnssRil.cpp new file mode 100644 index 0000000000..eae2169805 --- /dev/null +++ b/gnss/2.0/default/AGnssRil.cpp @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#define LOG_TAG "AGnssRil" + +#include "AGnssRil.h" +#include <log/log.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +// Methods from V1_0::IAGnssRil follow. +Return<void> AGnssRil::setCallback(const sp<V1_0::IAGnssRilCallback>&) { + // TODO implement + return Void(); +} + +Return<void> AGnssRil::setRefLocation(const V1_0::IAGnssRil::AGnssRefLocation&) { + // TODO implement + return Void(); +} + +Return<bool> AGnssRil::setSetId(V1_0::IAGnssRil::SetIDType, const hidl_string&) { + // TODO implement + return bool{}; +} + +Return<bool> AGnssRil::updateNetworkState(bool, V1_0::IAGnssRil::NetworkType, bool) { + // TODO implement + return bool{}; +} + +Return<bool> AGnssRil::updateNetworkAvailability(bool, const hidl_string&) { + // TODO implement + return bool{}; +} + +// Methods from ::android::hardware::gnss::V2_0::IAGnssRil follow. +Return<bool> AGnssRil::updateNetworkState_2_0( + const V2_0::IAGnssRil::NetworkAttributes& attributes) { + ALOGD("updateNetworkState_2_0 networkAttributes: %s", toString(attributes).c_str()); + return true; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.0/default/AGnssRil.h b/gnss/2.0/default/AGnssRil.h new file mode 100644 index 0000000000..0f822f8b0f --- /dev/null +++ b/gnss/2.0/default/AGnssRil.h @@ -0,0 +1,58 @@ +/* + * 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 ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H +#define ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H + +#include <android/hardware/gnss/2.0/IAGnssRil.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct AGnssRil : public IAGnssRil { + // Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow. + Return<void> setCallback(const sp<V1_0::IAGnssRilCallback>& callback) override; + Return<void> setRefLocation(const V1_0::IAGnssRil::AGnssRefLocation& agnssReflocation) override; + Return<bool> setSetId(V1_0::IAGnssRil::SetIDType type, const hidl_string& setid) override; + Return<bool> updateNetworkState(bool connected, V1_0::IAGnssRil::NetworkType type, + bool roaming) override; + Return<bool> updateNetworkAvailability(bool available, const hidl_string& apn) override; + + // Methods from ::android::hardware::gnss::V2_0::IAGnssRil follow. + Return<bool> updateNetworkState_2_0( + const V2_0::IAGnssRil::NetworkAttributes& attributes) override; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H
\ No newline at end of file diff --git a/gnss/2.0/default/Android.bp b/gnss/2.0/default/Android.bp new file mode 100644 index 0000000000..985aa2ba88 --- /dev/null +++ b/gnss/2.0/default/Android.bp @@ -0,0 +1,43 @@ +/* + * 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. + */ + +cc_binary { + name: "android.hardware.gnss@2.0-service", + init_rc: ["android.hardware.gnss@2.0-service.rc"], + relative_install_path: "hw", + vendor: true, + vintf_fragments: ["android.hardware.gnss@2.0-service.xml"], + srcs: [ + "GnssConfiguration.cpp", + "AGnss.cpp", + "AGnssRil.cpp", + "Gnss.cpp", + "GnssMeasurement.cpp", + "GnssVisibilityControl.cpp", + "service.cpp" + ], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libutils", + "liblog", + "android.hardware.gnss@2.0", + "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.visibility_control@1.0", + "android.hardware.gnss@1.0", + "android.hardware.gnss@1.1", + ], +} diff --git a/gnss/2.0/default/Gnss.cpp b/gnss/2.0/default/Gnss.cpp new file mode 100644 index 0000000000..217f0f358b --- /dev/null +++ b/gnss/2.0/default/Gnss.cpp @@ -0,0 +1,250 @@ +/* + * 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. + */ + +#define LOG_TAG "Gnss" + +#include "Gnss.h" +#include <log/log.h> +#include "AGnss.h" +#include "AGnssRil.h" +#include "GnssConfiguration.h" +#include "GnssMeasurement.h" +#include "GnssVisibilityControl.h" + +using ::android::hardware::Status; +using ::android::hardware::gnss::visibility_control::V1_0::implementation::GnssVisibilityControl; + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_0 = nullptr; +sp<V1_1::IGnssCallback> Gnss::sGnssCallback_1_1 = nullptr; + +// Methods from V1_0::IGnss follow. +Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>&) { + // TODO implement + return bool{}; +} + +Return<bool> Gnss::start() { + // TODO implement + return bool{}; +} + +Return<bool> Gnss::stop() { + // TODO implement + return bool{}; +} + +Return<void> Gnss::cleanup() { + // TODO implement + return Void(); +} + +Return<bool> Gnss::injectTime(int64_t, int64_t, int32_t) { + // TODO implement + return bool{}; +} + +Return<bool> Gnss::injectLocation(double, double, float) { + // TODO implement + return bool{}; +} + +Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) { + // TODO implement + return Void(); +} + +Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode, + V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t, + uint32_t) { + // TODO implement + return bool{}; +} + +Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() { + // TODO implement + return sp<V1_0::IAGnssRil>{}; +} + +Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() { + // TODO implement + return sp<V1_0::IGnssGeofencing>{}; +} + +Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() { + // TODO implement + return sp<V1_0::IAGnss>{}; +} + +Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() { + // The IGnssNi.hal interface is deprecated in 2.0. + return nullptr; +} + +Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() { + // Not supported + return nullptr; +} + +Return<sp<V1_0::IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() { + // TODO implement + return sp<V1_0::IGnssNavigationMessage>{}; +} + +Return<sp<V1_0::IGnssXtra>> Gnss::getExtensionXtra() { + // TODO implement + return sp<V1_0::IGnssXtra>{}; +} + +Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() { + // TODO implement + return sp<V1_0::IGnssConfiguration>{}; +} + +Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() { + // TODO implement + return sp<V1_0::IGnssDebug>{}; +} + +Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() { + // TODO implement + return sp<V1_0::IGnssBatching>{}; +} + +// Methods from V1_1::IGnss follow. +Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) { + ALOGD("Gnss::setCallback_1_1"); + if (callback == nullptr) { + ALOGE("%s: Null callback ignored", __func__); + return false; + } + + sGnssCallback_1_1 = callback; + + uint32_t capabilities = (uint32_t)V1_0::IGnssCallback::Capabilities::MEASUREMENTS; + auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019}; + + ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + auto gnssName = "Google Mock GNSS Implementation v2.0"; + ret = sGnssCallback_1_1->gnssNameCb(gnssName); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + return true; +} + +Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode, + V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t, + uint32_t, bool) { + // TODO implement + return bool{}; +} + +Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() { + // TODO implement + return sp<V1_1::IGnssConfiguration>{}; +} + +Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() { + ALOGD("Gnss::getExtensionGnssMeasurement_1_1"); + return new GnssMeasurement(); +} + +Return<bool> Gnss::injectBestLocation(const V1_0::GnssLocation&) { + // TODO implement + return bool{}; +} + +// Methods from V2_0::IGnss follow. +Return<sp<V2_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_0() { + return new GnssConfiguration{}; +} + +Return<sp<V2_0::IAGnss>> Gnss::getExtensionAGnss_2_0() { + return new AGnss{}; +} + +Return<sp<V2_0::IAGnssRil>> Gnss::getExtensionAGnssRil_2_0() { + return new AGnssRil{}; +} + +Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() { + ALOGD("Gnss::getExtensionGnssMeasurement_2_0"); + return new GnssMeasurement(); +} + +Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>> +Gnss::getExtensionMeasurementCorrections() { + // TODO implement + return sp<measurement_corrections::V1_0::IMeasurementCorrections>{}; +} + +Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> Gnss::getExtensionVisibilityControl() { + ALOGD("Gnss::getExtensionVisibilityControl"); + return new GnssVisibilityControl(); +} + +Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) { + ALOGD("Gnss::setCallback_2_0"); + if (callback == nullptr) { + ALOGE("%s: Null callback ignored", __func__); + return false; + } + + sGnssCallback_2_0 = callback; + + uint32_t capabilities = 0x0; + auto ret = sGnssCallback_2_0->gnssSetCapabilitesCb(capabilities); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019}; + + ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + auto gnssName = "Google Mock GNSS Implementation v2.0"; + ret = sGnssCallback_2_0->gnssNameCb(gnssName); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + + return true; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.0/default/Gnss.h b/gnss/2.0/default/Gnss.h new file mode 100644 index 0000000000..890b026749 --- /dev/null +++ b/gnss/2.0/default/Gnss.h @@ -0,0 +1,96 @@ +/* + * 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 ANDROID_HARDWARE_GNSS_V2_0_GNSS_H +#define ANDROID_HARDWARE_GNSS_V2_0_GNSS_H + +#include <android/hardware/gnss/2.0/IGnss.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct Gnss : public IGnss { + // Methods from V1_0::IGnss follow. + Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override; + Return<bool> start() override; + Return<bool> stop() override; + Return<void> cleanup() override; + Return<bool> injectTime(int64_t timeMs, int64_t timeReferenceMs, + int32_t uncertaintyMs) override; + Return<bool> injectLocation(double latitudeDegrees, double longitudeDegrees, + float accuracyMeters) override; + Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override; + Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode, + V1_0::IGnss::GnssPositionRecurrence recurrence, + uint32_t minIntervalMs, uint32_t preferredAccuracyMeters, + uint32_t preferredTimeMs) override; + Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override; + Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override; + Return<sp<V1_0::IAGnss>> getExtensionAGnss() override; + Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override; + Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override; + Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override; + Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override; + Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override; + Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override; + Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override; + + // Methods from V1_1::IGnss follow. + Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override; + Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode, + V1_0::IGnss::GnssPositionRecurrence recurrence, + uint32_t minIntervalMs, uint32_t preferredAccuracyMeters, + uint32_t preferredTimeMs, bool lowPowerMode) override; + Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override; + Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override; + Return<bool> injectBestLocation(const V1_0::GnssLocation& location) override; + + // Methods from V2_0::IGnss follow. + Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override; + Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override; + Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override; + Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override; + Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override; + Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>> + getExtensionMeasurementCorrections() override; + Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> getExtensionVisibilityControl() + override; + + private: + static sp<V2_0::IGnssCallback> sGnssCallback_2_0; + static sp<V1_1::IGnssCallback> sGnssCallback_1_1; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSS_H diff --git a/gnss/2.0/default/GnssConfiguration.cpp b/gnss/2.0/default/GnssConfiguration.cpp new file mode 100644 index 0000000000..4389dd28f3 --- /dev/null +++ b/gnss/2.0/default/GnssConfiguration.cpp @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#define LOG_TAG "GnssConfiguration" + +#include "GnssConfiguration.h" +#include <log/log.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow. +Return<bool> GnssConfiguration::setSuplEs(bool enable) { + ALOGD("setSuplEs enable: %d", enable); + // Method deprecated in 2.0 and not expected to be called by the framework. + return false; +} + +Return<bool> GnssConfiguration::setSuplVersion(uint32_t) { + // TODO implement + return bool{}; +} + +Return<bool> GnssConfiguration::setSuplMode(hidl_bitfield<SuplMode>) { + // TODO implement + return bool{}; +} + +Return<bool> GnssConfiguration::setGpsLock(hidl_bitfield<GpsLock> gpsLock) { + ALOGD("setGpsLock gpsLock: %hhu", static_cast<GpsLock>(gpsLock)); + // Method deprecated in 2.0 and not expected to be called by the framework. + return false; +} + +Return<bool> GnssConfiguration::setLppProfile(hidl_bitfield<LppProfile>) { + // TODO implement + return bool{}; +} + +Return<bool> GnssConfiguration::setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol>) { + // TODO implement + return bool{}; +} + +Return<bool> GnssConfiguration::setEmergencySuplPdn(bool) { + // TODO implement + return bool{}; +} + +// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow. +Return<bool> GnssConfiguration::setBlacklist( + const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>&) { + // TODO (b/122463906): Reuse 1.1 implementation. + return bool{}; +} + +// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow. +Return<bool> GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) { + ALOGD("setEsExtensionSec emergencyExtensionSeconds: %d", emergencyExtensionSeconds); + return true; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android
\ No newline at end of file diff --git a/gnss/2.0/default/GnssConfiguration.h b/gnss/2.0/default/GnssConfiguration.h new file mode 100644 index 0000000000..0c02ccd5e9 --- /dev/null +++ b/gnss/2.0/default/GnssConfiguration.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 ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H +#define ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H + +#include <android/hardware/gnss/2.0/IGnssConfiguration.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct GnssConfiguration : public IGnssConfiguration { + // Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow. + Return<bool> setSuplEs(bool enabled) override; + Return<bool> setSuplVersion(uint32_t version) override; + Return<bool> setSuplMode(hidl_bitfield<SuplMode> mode) override; + Return<bool> setGpsLock(hidl_bitfield<GpsLock> lock) override; + Return<bool> setLppProfile(hidl_bitfield<LppProfile> lppProfile) override; + Return<bool> setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol> protocol) override; + Return<bool> setEmergencySuplPdn(bool enable) override; + + // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow. + Return<bool> setBlacklist( + const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>& blacklist) override; + + // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow. + Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H
\ No newline at end of file diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp new file mode 100644 index 0000000000..dc23db3163 --- /dev/null +++ b/gnss/2.0/default/GnssMeasurement.cpp @@ -0,0 +1,149 @@ +/* + * 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. + */ +#define LOG_TAG "GnssMeasurement" + +#include "GnssMeasurement.h" +#include <log/log.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +using GnssConstellationType = V1_0::GnssConstellationType; +using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags; +using GnssMeasurementState = V1_0::IGnssMeasurementCallback::GnssMeasurementState; + +sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback = nullptr; + +GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {} + +GnssMeasurement::~GnssMeasurement() { + stop(); +} + +// Methods from V1_0::IGnssMeasurement follow. +Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback( + const sp<V1_0::IGnssMeasurementCallback>&) { + // TODO implement + return V1_0::IGnssMeasurement::GnssMeasurementStatus{}; +} + +Return<void> GnssMeasurement::close() { + std::unique_lock<std::mutex> lock(mMutex); + stop(); + sCallback = nullptr; + return Void(); +} + +// Methods from V1_1::IGnssMeasurement follow. +Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1( + const sp<V1_1::IGnssMeasurementCallback>&, bool) { + // TODO implement + return V1_0::IGnssMeasurement::GnssMeasurementStatus{}; +} + +// Methods from V2_0::IGnssMeasurement follow. +Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0( + const sp<V2_0::IGnssMeasurementCallback>& callback, bool) { + std::unique_lock<std::mutex> lock(mMutex); + sCallback = callback; + + if (mIsActive) { + ALOGW("GnssMeasurement callback already set. Resetting the callback..."); + stop(); + } + start(); + + return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS; +} + +void GnssMeasurement::start() { + mIsActive = true; + mThread = std::thread([this]() { + while (mIsActive == true) { + auto measurement = this->getMockMeasurement(); + this->reportMeasurement(measurement); + + std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); + } + }); +} + +void GnssMeasurement::stop() { + mIsActive = false; + if (mThread.joinable()) { + mThread.join(); + } +} + +GnssData GnssMeasurement::getMockMeasurement() { + V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = { + .flags = (uint32_t)GnssMeasurementFlags::HAS_CARRIER_FREQUENCY, + .svid = (int16_t)6, + .constellation = GnssConstellationType::GLONASS, + .timeOffsetNs = 0.0, + .state = GnssMeasurementState::STATE_CODE_LOCK | GnssMeasurementState::STATE_BIT_SYNC | + GnssMeasurementState::STATE_SUBFRAME_SYNC | + GnssMeasurementState::STATE_TOW_DECODED | + GnssMeasurementState::STATE_GLO_STRING_SYNC | + GnssMeasurementState::STATE_GLO_TOD_DECODED, + .receivedSvTimeInNs = 8195997131077, + .receivedSvTimeUncertaintyInNs = 15, + .cN0DbHz = 30.0, + .pseudorangeRateMps = -484.13739013671875, + .pseudorangeRateUncertaintyMps = 1.0379999876022339, + .accumulatedDeltaRangeState = (uint32_t) + V1_0::IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_UNKNOWN, + .accumulatedDeltaRangeM = 0.0, + .accumulatedDeltaRangeUncertaintyM = 0.0, + .carrierFrequencyHz = 1.59975e+09, + .multipathIndicator = + V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN}; + V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0}; + V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = { + .v1_1 = measurement_1_1, + .codeType = IGnssMeasurementCallback::GnssMeasurementCodeType::CODE_TYPE_C}; + + hidl_vec<IGnssMeasurementCallback::GnssMeasurement> measurements(1); + measurements[0] = measurement_2_0; + V1_0::IGnssMeasurementCallback::GnssClock clock = {.timeNs = 2713545000000, + .fullBiasNs = -1226701900521857520, + .biasNs = 0.59689998626708984, + .biasUncertaintyNs = 47514.989972114563, + .driftNsps = -51.757811607455452, + .driftUncertaintyNsps = 310.64968328491528, + .hwClockDiscontinuityCount = 1}; + GnssData gnssData = {.measurements = measurements, .clock = clock}; + return gnssData; +} + +void GnssMeasurement::reportMeasurement(const GnssData& data) { + ALOGD("reportMeasurement()"); + std::unique_lock<std::mutex> lock(mMutex); + if (sCallback == nullptr) { + ALOGE("%s: GnssMeasurement::sCallback is null.", __func__); + return; + } + sCallback->gnssMeasurementCb_2_0(data); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.0/default/GnssMeasurement.h b/gnss/2.0/default/GnssMeasurement.h new file mode 100644 index 0000000000..c24c00e341 --- /dev/null +++ b/gnss/2.0/default/GnssMeasurement.h @@ -0,0 +1,78 @@ +/* + * 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 ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H +#define ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H + +#include <android/hardware/gnss/2.0/IGnssMeasurement.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <atomic> +#include <mutex> +#include <thread> + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +using GnssData = V2_0::IGnssMeasurementCallback::GnssData; + +struct GnssMeasurement : public IGnssMeasurement { + GnssMeasurement(); + ~GnssMeasurement(); + // Methods from V1_0::IGnssMeasurement follow. + Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback( + const sp<V1_0::IGnssMeasurementCallback>& callback) override; + Return<void> close() override; + + // Methods from V1_1::IGnssMeasurement follow. + Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_1_1( + const sp<V1_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) override; + + // Methods from V2_0::IGnssMeasurement follow. + Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_0( + const sp<V2_0::IGnssMeasurementCallback>& callback, bool enableFullTracking) override; + + private: + void start(); + void stop(); + GnssData getMockMeasurement(); + void reportMeasurement(const GnssData&); + + static sp<IGnssMeasurementCallback> sCallback; + std::atomic<long> mMinIntervalMillis; + std::atomic<bool> mIsActive; + std::thread mThread; + mutable std::mutex mMutex; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H diff --git a/gnss/2.0/default/GnssVisibilityControl.cpp b/gnss/2.0/default/GnssVisibilityControl.cpp new file mode 100644 index 0000000000..99b8e34746 --- /dev/null +++ b/gnss/2.0/default/GnssVisibilityControl.cpp @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#define LOG_TAG "GnssVisibilityControl" + +#include "GnssVisibilityControl.h" +#include <log/log.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace visibility_control { +namespace V1_0 { +namespace implementation { + +// Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow. +Return<bool> GnssVisibilityControl::enableNfwLocationAccess( + const hidl_vec<hidl_string>& proxyApps) { + std::string os; + bool first = true; + for (const auto& proxyApp : proxyApps) { + if (first) { + first = false; + } else { + os += " "; + } + + os += proxyApp; + } + + ALOGD("enableNfwLocationAccess proxyApps: %s", os.c_str()); + return true; +} + +Return<bool> GnssVisibilityControl::setCallback(const sp<V1_0::IGnssVisibilityControlCallback>&) { + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace visibility_control +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.0/default/GnssVisibilityControl.h b/gnss/2.0/default/GnssVisibilityControl.h new file mode 100644 index 0000000000..45febfff9e --- /dev/null +++ b/gnss/2.0/default/GnssVisibilityControl.h @@ -0,0 +1,53 @@ +/* + * 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 ANDROID_HARDWARE_GNSS_VISIBILITY_CONTROL_V1_0_GNSSVISIBILITYCONTROL_H +#define ANDROID_HARDWARE_GNSS_VISIBILITY_CONTROL_V1_0_GNSSVISIBILITYCONTROL_H + +#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace visibility_control { +namespace V1_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct GnssVisibilityControl : public IGnssVisibilityControl { + // Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl + // follow. + Return<bool> enableNfwLocationAccess(const hidl_vec<hidl_string>& proxyApps) override; + Return<bool> setCallback(const sp<V1_0::IGnssVisibilityControlCallback>& callback) override; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace visibility_control +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_VISIBILITY_CONTROL_V1_0_GNSSVISIBILITYCONTROL_H
\ No newline at end of file diff --git a/gnss/2.0/default/OWNERS b/gnss/2.0/default/OWNERS new file mode 100644 index 0000000000..8da956c08f --- /dev/null +++ b/gnss/2.0/default/OWNERS @@ -0,0 +1,5 @@ +wyattriley@google.com +gomo@google.com +smalkos@google.com +yuhany@google.com +aadmal@google.com diff --git a/gnss/2.0/default/android.hardware.gnss@2.0-service.rc b/gnss/2.0/default/android.hardware.gnss@2.0-service.rc new file mode 100644 index 0000000000..a27240d909 --- /dev/null +++ b/gnss/2.0/default/android.hardware.gnss@2.0-service.rc @@ -0,0 +1,4 @@ +service vendor.gnss-2-0 /vendor/bin/hw/android.hardware.gnss@2.0-service + class hal + user system + group system diff --git a/gnss/2.0/default/android.hardware.gnss@2.0-service.xml b/gnss/2.0/default/android.hardware.gnss@2.0-service.xml new file mode 100644 index 0000000000..5b417f6923 --- /dev/null +++ b/gnss/2.0/default/android.hardware.gnss@2.0-service.xml @@ -0,0 +1,12 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.gnss</name> + <transport>hwbinder</transport> + <version>2.0</version> + <version>1.1</version> + <interface> + <name>IGnss</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/gnss/2.0/default/service.cpp b/gnss/2.0/default/service.cpp new file mode 100644 index 0000000000..301d1816dd --- /dev/null +++ b/gnss/2.0/default/service.cpp @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.gnss@2.0-service" + +#include <hidl/HidlSupport.h> +#include <hidl/HidlTransportSupport.h> +#include "Gnss.h" + +using ::android::OK; +using ::android::sp; +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::joinRpcThreadpool; +using ::android::hardware::gnss::V2_0::IGnss; +using ::android::hardware::gnss::V2_0::implementation::Gnss; + +int main(int /* argc */, char* /* argv */ []) { + sp<IGnss> gnss = new Gnss(); + configureRpcThreadpool(1, true /* will join */); + if (gnss->registerAsService() != OK) { + ALOGE("Could not register gnss 2.0 service."); + return 1; + } + joinRpcThreadpool(); + + ALOGE("Service exited!"); + return 1; +} diff --git a/audio/common/4.0/default/HidlUtils.cpp b/gnss/2.0/types.hal index b66eff975a..97c178ff32 100644 --- a/audio/common/4.0/default/HidlUtils.cpp +++ b/gnss/2.0/types.hal @@ -14,8 +14,7 @@ * limitations under the License. */ -#include "HidlUtils.h" +package android.hardware.gnss@2.0; -#define AUDIO_HAL_VERSION V4_0 -#include <common/all-versions/default/HidlUtils.impl.h> -#undef AUDIO_HAL_VERSION +/** Network handle type. */ +typedef uint64_t net_handle_t; diff --git a/gnss/2.0/vts/OWNERS b/gnss/2.0/vts/OWNERS new file mode 100644 index 0000000000..0a7ce6c26d --- /dev/null +++ b/gnss/2.0/vts/OWNERS @@ -0,0 +1,8 @@ +wyattriley@google.com +gomo@google.com +smalkos@google.com +yuhany@google.com +aadmal@google.com + +# VTS team +yim@google.com diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp new file mode 100644 index 0000000000..684b381ae2 --- /dev/null +++ b/gnss/2.0/vts/functional/Android.bp @@ -0,0 +1,32 @@ +// +// 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. +// + +cc_test { + name: "VtsHalGnssV2_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "gnss_hal_test.cpp", + "gnss_hal_test_cases.cpp", + "VtsHalGnssV2_0TargetTest.cpp", + ], + static_libs: [ + "android.hardware.gnss.measurement_corrections@1.0", + "android.hardware.gnss.visibility_control@1.0", + "android.hardware.gnss@1.0", + "android.hardware.gnss@1.1", + "android.hardware.gnss@2.0", + ], +} diff --git a/audio/common/4.0/default/HidlUtils.h b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp index 91e6a9e121..a8e40ba250 100644 --- a/audio/common/4.0/default/HidlUtils.h +++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp @@ -13,14 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#define LOG_TAG "VtsHalGnssV2_0TargetTest" -#ifndef android_hardware_audio_V4_0_Hidl_Utils_H_ -#define android_hardware_audio_V4_0_Hidl_Utils_H_ +#include <VtsHalHidlTargetTestBase.h> -#include <android/hardware/audio/common/4.0/types.h> +#include "gnss_hal_test.h" -#define AUDIO_HAL_VERSION V4_0 -#include <common/all-versions/default/HidlUtils.h> -#undef AUDIO_HAL_VERSION - -#endif // android_hardware_audio_V4_0_Hidl_Utils_H_ +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + GnssHidlEnvironment::Instance()->init(&argc, argv); + // TODO (b/122463165): Expand coverage to include 1.1 and 1.0 VTS tests. + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp new file mode 100644 index 0000000000..3a48c9e268 --- /dev/null +++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp @@ -0,0 +1,145 @@ +/* + * 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. + */ + +#define LOG_TAG "GnssHalTest" + +#include <gnss_hal_test.h> + +#include <chrono> + +// Implementations for the main test class for GNSS HAL +GnssHalTest::GnssHalTest() + : info_called_count_(0), + capabilities_called_count_(0), + location_called_count_(0), + name_called_count_(0), + notify_count_(0) {} + +void GnssHalTest::SetUp() { + gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>( + GnssHidlEnvironment::Instance()->getServiceName<IGnss>()); + list_gnss_sv_status_.clear(); + ASSERT_NE(gnss_hal_, nullptr); + + SetUpGnssCallback(); +} + +void GnssHalTest::TearDown() { + // Reset counters + info_called_count_ = 0; + capabilities_called_count_ = 0; + location_called_count_ = 0; + name_called_count_ = 0; + measurement_called_count_ = 0; + + if (gnss_hal_ != nullptr) { + gnss_hal_->cleanup(); + } + if (notify_count_ > 0) { + ALOGW("%d unprocessed callbacks discarded", notify_count_); + } +} + +void GnssHalTest::SetUpGnssCallback() { + gnss_cb_ = new GnssCallback(*this); + ASSERT_NE(gnss_cb_, nullptr); + + auto result = gnss_hal_->setCallback_1_1(gnss_cb_); + if (!result.isOk()) { + ALOGE("result of failed setCallback %s", result.description().c_str()); + } + + ASSERT_TRUE(result.isOk()); + ASSERT_TRUE(result); + + /* + * All capabilities, name and systemInfo callbacks should trigger + */ + EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC)); + EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC)); + EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC)); + + EXPECT_EQ(capabilities_called_count_, 1); + EXPECT_EQ(info_called_count_, 1); + EXPECT_EQ(name_called_count_, 1); +} + +void GnssHalTest::notify() { + std::unique_lock<std::mutex> lock(mtx_); + notify_count_++; + cv_.notify_one(); +} + +std::cv_status GnssHalTest::wait(int timeout_seconds) { + std::unique_lock<std::mutex> lock(mtx_); + + auto status = std::cv_status::no_timeout; + while (notify_count_ == 0) { + status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds)); + if (status == std::cv_status::timeout) return status; + } + notify_count_--; + return status; +} + +Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb( + const IGnssCallback::GnssSystemInfo& info) { + ALOGI("Info received, year %d", info.yearOfHw); + parent_.info_called_count_++; + parent_.last_info_ = info; + parent_.notify(); + return Void(); +} + +Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) { + ALOGI("Capabilities received %d", capabilities); + parent_.capabilities_called_count_++; + parent_.last_capabilities_ = capabilities; + parent_.notify(); + return Void(); +} + +Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) { + ALOGI("Name received: %s", name.c_str()); + parent_.name_called_count_++; + parent_.last_name_ = name; + parent_.notify(); + return Void(); +} + +Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) { + ALOGI("Location received"); + parent_.location_called_count_++; + parent_.last_location_ = location; + parent_.notify(); + return Void(); +} + +Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb( + const IGnssCallback::GnssSvStatus& svStatus) { + ALOGI("GnssSvStatus received"); + parent_.list_gnss_sv_status_.emplace_back(svStatus); + return Void(); +} + +Return<void> GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_0( + const IGnssMeasurementCallback_2_0::GnssData& data) { + ALOGD("GnssMeasurement received. Size = %d", (int)data.measurements.size()); + parent_.measurement_called_count_++; + parent_.last_measurement_ = data; + parent_.notify(); + return Void(); +} diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h new file mode 100644 index 0000000000..5649b45bbd --- /dev/null +++ b/gnss/2.0/vts/functional/gnss_hal_test.h @@ -0,0 +1,159 @@ +/* + * 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 GNSS_HAL_TEST_H_ +#define GNSS_HAL_TEST_H_ + +#include <android/hardware/gnss/2.0/IGnss.h> + +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> + +#include <condition_variable> +#include <list> +#include <mutex> + +using android::hardware::Return; +using android::hardware::Void; + +using android::hardware::gnss::V1_0::GnssLocation; + +using android::hardware::gnss::V1_0::GnssLocationFlags; +using android::hardware::gnss::V1_1::IGnssCallback; +using android::hardware::gnss::V2_0::IGnss; +using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback; +using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback; +using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback; + +using android::sp; + +#define TIMEOUT_SEC 2 // for basic commands/responses + +// Test environment for GNSS HIDL HAL. +class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static GnssHidlEnvironment* Instance() { + static GnssHidlEnvironment* instance = new GnssHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<IGnss>(); } + + private: + GnssHidlEnvironment() {} +}; + +// The main test class for GNSS HAL. +class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { + public: + GnssHalTest(); + + virtual void SetUp() override; + + virtual void TearDown() override; + + /* Used as a mechanism to inform the test that a callback has occurred */ + void notify(); + + /* Test code calls this function to wait for a callback */ + std::cv_status wait(int timeout_seconds); + + /* Callback class for data & Event. */ + class GnssCallback : public IGnssCallback { + public: + GnssHalTest& parent_; + + GnssCallback(GnssHalTest& parent) : parent_(parent){}; + + virtual ~GnssCallback() = default; + + // Dummy callback handlers + Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override { + return Void(); + } + Return<void> gnssNmeaCb(int64_t /* timestamp */, + const android::hardware::hidl_string& /* nmea */) override { + return Void(); + } + Return<void> gnssAcquireWakelockCb() override { return Void(); } + Return<void> gnssReleaseWakelockCb() override { return Void(); } + Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override { + return Void(); + } + Return<void> gnssRequestTimeCb() override { return Void(); } + // Actual (test) callback handlers + Return<void> gnssNameCb(const android::hardware::hidl_string& name) override; + Return<void> gnssLocationCb(const GnssLocation& location) override; + Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override; + Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override; + Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override; + }; + + /* Callback class for GnssMeasurement. */ + class GnssMeasurementCallback : public IGnssMeasurementCallback_2_0 { + public: + GnssHalTest& parent_; + GnssMeasurementCallback(GnssHalTest& parent) : parent_(parent){}; + virtual ~GnssMeasurementCallback() = default; + + // Methods from V1_0::IGnssMeasurementCallback follow. + Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override { + return Void(); + } + + // Methods from V1_1::IGnssMeasurementCallback follow. + Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override { + return Void(); + } + + // Methods from V2_0::IGnssMeasurementCallback follow. + Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override; + }; + + /* + * SetUpGnssCallback: + * Set GnssCallback and verify the result. + */ + void SetUpGnssCallback(); + + sp<IGnss> gnss_hal_; // GNSS HAL to call into + sp<IGnssCallback> gnss_cb_; // Primary callback interface + + /* Count of calls to set the following items, and the latest item (used by + * test.) + */ + int info_called_count_; + int capabilities_called_count_; + int location_called_count_; + int measurement_called_count_; + int name_called_count_; + + IGnssCallback::GnssSystemInfo last_info_; + uint32_t last_capabilities_; + GnssLocation last_location_; + IGnssMeasurementCallback_2_0::GnssData last_measurement_; + android::hardware::hidl_string last_name_; + + list<IGnssCallback::GnssSvStatus> list_gnss_sv_status_; + + private: + std::mutex mtx_; + std::condition_variable cv_; + int notify_count_; +}; + +#endif // GNSS_HAL_TEST_H_ diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp new file mode 100644 index 0000000000..552cf1b5b1 --- /dev/null +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -0,0 +1,265 @@ +/* + * 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. + */ + +#define LOG_TAG "GnssHalTestCases" + +#include <VtsHalHidlTargetTestBase.h> +#include <gnss_hal_test.h> + +using android::hardware::hidl_string; +using android::hardware::hidl_vec; + +using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; +using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil; +using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; +using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; +using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; +using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil; +using IAGnss_2_0 = android::hardware::gnss::V2_0::IAGnss; +using IAGnss_1_0 = android::hardware::gnss::V1_0::IAGnss; +using IAGnssCallback_2_0 = android::hardware::gnss::V2_0::IAGnssCallback; +using android::hardware::gnss::V1_0::IGnssNi; +using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl; + +/* + * SetupTeardownCreateCleanup: + * Requests the gnss HAL then calls cleanup + * + * Empty test fixture to verify basic Setup & Teardown + */ +TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {} + +/* + * TestGnssMeasurementCallback: + * Gets the GnssMeasurementExtension and verify that it returns an actual extension. + */ +TEST_F(GnssHalTest, TestGnssMeasurementCallback) { + auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0(); + auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1(); + auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement(); + ASSERT_TRUE(gnssMeasurement_2_0.isOk() || gnssMeasurement_1_1.isOk() || + gnssMeasurement_1_0.isOk()); + if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) { + sp<IGnssMeasurement_2_0> iGnssMeas_2_0 = gnssMeasurement_2_0; + sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1; + sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0; + // At least one interface is non-null. + int numNonNull = (int)(iGnssMeas_2_0 != nullptr) + (int)(iGnssMeas_1_1 != nullptr) + + (int)(iGnssMeas_1_0 != nullptr); + ASSERT_TRUE(numNonNull >= 1); + } +} + +/* + * TestGnssConfigurationExtension: + * Gets the GnssConfigurationExtension and verifies that it returns an actual extension by + * calling a method. + * + * The GNSS HAL 2.0 implementation must support @2.0::IGnssConfiguration interface due to + * the deprecation of some methods in @1.0::IGnssConfiguration interface. + */ +TEST_F(GnssHalTest, TestGnssConfigurationExtension) { + auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); + ASSERT_TRUE(gnssConfiguration.isOk()); + sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration; + ASSERT_NE(iGnssConfiguration, nullptr); + + auto result = iGnssConfiguration->setEsExtensionSec(180); + ASSERT_TRUE(result.isOk()); + // Expected result can be true or false depending on whether HAL implementation supports + // detecting emergency sessions without involving the framework. +} + +/* + * TestGnssConfiguration_setSuplEs_Deprecation: + * Calls setSuplEs and verifies that it returns false. + */ +TEST_F(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) { + auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); + ASSERT_TRUE(gnssConfiguration.isOk()); + sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration; + ASSERT_NE(iGnssConfiguration, nullptr); + + auto result = iGnssConfiguration->setSuplEs(false); + ASSERT_TRUE(result.isOk()); + EXPECT_FALSE(result); +} + +/* + * TestGnssConfiguration_setGpsLock_Deprecation: + * Calls setGpsLock and verifies that it returns false. + */ +TEST_F(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) { + auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); + ASSERT_TRUE(gnssConfiguration.isOk()); + sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration; + ASSERT_NE(iGnssConfiguration, nullptr); + + auto result = iGnssConfiguration->setGpsLock(0); + ASSERT_TRUE(result.isOk()); + EXPECT_FALSE(result); +} + +/* + * TestAGnssRilExtension: + * Gets the AGnssRilExtension and verifies that it returns an actual extension. + * + * The GNSS HAL 2.0 implementation must support @2.0::IAGnssRil interface due to the deprecation + * of framework network API methods needed to support the @1.0::IAGnssRil interface. + * + * TODO (b/121287858): Enforce gnss@2.0 HAL package is supported on devices launched with Q or later + */ +TEST_F(GnssHalTest, TestAGnssRilExtension) { + auto agnssRil = gnss_hal_->getExtensionAGnssRil_2_0(); + ASSERT_TRUE(agnssRil.isOk()); + sp<IAGnssRil_2_0> iAGnssRil = agnssRil; + ASSERT_NE(iAGnssRil, nullptr); +} + +/* + * TestAGnssRil_UpdateNetworkState_2_0: + * 1. Updates GNSS HAL that a network has connected. + * 2. Updates GNSS HAL that network has disconnected. + */ +TEST_F(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) { + auto agnssRil = gnss_hal_->getExtensionAGnssRil_2_0(); + ASSERT_TRUE(agnssRil.isOk()); + sp<IAGnssRil_2_0> iAGnssRil = agnssRil; + ASSERT_NE(iAGnssRil, nullptr); + + // Update GNSS HAL that a network has connected. + IAGnssRil_2_0::NetworkAttributes networkAttributes = { + .networkHandle = static_cast<uint64_t>(7700664333), + .isConnected = true, + .capabilities = static_cast<uint16_t>(IAGnssRil_2_0::NetworkCapability::NOT_ROAMING), + .apn = "dummy-apn"}; + auto result = iAGnssRil->updateNetworkState_2_0(networkAttributes); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + // Update GNSS HAL that network has disconnected. + networkAttributes.isConnected = false; + result = iAGnssRil->updateNetworkState_2_0(networkAttributes); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +/* + * TestGnssMeasurementCodeType: + * Sets a GnssMeasurementCallback, waits for a measurement, and verifies the codeType is valid. + */ +TEST_F(GnssHalTest, TestGnssMeasurementCodeType) { + const int kFirstGnssMeasurementTimeoutSeconds = 10; + + auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0(); + if (!gnssMeasurement.isOk()) { + return; + } + + sp<IGnssMeasurement_2_0> iGnssMeasurement = gnssMeasurement; + if (iGnssMeasurement == nullptr) { + return; + } + + sp<IGnssMeasurementCallback_2_0> callback = new GnssMeasurementCallback(*this); + + auto result = iGnssMeasurement->setCallback_2_0(callback, /* enableFullTracking= */ true); + ASSERT_TRUE(result.isOk()); + EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS); + + wait(kFirstGnssMeasurementTimeoutSeconds); + EXPECT_EQ(measurement_called_count_, 1); + ASSERT_TRUE(last_measurement_.measurements.size() > 0); + for (auto measurement : last_measurement_.measurements) { + ASSERT_TRUE( + (int)measurement.codeType >= + (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::CODE_TYPE_A && + (int)measurement.codeType <= + (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::CODE_TYPE_CODELESS); + } + + iGnssMeasurement->close(); +} + +/* + * TestAGnssExtension: + * Gets the AGnssExtension and verifies that it supports @2.0::IAGnss interface by invoking + * a method. + * + * The GNSS HAL 2.0 implementation must support @2.0::IAGnss interface due to the deprecation + * of framework network API methods needed to support the @1.0::IAGnss interface. + * + * TODO (b/121287858): Enforce gnss@2.0 HAL package is supported on devices launched with Q or later + */ +TEST_F(GnssHalTest, TestAGnssExtension) { + // Verify IAGnss 2.0 is supported. + auto agnss = gnss_hal_->getExtensionAGnss_2_0(); + ASSERT_TRUE(agnss.isOk()); + sp<IAGnss_2_0> iAGnss = agnss; + ASSERT_NE(iAGnss, nullptr); + + // Set SUPL server host/port + auto result = iAGnss->setServer(IAGnssCallback_2_0::AGnssType::SUPL, "supl.google.com", 7275); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +/* + * TestAGnssExtension_1_0_Deprecation: + * Gets the @1.0::IAGnss extension and verifies that it is a nullptr. + * + * TODO (b/121287858): Enforce gnss@2.0 HAL package is supported on devices launched with Q or later + */ +TEST_F(GnssHalTest, TestAGnssExtension_1_0_Deprecation) { + // Verify IAGnss 1.0 is not supported. + auto agnss_1_0 = gnss_hal_->getExtensionAGnss(); + ASSERT_TRUE(!agnss_1_0.isOk() || ((sp<IAGnss_1_0>)agnss_1_0) == nullptr); +} + +/* + * TestGnssNiExtension_Deprecation: + * Gets the @1.0::IGnssNi extension and verifies that it is a nullptr. + * + * TODO (b/121287858): Enforce gnss@2.0 HAL package is supported on devices launched with Q or later + */ +TEST_F(GnssHalTest, TestGnssNiExtension_Deprecation) { + // Verify IGnssNi 1.0 is not supported. + auto gnssNi = gnss_hal_->getExtensionGnssNi(); + ASSERT_TRUE(!gnssNi.isOk() || ((sp<IGnssNi>)gnssNi) == nullptr); +} + +/* + * TestGnssVisibilityControlExtension: + * Gets the GnssVisibilityControlExtension and verifies that it supports the + * gnss.visibility_control@1.0::IGnssVisibilityControl interface by invoking a method. + * + * The GNSS HAL 2.0 implementation must support gnss.visibility_control@1.0::IGnssVisibilityControl. + * + * TODO (b/121287858): Enforce gnss@2.0 HAL package is supported on devices launched with Q or later + */ +TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) { + // Verify IGnssVisibilityControl is supported. + auto gnssVisibilityControl = gnss_hal_->getExtensionVisibilityControl(); + ASSERT_TRUE(gnssVisibilityControl.isOk()); + sp<IGnssVisibilityControl> iGnssVisibilityControl = gnssVisibilityControl; + ASSERT_NE(iGnssVisibilityControl, nullptr); + + // Set non-framework proxy apps. + hidl_vec<hidl_string> proxyApps{"ims.example.com", "mdt.example.com"}; + auto result = iGnssVisibilityControl->enableNfwLocationAccess(proxyApps); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} diff --git a/gnss/measurement_corrections/1.0/Android.bp b/gnss/measurement_corrections/1.0/Android.bp new file mode 100644 index 0000000000..237b008bba --- /dev/null +++ b/gnss/measurement_corrections/1.0/Android.bp @@ -0,0 +1,25 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.gnss.measurement_corrections@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IMeasurementCorrections.hal", + ], + interfaces: [ + "android.hardware.gnss@1.0", + "android.hidl.base@1.0", + ], + types: [ + "GnssSingleSatCorrectionFlags", + "MeasurementCorrections", + "ReflectingPlane", + "SingleSatCorrection", + ], + gen_java: true, +} + diff --git a/gnss/measurement_corrections/1.0/IMeasurementCorrections.hal b/gnss/measurement_corrections/1.0/IMeasurementCorrections.hal new file mode 100644 index 0000000000..934d10f64a --- /dev/null +++ b/gnss/measurement_corrections/1.0/IMeasurementCorrections.hal @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package android.hardware.gnss.measurement_corrections@1.0; + +/** + * Interface for measurement corrections support. + */ +interface IMeasurementCorrections { + + /** + * Injects measurement corrections to be used by the HAL to improve the GNSS location output. + * + * These are NOT to be used to adjust the IGnssMeasurementCallback output values - + * those remain raw, uncorrected measurements. + * + * In general, these are injected when conditions defined by the platform are met, such as when + * GNSS Location is being requested at a sufficiently high accuracy, based on the capabilities + * of the GNSS chipset as reported in the IGnssCallback. + * + * @param corrections The computed corrections to be used by the HAL. + * + * @return success Whether the HAL can accept & use these corrections. + */ + setCorrections(MeasurementCorrections corrections) generates (bool success); +}; diff --git a/gnss/measurement_corrections/1.0/types.hal b/gnss/measurement_corrections/1.0/types.hal new file mode 100644 index 0000000000..edf26bf7c0 --- /dev/null +++ b/gnss/measurement_corrections/1.0/types.hal @@ -0,0 +1,154 @@ +/* + * 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. + */ + +package android.hardware.gnss.measurement_corrections@1.0; + +import android.hardware.gnss@1.0::GnssConstellationType; + +/** + * A struct with measurement corrections for a single visible satellites + * + * The bit mask singleSatCorrectionFlags indicates which correction values are valid in the struct + */ +struct SingleSatCorrection { + + /** Contains GnssSingleSatCorrectionFlags bits. */ + bitfield<GnssSingleSatCorrectionFlags> singleSatCorrectionFlags; + + /** + * Defines the constellation of the given satellite. + */ + GnssConstellationType constellation; + + /** + * Satellite vehicle ID number, as defined in GnssSvInfo::svid + */ + uint16_t svid; + + /** + * Carrier frequency of the signal to be corrected, for example it can be the + * GPS center frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc. + * + * For a receiver with capabilities to track multiple frequencies for the same satellite, + * multiple corrections for the same satellite may be provided. + */ + float carrierFrequencyHz; + + /** + * The probability that the satellite is estimated to be in Line-of-Sight condition at the given + * location. + */ + float probSatIsLos; + + /** + * Excess path length to be subtracted from pseudorange before using it in calculating location. + * + * Note this value is NOT to be used to adjust the GnssMeasurementCallback outputs. + */ + float excessPathLengthMeters; + + /** Error estimate (1-sigma) for the Excess path length estimate */ + float excessPathLengthUncertaintyMeters; + + /** + * Defines the reflecting plane characteristics such as location and azimuth + * + * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane + * means either reflection planes serving is not supported or the satellite signal has gone + * through multiple reflections. + */ + ReflectingPlane reflectingPlane; +}; + +/** + * A struct containing a set of measurement corrections for all used GNSS satellites at the location + * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified + * toaGpsNanosecondsOfWeek + */ +struct MeasurementCorrections { + /** Represents latitude in degrees at which the corrections are computed.. */ + double latitudeDegrees; + + /** Represents longitude in degrees at which the corrections are computed.. */ + double longitudeDegrees; + + /** + * Represents altitude in meters above the WGS 84 reference ellipsoid at which the corrections + * are computed. + */ + double altitudeMeters; + + /** + * Represents the horizontal uncertainty (68% confidence) in meters on the device position at + * which the corrections are provided. + * + * This value is useful for example to judge how accurate the provided corrections are. + */ + double horizontalPositionUncertaintyMeters; + + /** + * Represents the vertical uncertainty (68% confidence) in meters on the device position at + * which the corrections are provided. + * + * This value is useful for example to judge how accurate the provided corrections are. + */ + double verticalPositionUncertaintyMeters; + + /** Time Of Applicability, GPS time of week in nanoseconds. */ + uint64_t toaGpsNanosecondsOfWeek; + + /** + * A set of SingleSatCorrection each containing measurement corrections for a satellite in view + */ + vec<SingleSatCorrection> satCorrections; +}; + +/** + * A struct containing the characteristics of the reflecting plane that the satellite signal has + * bounced from. + * + * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane + * means either reflection planes serving is not supported or the satellite signal has gone + * through multiple reflections. + */ +struct ReflectingPlane { + /** Represents latitude of the reflecting plane in degrees. */ + double latitudeDegrees; + + /** Represents longitude of the reflecting plane in degrees. */ + double longitudeDegrees; + + /** + * Represents altitude of the reflecting point in the plane in meters above the WGS 84 reference + * ellipsoid. + */ + double altitudeMeters; + + /** Represents azimuth clockwise from north of the reflecting plane in degrees. */ + double azimuthDegrees; +}; + +/** Bit mask to indicate which values are valid in a SingleSatCorrection object. */ +enum GnssSingleSatCorrectionFlags : uint16_t { + /** GnssSingleSatCorrectionFlags has valid satellite-is-line-of-sight-probability field. */ + HAS_SAT_IS_LOS_PROBABILITY = 0x0001, + /** GnssSingleSatCorrectionFlags has valid Excess Path Length field. */ + HAS_EXCESS_PATH_LENGTH = 0x0002, + /** GnssSingleSatCorrectionFlags has valid Excess Path Length Uncertainty field. */ + HAS_EXCESS_PATH_LENGTH_UNC = 0x0004, + /** GnssSingleSatCorrectionFlags has valid Reflecting Plane field. */ + HAS_REFLECTING_PLANE = 0x0008 +};
\ No newline at end of file diff --git a/gnss/visibility_control/1.0/Android.bp b/gnss/visibility_control/1.0/Android.bp new file mode 100644 index 0000000000..40a28c90ab --- /dev/null +++ b/gnss/visibility_control/1.0/Android.bp @@ -0,0 +1,18 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.gnss.visibility_control@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IGnssVisibilityControl.hal", + "IGnssVisibilityControlCallback.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + gen_java: true, +} + diff --git a/gnss/visibility_control/1.0/IGnssVisibilityControl.hal b/gnss/visibility_control/1.0/IGnssVisibilityControl.hal new file mode 100644 index 0000000000..914812723d --- /dev/null +++ b/gnss/visibility_control/1.0/IGnssVisibilityControl.hal @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package android.hardware.gnss.visibility_control@1.0; + +import IGnssVisibilityControlCallback; + +/** + * Represents the GNSS location reporting permissions and notification interface. + * + * This interface is used to tell the GNSS HAL implementation whether the framework user has + * granted permission to the GNSS HAL implementation to provide GNSS location information for + * non-framework (NFW), non-user initiated emergency use cases, and to notify the framework user + * of these GNSS location information deliveries. + * + * For user initiated emergency cases (and for the configured extended emergency session duration), + * the GNSS HAL implementation must serve the emergency location supporting network initiated + * location requests immediately irrespective of this permission settings. + * + * There is no separate need for the GNSS HAL implementation to monitor the global device location + * on/off setting. Permission to use GNSS for non-framework use cases is expressly controlled + * by the method enableNfwLocationAccess(). The framework monitors the location permission settings + * of the configured proxy applications(s), and device location settings, and calls the method + * enableNfwLocationAccess() whenever the user control proxy applications have, or do not have, + * location permission. The proxy applications are used to provide user visibility and control of + * location access by the non-framework on/off device entities they are representing. + * + * For device user visibility, the GNSS HAL implementation must call the method + * IGnssVisibilityControlCallback.nfwNotifyCb() whenever location request is rejected or + * location information is provided to non-framework entities (on or off device). This includes + * the network initiated location requests for user-initiated emergency use cases as well. + * + * The HAL implementations that support this interface must not report GNSS location, measurement, + * status, or other information that can be used to derive user location to any entity when not + * expressly authorized by this HAL. This includes all endpoints for location information + * off the device, including carriers, vendors, OEM and others directly or indirectly. + */ +interface IGnssVisibilityControl { + /** + * Enables/disables non-framework entity location access permission in the GNSS HAL. + * + * The framework will call this method to update GNSS HAL implementation every time the + * framework user, through the given proxy application(s) and/or device location settings, + * explicitly grants/revokes the location access permission for non-framework, non-user + * initiated emergency use cases. + * + * Whenever the user location information is delivered to non-framework entities, the HAL + * implementation must call the method IGnssVisibilityControlCallback.nfwNotifyCb() to notify + * the framework for user visibility. + * + * @param proxyApps Full list of package names of proxy Android applications representing + * the non-framework location access entities (on/off the device) for which the framework + * user has granted non-framework location access permission. The GNSS HAL implementation + * must provide location information only to non-framework entities represented by these + * proxy applications. + * + * The package name of the proxy Android application follows the standard Java language + * package naming format. For example, com.example.myapp. + * + * @return success True if the operation was successful. + */ + enableNfwLocationAccess(vec<string> proxyApps) generates (bool success); + + /** + * Registers the callback for HAL implementation to use. + * + * @param callback Handle to IGnssVisibilityControlCallback interface. + */ + setCallback(IGnssVisibilityControlCallback callback) generates (bool success); +};
\ No newline at end of file diff --git a/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal new file mode 100644 index 0000000000..5a582c23de --- /dev/null +++ b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package android.hardware.gnss.visibility_control@1.0; + +/** + * GNSS location reporting permissions and notification callback interface. + */ +interface IGnssVisibilityControlCallback { + /** + * Protocol stack that is requesting the non-framework location information. + */ + enum NfwProtocolStack : uint8_t { + /** Cellular control plane requests */ + CTRL_PLANE = 0, + /** All types of SUPL requests */ + SUPL = 1, + + /** All types of requests from IMS */ + IMS = 10, + /** All types of requests from SIM */ + SIM = 11, + + /** Requests from other protocol stacks */ + OTHER_PROTOCOL_STACK = 100 + }; + + /* + * Entity that is requesting/receiving the location information. + */ + enum NfwRequestor : uint8_t { + /** Wireless service provider */ + CARRIER = 0, + + /** Device manufacturer */ + OEM = 10, + /** Modem chipset vendor */ + MODEM_CHIPSET_VENDOR = 11, + /** GNSS chipset vendor */ + GNSS_CHIPSET_VENDOR = 12, + /** Other chipset vendor */ + OTHER_CHIPSET_VENDOR = 13, + + /** Automobile client */ + AUTOMOBILE_CLIENT = 20, + + /** Other sources */ + OTHER_REQUESTOR = 100 + }; + + /** + * GNSS response type for non-framework location requests. + */ + enum NfwResponseType : uint8_t { + /** Request rejected because framework has not given permission for this use case */ + REJECTED = 0, + + /** Request accepted but could not provide location because of a failure */ + ACCEPTED_NO_LOCATION_PROVIDED = 1, + + /** Request accepted and location provided */ + ACCEPTED_LOCATION_PROVIDED = 2, + }; + + /** + * Represents a non-framework location information request/response notification. + */ + struct NfwNotification { + /** + * Package name of the Android proxy application representing the non-framework + * entity that requested location. Set to empty string if unknown. + */ + string proxyAppPackageName; + + /** Protocol stack that initiated the non-framework location request. */ + NfwProtocolStack protocolStack; + + /** + * Name of the protocol stack if protocolStack field is set to OTHER_PROTOCOL_STACK. + * Otherwise, set to empty string. + * + * This field is opaque to the framework and used for logging purposes. + */ + string otherProtocolStackName; + + /** Source initiating/receiving the location information. */ + NfwRequestor requestor; + + /** + * Identity of the endpoint receiving the location information. For example, carrier + * name, OEM name, SUPL SLP/E-SLP FQDN, chipset vendor name, etc. + * + * This field is opaque to the framework and used for logging purposes. + */ + string requestorId; + + /** Indicates whether location information was provided for this request. */ + NfwResponseType responseType; + + /** Is the device in user initiated emergency session. */ + bool inEmergencyMode; + + /** Is cached location provided */ + bool isCachedLocation; + }; + + /** + * Callback to report a non-framework delivered location. + * + * The GNSS HAL implementation must call this method to notify the framework whenever + * a non-framework location request is made to the GNSS HAL. + * + * Non-framework entities like low power sensor hubs that request location from GNSS and + * only pass location information through Android framework controls are exempt from this + * power-spending reporting. However, low power sensor hubs or other chipsets which may send + * the location information to anywhere other than Android framework (which provides user + * visibility and control), must report location information use through this API whenever + * location information (or events driven by that location such as "home" location detection) + * leaves the domain of that low power chipset. + * + * To avoid overly spamming the framework, high speed location reporting of the exact same + * type may be throttled to report location at a lower rate than the actual report rate, as + * long as the location is reported with a latency of no more than the larger of 5 seconds, + * or the next the Android processor awake time. For example, if an Automotive client is + * getting location information from the GNSS location system at 20Hz, this method may be + * called at 1Hz. As another example, if a low power processor is getting location from the + * GNSS chipset, and the Android processor is asleep, the notification to the Android HAL may + * be delayed until the next wake of the Android processor. + * + * @param notification Non-framework delivered location request/response description. + */ + nfwNotifyCb(NfwNotification notification); + + /** + * Tells if the device is currently in an emergency session. + * + * Emergency session is defined as the device being actively in a user initiated emergency + * call or in post emergency call extension time period. + * + * If the GNSS HAL implementation cannot determine if the device is in emergency session + * mode, it must call this method to confirm that the device is in emergency session before + * serving network initiated emergency SUPL and Control Plane location requests. + * + * @return success True if the framework determines that the device is in emergency session. + */ + isInEmergencySession() generates (bool success); +};
\ No newline at end of file diff --git a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc index 6eee71f6e7..a2a881a8f4 100644 --- a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc +++ b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc @@ -1,5 +1,6 @@ service vendor.gralloc-2-0 /vendor/bin/hw/android.hardware.graphics.allocator@2.0-service class hal animation + interface android.hardware.graphics.allocator@2.0::IAllocator default user system group graphics drmrpc capabilities SYS_NICE diff --git a/graphics/allocator/3.0/Android.bp b/graphics/allocator/3.0/Android.bp new file mode 100644 index 0000000000..fa3e2cecc7 --- /dev/null +++ b/graphics/allocator/3.0/Android.bp @@ -0,0 +1,21 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.graphics.allocator@3.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IAllocator.hal", + ], + interfaces: [ + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hardware.graphics.mapper@3.0", + "android.hidl.base@1.0", + ], + gen_java: false, +} + diff --git a/graphics/allocator/3.0/IAllocator.hal b/graphics/allocator/3.0/IAllocator.hal new file mode 100644 index 0000000000..34b08e7c61 --- /dev/null +++ b/graphics/allocator/3.0/IAllocator.hal @@ -0,0 +1,55 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.allocator@3.0; + +import android.hardware.graphics.mapper@3.0; + +interface IAllocator { + /** + * Retrieves implementation-defined debug information, which will be + * displayed during, for example, `dumpsys SurfaceFlinger`. + * + * @return debugInfo is a string of debug information. + */ + dumpDebugInfo() generates (string debugInfo); + + /** + * Allocates buffers with the properties specified by the descriptor. + * + * Allocations should be optimized for usage bits provided in the + * descriptor. + * + * @param descriptor Properties of the buffers to allocate. This must be + * obtained from IMapper::createDescriptor(). + * @param count The number of buffers to allocate. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_DESCRIPTOR` if the descriptor is invalid. + * - `NO_RESOURCES` if the allocation cannot be fulfilled at this time. + * - `UNSUPPORTED` if any of the properties encoded in the descriptor + * are not supported. + * @return stride The number of pixels between two consecutive rows of + * an allocated buffer, when the concept of consecutive rows is defined. + * Otherwise, it has no meaning. + * @return buffers Array of raw handles to the allocated buffers. + */ + allocate(BufferDescriptor descriptor, uint32_t count) + generates (Error error, + uint32_t stride, + vec<handle> buffers); +}; + diff --git a/graphics/bufferqueue/2.0/Android.bp b/graphics/bufferqueue/2.0/Android.bp new file mode 100644 index 0000000000..5385f2806a --- /dev/null +++ b/graphics/bufferqueue/2.0/Android.bp @@ -0,0 +1,27 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.graphics.bufferqueue@2.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IGraphicBufferProducer.hal", + "IProducerListener.hal", + ], + interfaces: [ + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hidl.base@1.0", + ], + types: [ + "ConnectionType", + "SlotIndex", + "Status", + ], + gen_java: true, +} + diff --git a/graphics/bufferqueue/2.0/IGraphicBufferProducer.hal b/graphics/bufferqueue/2.0/IGraphicBufferProducer.hal new file mode 100644 index 0000000000..734c0b4310 --- /dev/null +++ b/graphics/bufferqueue/2.0/IGraphicBufferProducer.hal @@ -0,0 +1,648 @@ +/* + * 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. + */ + +package android.hardware.graphics.bufferqueue@2.0; + +import android.hardware.graphics.common@1.2::HardwareBuffer; +import android.hardware.graphics.common@1.2::HardwareBufferDescription; +import android.hardware.graphics.common@1.2::Rect; + +import IProducerListener; + +/** + * Ref: frameworks/native/include/gui/IGraphicBufferProducer.h: + * IGraphicBufferProducer + * This is a wrapper/wrapped HAL interface for the actual binder interface. + */ +interface IGraphicBufferProducer { + /** + * Sets the maximum number of buffers that can be dequeued at one time. If + * this method succeeds, any new buffer slots shall be both unallocated and + * owned by the buffer queue, i.e., they are not owned by the producer or + * the consumer. Calling this may cause some buffer slots to be emptied. If + * the caller is caching the contents of the buffer slots, it must empty + * that cache after calling this method. + * + * @p maxDequeuedBuffers must not be less than the number of currently + * dequeued buffer slots; otherwise, the returned @p status shall be + * `BAD_VALUE`. + * + * @p maxDequeuedBuffers must be at least 1 (inclusive), but at most + * (`NUM_BUFFER_SLOTS` - the minimum undequeued buffer count) (exclusive). + * The minimum undequeued buffer count can be obtained by calling + * `query(ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS)`. + * + * Before calling setMaxDequeuedBufferCount(), the caller must make sure + * that + * - @p maxDequeuedBuffers is greater than or equal to 1. + * - @p maxDequeuedBuffers is greater than or equal to the number of + * currently dequeued buffer slots. + * If any of these conditions do not hold, or if the request to set the new + * maximum number of dequeued buffers cannot be accomplished for any other + * reasons, `BAD_VALUE` shall be returned in @p status. + * + * @param maxDequeuedBuffers The desired number of buffers that can be + * dequeued at one time. + * @return status Status of the call. + */ + setMaxDequeuedBufferCount( + int32_t maxDequeuedBuffers + ) generates ( + Status status + ); + + /** + * Assigns a newly created buffer to the given slot index. The client is + * expected to mirror the slot-to-buffer mapping so that it is not necessary + * to transfer a `HardwareBuffer` object for every dequeue operation. + * + * If @p slot is not a valid slot index corresponding to a dequeued buffer, + * the call shall fail with @p status set to `BAD_VALUE`. + * + * @param slot Slot index. + * @return status Status of the call. + * @return buffer New buffer associated to the given slot index. + */ + requestBuffer( + int32_t slot + ) generates ( + Status status, + HardwareBuffer buffer + ); + + /** + * Sets the async flag: whether the producer intends to asynchronously queue + * buffers without blocking. Typically this is used for triple-buffering + * and/or when the swap interval is set to zero. + * + * Enabling async mode may internally allocate an additional buffer to allow + * for the asynchronous behavior. If it is not enabled, queue/dequeue calls + * may block. + * + * Changing the async flag may affect the number of available slots. If the + * adjustment to the number of slots cannot be made, @p status shall be set + * to `BAD_VALUE`. + * + * @param async True if the asynchronous operation is desired; false + * otherwise. + * @return status Status of the call. + */ + setAsyncMode( + bool async + ) generates ( + Status status + ); + + /** + * Input data for dequeueBuffer() specifying desired attributes of a buffer + * to dequeue. + * + * This structure contains 4 fields from + * +llndk libnativewindow#AHardwareBuffer_Desc. + * + * The `width` and `height` parameters must be no greater than the minimum + * of `GL_MAX_VIEWPORT_DIMS` and `GL_MAX_TEXTURE_SIZE` (see: + * glGetIntegerv()). An error due to invalid dimensions may not be reported + * until updateTexImage() is called. + * + * If `width` and `height` are both zero, the default dimensions shall be + * used. If only one of `width` and `height` is zero, dequeueBuffer() shall + * return `BAD_VALUE` in `status`. + * + * If `format` is zero, the default format shall be used. + * + * `usage` shall be merged with the usage flags set from the consumer side. + * + * @sa +llndk libnativewindow#AHardwareBuffer_Desc. + */ + struct DequeueBufferInput { + uint32_t width; + uint32_t height; + uint32_t format; + uint64_t usage; + }; + + /** + * Output data for dequeueBuffer(). + * + * A `DequeueBufferOutput` object returned from dequeueBuffer() shall be + * valid if and only if `status` returned from the same call is `OK`. + */ + struct DequeueBufferOutput { + /** + * The number of frames that have elapsed since the buffer was last + * queued. + */ + uint64_t bufferAge; + /** + * Whether the client must call requestBuffer(). + */ + bool bufferNeedsReallocation; + /** + * Whether the client must discard the mirrored slot-to-buffer + * mapping. + */ + bool releaseAllBuffers; + /** + * Fence associated with the buffer. + * + * If this is an empty fence, the buffer may be written immediately; + * otherwise, the buffer must not be written to until the fence signals. + */ + Fence fence; + }; + + /** + * Requests a new buffer slot for the client to use. Ownership of the slot + * is transfered to the client, meaning that the server shall not use the + * contents of the buffer associated with that slot. + * + * On success, @p status shall be `OK`, and @p output shall contain valid + * information of the call. Otherwise, the contents of @p output are + * meaningless. + * + * The slot index returned in @p slot may or may not contain a buffer + * (client-side). If the slot is empty, the client must call + * requestBuffer() to assign a new buffer to that slot. + * + * Once the client is done filling this buffer, it is expected to transfer + * buffer ownership back to the server with either cancelBuffer() on + * the dequeued slot or to fill in the contents of its associated buffer + * contents and call queueBuffer(). + * + * If dequeueBuffer() returns with `output.releaseAllBuffers` set to `true`, + * the client is expected to release all of the mirrored slot-to-buffer + * mappings. + * + * If dequeueBuffer() returns with `output.bufferNeedsReallocation` set to + * `true`, the client is expected to call requestBuffer() immediately. + * + * The returned `output.fence` shall be updated to hold the fence associated + * with the buffer. The contents of the buffer must not be overwritten until + * the fence signals. If the fence is an empty fence, the buffer may be + * written immediately. + * + * This call shall block until a buffer is available to be dequeued. If + * both the producer and consumer are controlled by the app, then this call + * can never block and shall return `WOULD_BLOCK` in @p status if no buffer + * is available. + * + * If a dequeue operation shall cause certain conditions on the number of + * buffers to be violated (such as the maximum number of dequeued buffers), + * @p status shall be set to `INVALID_OPERATION` to indicate failure. + * + * If a dequeue operation cannot be completed within the time period + * previously set by setDequeueTimeout(), the return @p status shall + * `TIMED_OUT`. + * + * See @ref DequeueBufferInput for more information on the @p input + * parameter. + * + * @param input See #DequeueBufferInput for more information. + * @param status Status of the call. + * @param slot Slot index. + * @param output See #DequeueBufferOutput for more information. + * + * @sa queueBuffer(), requestBuffer(). + */ + dequeueBuffer( + DequeueBufferInput input + ) generates ( + Status status, + int32_t slot, + DequeueBufferOutput output + ); + + /** + * Attempts to remove all ownership of the buffer in the given slot from the + * buffer queue. + * + * If this call succeeds, the slot shall be freed, and there shall be no way + * to obtain the buffer from this interface. The freed slot shall remain + * unallocated until either it is selected to hold a freshly allocated + * buffer in dequeueBuffer() or a buffer is attached to the slot. The buffer + * must have already been dequeued, and the caller must already possesses + * the buffer (i.e., must have called requestBuffer()). + * + * @param slot Slot index. + * @return status Status of the call. + */ + detachBuffer( + int32_t slot + ) generates ( + Status status + ); + + /** + * Dequeues a buffer slot, requests the buffer associated to the slot, and + * detaches it from the buffer queue. This is equivalent to calling + * dequeueBuffer(), requestBuffer(), and detachBuffer() in succession except + * for two things: + * 1. It is unnecessary to provide a #DequeueBufferInput object. + * 2. The call shall not block, since if it cannot find an appropriate + * buffer to return, it shall return an error instead. + * + * Only slots that are free but still contain a buffer shall be considered, + * and the oldest of those shall be returned. @p buffer is equivalent to the + * buffer that would be returned from requestBuffer(), and @p fence is + * equivalent to the fence that would be returned from dequeueBuffer(). + * + * @return status Status of the call. + * @return buffer Buffer just released from the buffer queue. + * @return fence Fence associated to @p buffer. + * + * @sa dequeueBuffer(), requestBuffer(), detachBuffer(). + */ + detachNextBuffer( + ) generates ( + Status status, + HardwareBuffer buffer, + Fence fence + ); + + /** + * Attempts to transfer ownership of a buffer to the buffer queue. + * + * If this call succeeds, it shall be as if this buffer was dequeued from the + * returned slot index. As such, this call shall fail if attaching this + * buffer would cause too many buffers to be simultaneously dequeued. + * + * If the returned @p releaseAllBuffers is `true`, the caller is expected to + * release all of the mirrored slot-to-buffer mappings. + * + * See dequeueBuffer() for conditions that may cause the call to fail. + * + * @param buffer Buffer to attach to the buffer queue. + * @return status Status of the call. + * @return slot Slot index assigned to @p buffer. + * @return releaseAllBuffers Whether the caller is expected to release all + * of the mirrored slot-to-buffer mappings. + * + * @sa dequeueBuffer(). + */ + attachBuffer( + HardwareBuffer buffer + ) generates ( + Status status, + int32_t slot, + bool releaseAllBuffers + ); + + struct QueueBufferInput { + /** + * Timestamp in nanoseconds. + */ + int64_t timestamp; + /** + * Whether the timestamp was synthesized at queue time. + */ + bool isAutoTimestamp; + /** + * Dataspace of the contents. + * + * @sa +ndk libnativewindow#ADataSpace. + */ + int32_t dataSpace; + /** + * Crop rectangle that is used as a hint to the consumer. + */ + Rect crop; + /** + * Transformation flags. + * + * @sa +ndk libnativewindow#ANativeWindowTransform. + */ + int32_t transform; + /** + * The sticky transform set in Surface (only used by the LEGACY camera + * mode). + * + * @sa +ndk libnativewindow#ANativeWindowTransform. + */ + int32_t stickyTransform; + /** + * Fence that the consumer must wait on before reading the buffer. An + * empty fence indicates that the buffer is ready immediately. + */ + Fence fence; + /** + * List of rectangular pieces covering the damage region. + */ + vec<Rect> surfaceDamage; + }; + + /** + * Information about the queued buffer. `QueueBufferOutput` is used in both + * queueBuffer() and connect(). + */ + struct QueueBufferOutput { + /** + * Default width of a buffer in the buffer queue. + */ + uint32_t width; + /** + * Default height of a buffer in the buffer queue. + */ + uint32_t height; + /** + * The transform hint of the buffer queue. + * + * @sa +ndk libnativewindow#ANativeWindowTransform. + */ + int32_t transformHint; + /** + * The number of pending buffers in the buffer queue. If this is + * returned from queueBuffer(), the number shall include the buffer that + * has just been queued. + */ + uint32_t numPendingBuffers; + /** + * The frame number of the next frame. The buffer queue maintains this + * number and makes sure that it is increasing for every successful + * queueBuffer() call. + */ + uint64_t nextFrameNumber; + /** + * After a successful queueBuffer() call, #bufferReplaced shall be set to + * true if the queued buffer replaced a previously queued buffer that + * has not been consumed. + */ + bool bufferReplaced; + }; + + /** + * Indicates that the client has finished filling in the contents of the + * buffer associated with slot and transfers ownership of that slot back to + * the buffer queue. + * + * @p status may be set to `BAD_VALUE` if any of the following conditions + * hold: + * - The buffer queue is operating in the asynchronous mode, and the + * buffer count was smaller than the maximum number of buffers that can + * be allocated at once. + * - @p slot is an invalid slot index, i.e., the slot is not owned by the + * client by previously calling dequeueBuffer(), requestBuffer() or + * attachBuffer(). + * - The crop rectangle is not contained in the buffer. + * + * Upon success, the output shall be filled with meaningful values + * (refer to the documentation of @ref QueueBufferOutput). + * + * @param slot Slot index. + * @param input See @ref QueueBufferInput. + * @return status Status of the call. + * @return output See @ref QueueBufferOutput. + * + * @sa #QueueBufferInput, #QueueBufferOutput, dequeueBuffer(). + */ + queueBuffer( + int32_t slot, + QueueBufferInput input + ) generates ( + Status status, + QueueBufferOutput output + ); + + /** + * Indicates that the client does not wish to fill in the buffer associated + * with the slot and transfers ownership of the slot back to the server. The + * buffer is not queued for use by the consumer. + * + * If @p fence is not an empty fence, the buffer shall not be overwritten + * until the fence signals. @p fence is usually obtained from + * dequeueBuffer(). + * + * @param slot Slot index. + * @param fence Fence for the canceled buffer. + * @return status Status of the call. + */ + cancelBuffer( + int32_t slot, + Fence fence + ) generates ( + Status status + ); + + /** + * Retrieves information for this surface. + * + * @param what What to query. @p what must be one of the values in + * +llndk libnativewindow#ANativeWindowQuery. + * @return status Status of the call. + * @return value The value queried. The set of possible values depends on + * the value of @p what. + * + * @sa +llndk libnativewindow#ANativeWindowQuery. + */ + query( + int32_t what + ) generates ( + int32_t result, + int32_t value + ); + + /** + * Attempts to connect the client as a producer of the buffer queue. + * This method must be called before any other methods in this interface. + * + * If the buffer queue does not have a consumer ready (connected), the + * return @p status shall be `NO_INIT`. + * + * If any of the following conditions hold, the error code `BAD_VALUE` shall + * be reported in @p status: + * - The producer is already connected. + * - The number of available slots cannot be adjusted to accommodate the + * supplied value of @p producerControlledByApp. + * + * @param listener An optional callback object that can be provided if the + * client wants to be notified when the consumer releases a buffer back + * to the buffer queue. + * @param api How the client shall write to buffers. + * @param producerControlledByApp `true` if the producer is hosted by an + * untrusted process (typically application-forked processes). If both + * the producer and the consumer are controlled by app, the buffer queue + * shall operate in the asynchronous mode regardless of the async flag + * set by setAsyncMode(). + * @return status Status of the call. + * @return output See #QueueBufferOutput for more information. + * + * @sa #QueueBufferOutput, disconnect(), setAsyncMode(). + */ + connect( + IProducerListener listener, + ConnectionType api, + bool producerControlledByApp + ) generates ( + Status status, + QueueBufferOutput output + ); + + /** + * Attempts to disconnect the client from the producer end of the buffer + * queue. + * + * Calling this method shall cause any subsequent calls to other + * @ref IGraphicBufferProducer methods apart from connect() to fail. + * A successful connect() call afterwards may allow other methods to succeed + * again. + * + * Disconnecting from an abandoned buffer queue is legal and is considered a + * no-op. + * + * @param api The type of connection to disconnect. Supplying the value of + * `CURRENTLY_CONNECTED` to @p api has the same effect as supplying the + * current connection type. If the producer end is not connected, + * supplying `CURRENTLY_CONNECTED` shall result in a successful no-op + * call. + * @return status Status of the call. + * + * @sa connect(). + */ + disconnect( + ConnectionType api + ) generates ( + Status status + ); + + /** + * Allocates buffers based on the given dimensions, format and usage. + * + * This function shall allocate up to the maximum number of buffers + * permitted by the current buffer queue configuration. It shall use the + * given format, dimensions, and usage bits, which are interpreted in the + * same way as for dequeueBuffer(), and the async flag must be set the same + * way as for dequeueBuffer() to ensure that the correct number of buffers + * are allocated. This is most useful to avoid an allocation delay during + * dequeueBuffer(). If there are already the maximum number of buffers + * allocated, this function has no effect. + * + * A value of 0 in @p width, @p height or @p format indicates that the + * buffer queue can pick the default value. + * + * @param width Width of buffers to allocate. + * @param height Height of buffers to allocate. + * @param format Format of buffers to allocate. + * @param usage Usage of bufferes to allocate. + * @return status Status of the call. + */ + allocateBuffers( + uint32_t width, + uint32_t height, + uint32_t format, + uint64_t usage + ) generates ( + Status status + ); + + /** + * Sets whether dequeueBuffer() is allowed to allocate new buffers. + * + * Normally dequeueBuffer() does not discriminate between free slots which + * already have an allocated buffer and those which do not, and shall + * allocate a new buffer if the slot doesn't have a buffer or if the slot's + * buffer doesn't match the requested size, format, or usage. This method + * allows the producer to restrict the eligible slots to those which already + * have an allocated buffer of the correct size, format, and usage. If no + * eligible slot is available, dequeueBuffer() shall block or return an + * error. + * + * @param allow Whether to allow new buffers to be allocated in + * dequeueBuffer(). + * @return status Status of the call. + */ + allowAllocation( + bool allow + ) generates ( + Status status + ); + + /** + * Sets the current generation number of the buffer queue. + * + * This generation number shall be inserted into any buffers allocated by the + * buffer queue, and any attempts to attach a buffer with a different + * generation number shall fail. Buffers already in the queue are not + * affected and shall retain their current generation number. The generation + * number defaults to 0, i.e., buffers allocated before the first call to + * setGenerationNumber() shall be given 0 as their generation numbers. + * + * @param generationNumber New generation number. The client must make sure + * that @p generationNumber is different from the previous generation + * number if it wants to deprecate old buffers. + * @return status Status of the call. + */ + setGenerationNumber( + uint32_t generationNumber + ) generates ( + Status status + ); + + /** + * Sets how long dequeueBuffer() shall wait for a buffer to become available + * before returning an error `TIMED_OUT`. + * + * This timeout also affects the attachBuffer() call, which shall block if + * there is not a free slot available into which the attached buffer can be + * placed. + * + * By default, the buffer queue shall wait forever, which is equivalent to + * setting @p timeoutNs equal to any negative number (such as `-1`). If + * @p timeoutNs is non-negative, setDequeueTimeout() shall disable + * non-blocking mode and its corresponding spare buffer (which is used to + * ensure a buffer is always available). + * + * Changing the dequeue timeout may affect the number of buffers. (See + * setAsyncMode().) If the adjustment to the number of buffers inside the + * buffer queue is not feasible, @p status shall be set to `BAD_VALUE`. + * + * @param timeoutNs Amount of time dequeueBuffer() is allowed to block + * before returning `TIMED_OUT`. If @p timeoutNs is negative, + * dequeueBuffer() shall not be able to return `TIMED_OUT`. Instead, it + * may block forever or return `WOULD_BLOCK`. + * @return status Status of the call. + * + * @sa dequeueBuffer(), setAsyncMode(), query(). + */ + setDequeueTimeout( + int64_t timeoutNs + ) generates ( + Status status + ); + + /** + * Returns a unique id for this buffer queue. + * + * @return id System-wide unique id of the buffer queue. + */ + getUniqueId( + ) generates ( + uint64_t id + ); + + /** + * Returns the name of the connected consumer. + * + * \note This is used for debugging only. + * + * @return name Name of the consumer. + */ + getConsumerName( + ) generates ( + string name + ); + +}; + diff --git a/audio/effect/4.0/default/AcousticEchoCancelerEffect.cpp b/graphics/bufferqueue/2.0/IProducerListener.hal index 242740e582..bc478ed7c8 100644 --- a/audio/effect/4.0/default/AcousticEchoCancelerEffect.cpp +++ b/graphics/bufferqueue/2.0/IProducerListener.hal @@ -14,10 +14,20 @@ * limitations under the License. */ -#define LOG_TAG "AEC_Effect_HAL" +package android.hardware.graphics.bufferqueue@2.0; -#include "AcousticEchoCancelerEffect.h" +/** + * Listener interface. + */ +interface IProducerListener { + /** + * Notifies the listener when buffers are released. + * + * This function is usually called by the consumer. + * + * @param count The number of buffers released (since the last call to + * onBufferReleased()). + */ + oneway onBuffersReleased(uint32_t count); +}; -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/AcousticEchoCancelerEffect.impl.h> -#undef AUDIO_HAL_VERSION diff --git a/graphics/bufferqueue/2.0/types.hal b/graphics/bufferqueue/2.0/types.hal new file mode 100644 index 0000000000..f6bc2d960c --- /dev/null +++ b/graphics/bufferqueue/2.0/types.hal @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package android.hardware.graphics.bufferqueue@2.0; + +/** + * Possible return values from a function call. + */ +enum Status : int32_t { + /** + * The call succeeds. + */ + OK = 0, + /** + * The function fails allocate memory. + */ + NO_MEMORY = -12, + /** + * The buffer queue has been abandoned, no consumer is connected, or no + * producer is connected at the time of the call. + */ + NO_INIT = -19, + /** + * Some of the provided input arguments are invalid. + */ + BAD_VALUE = -22, + /** + * An unexpected death of some object prevents the operation from + * continuing. + * + * @note This status value is different from a transaction failure, which + * should be detected by isOk(). + */ + DEAD_OBJECT = -32, + /** + * The internal state of the buffer queue does not permit the operation. + */ + INVALID_OPERATION = -38, + /** + * The call fails to finish within the specified time limit. + */ + TIMED_OUT = -110, + /** + * The buffer queue is operating in a non-blocking mode, but the call cannot + * be completed without blocking. + */ + WOULD_BLOCK = 0xfffffffb, + /** + * The call fails because of a reason not listed above. + */ + UNKNOWN_ERROR = 0xffffffff, +}; + +/** + * Special values for a slot index. + */ +enum SlotIndex : int32_t { + /** + * Invalid/unspecified slot index. This may be returned from a function that + * returns a slot index if the call is unsuccessful. + */ + INVALID = -1, + UNSPECIFIED = -1, +}; + +/** + * An "empty" fence can be an empty handle (containing no fds and no ints) or a + * fence with one fd that is equal to -1 and no ints. + * + * A valid fence is an empty fence or a native handle with exactly one fd and no + * ints. + */ +typedef handle Fence; + +/** + * How buffers shall be produced. One of these values must be provided in a call + * to IGraphicBufferProducer::connect() and + * IGraphicBufferProducer::disconnect(). + */ +enum ConnectionType : int32_t { + /** + * This value can be used only as an input to + * IGraphicBufferProducer::disconnect(). + */ + CURRENTLY_CONNECTED = -1, + /** + * Buffers shall be queued by EGL via `eglSwapBuffers()` after being filled + * using OpenGL ES. + */ + EGL = 1, + /** + * Buffers shall be queued after being filled using the CPU. + */ + CPU = 2, + /** + * Buffers shall be queued by Stagefright after being filled by a video + * decoder. The video decoder can either be a software or hardware decoder. + */ + MEDIA = 3, + /** + * Buffers shall be queued by the camera HAL. + */ + CAMERA = 4, +}; + + diff --git a/graphics/common/1.2/Android.bp b/graphics/common/1.2/Android.bp new file mode 100644 index 0000000000..a3ebdbf219 --- /dev/null +++ b/graphics/common/1.2/Android.bp @@ -0,0 +1,25 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.graphics.common@1.2", + root: "android.hardware", + vndk: { + enabled: true, + support_system_process: true, + }, + srcs: [ + "types.hal", + ], + interfaces: [ + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + ], + types: [ + "ColorMode", + "Dataspace", + "HardwareBuffer", + ], + gen_java: true, + gen_java_constants: true, +} + diff --git a/graphics/common/1.2/types.hal b/graphics/common/1.2/types.hal new file mode 100644 index 0000000000..3da6176342 --- /dev/null +++ b/graphics/common/1.2/types.hal @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package android.hardware.graphics.common@1.2; + +import @1.0::Hdr; +import @1.1::BufferUsage; +import @1.1::ColorMode; +import @1.1::Dataspace; +import @1.1::PixelFormat; + +/** + * Hdr + */ +@export(name="android_hdr_v1_2_t", value_prefix="HAL_HDR_", + export_parent="false") +enum Hdr : @1.0::Hdr { + HDR10_PLUS = 4, +}; + +@export(name="android_dataspace_v1_2_t", value_prefix="HAL_DATASPACE_", + export_parent="false") +enum Dataspace : @1.1::Dataspace { + /** + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, sRGB transfer and BT2020 standard + */ + DISPLAY_BT2020 = STANDARD_BT2020 | TRANSFER_SRGB | RANGE_FULL, + + /** + * ISO 16684-1:2011(E) + * + * Embedded depth metadata following the dynamic depth specification. + */ + DYNAMIC_DEPTH = 0x1002, +}; + +enum ColorMode : @1.1::ColorMode { + /** + * DISPLAY_BT2020 corresponds with display settings that implement the ITU-R + * Recommendation BT.2020 / Rec. 2020 for UHDTV, but specifies an SRGB + * transfer function. + * + * Primaries: + * x y + * green 0.170 0.797 + * blue 0.131 0.046 + * red 0.708 0.292 + * white (D65) 0.3127 0.3290 + * + * Transfer Function is sRGB + */ + DISPLAY_BT2020 = 13, +}; + +/** + * HIDL counterpart of `AHardwareBuffer_Desc`. + * + * An `AHardwareBuffer_Desc` object can be converted to and from a + * `HardwareBufferDescription` object by `memcpy()`. + * + * @sa +ndk libnativewindow#AHardwareBuffer_Desc. + */ +typedef uint32_t[10] HardwareBufferDescription; + +/** + * HIDL counterpart of `AHardwareBuffer`. + * + * AHardwareBuffer_createFromHandle() can be used to convert a `HardwareBuffer` + * object to an `AHardwareBuffer` object. + * + * Conversely, AHardwareBuffer_getNativeHandle() can be used to extract a native + * handle from an `AHardwareBuffer` object. Paired with `AHardwareBuffer_Desc`, + * AHardwareBuffer_getNativeHandle() can be used to convert between + * `HardwareBuffer` and `AHardwareBuffer`. + * + * @sa +ndk libnativewindow#AHardwareBuffer". + */ +struct HardwareBuffer { + HardwareBufferDescription description; + handle nativeHandle; +}; + +/** + * HIDL counterpart of `ARect`. + * + * @sa +ndk libarect_headers#ARect. + */ +typedef int32_t[4] Rect; + +/** + * Pixel formats for graphics buffers. + */ +@export(name="android_pixel_format_v1_2_t", value_prefix="HAL_PIXEL_FORMAT_", + export_parent="false") +enum PixelFormat : @1.1::PixelFormat { + /** + * 24-bit format that has 8-bit H, S, and V components, in that order, + * from the lowest memory address to the highest memory address. + * + * The component values are unsigned normalized to the range [0, 1], whose + * interpretation is defined by the dataspace. + */ + HSV_888 = 0x37, +}; diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp index 2de1e3caa4..63accffef7 100644 --- a/graphics/composer/2.1/default/Android.bp +++ b/graphics/composer/2.1/default/Android.bp @@ -10,6 +10,7 @@ cc_library_shared { shared_libs: [ "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "libbase", "libcutils", "libfmq", diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h index 2742207132..ebac2e0f58 100644 --- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h +++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h @@ -534,6 +534,9 @@ class CommandWriterBase { static constexpr uint16_t kMaxLength = std::numeric_limits<uint16_t>::max(); + std::unique_ptr<uint32_t[]> mData; + uint32_t mDataWritten; + private: void growData(uint32_t grow) { uint32_t newWritten = mDataWritten + grow; @@ -558,9 +561,6 @@ class CommandWriterBase { } uint32_t mDataMaxSize; - std::unique_ptr<uint32_t[]> mData; - - uint32_t mDataWritten; // end offset of the current command uint32_t mCommandEnd; @@ -746,13 +746,14 @@ class CommandReaderBase { return fd; } + std::unique_ptr<uint32_t[]> mData; + uint32_t mDataRead; + private: std::unique_ptr<CommandQueueType> mQueue; uint32_t mDataMaxSize; - std::unique_ptr<uint32_t[]> mData; uint32_t mDataSize; - uint32_t mDataRead; // begin/end offsets of the current command uint32_t mCommandBegin; diff --git a/graphics/composer/2.1/utils/hal/Android.bp b/graphics/composer/2.1/utils/hal/Android.bp index f24e768239..7a501fcc88 100644 --- a/graphics/composer/2.1/utils/hal/Android.bp +++ b/graphics/composer/2.1/utils/hal/Android.bp @@ -20,11 +20,13 @@ cc_library_headers { shared_libs: [ "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "libhardware", // TODO remove hwcomposer2.h dependency ], export_shared_lib_headers: [ "android.hardware.graphics.composer@2.1", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "libhardware", ], header_libs: [ diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h index 2cbf044604..3a73f845e4 100644 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h +++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h @@ -26,6 +26,7 @@ #include <vector> #include <android/hardware/graphics/mapper/2.0/IMapper.h> +#include <android/hardware/graphics/mapper/3.0/IMapper.h> #include <log/log.h> namespace android { @@ -39,9 +40,16 @@ namespace hal { class ComposerHandleImporter { public: bool init() { - mMapper = mapper::V2_0::IMapper::getService(); - ALOGE_IF(!mMapper, "failed to get mapper service"); - return mMapper != nullptr; + mMapper3 = mapper::V3_0::IMapper::getService(); + if (mMapper3) { + return true; + } + ALOGW_IF(!mMapper3, "failed to get mapper 3.0 service"); + + mMapper2 = mapper::V2_0::IMapper::getService(); + ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service"); + + return mMapper2 != nullptr; } Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle) { @@ -50,14 +58,28 @@ class ComposerHandleImporter { return Error::NONE; } - mapper::V2_0::Error error; const native_handle_t* bufferHandle; - mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { - error = tmpError; - bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle); - }); - if (error != mapper::V2_0::Error::NONE) { - return Error::NO_RESOURCES; + if (mMapper2) { + mapper::V2_0::Error error; + mMapper2->importBuffer( + rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { + error = tmpError; + bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle); + }); + if (error != mapper::V2_0::Error::NONE) { + return Error::NO_RESOURCES; + } + } + if (mMapper3) { + mapper::V3_0::Error error; + mMapper3->importBuffer( + rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { + error = tmpError; + bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle); + }); + if (error != mapper::V3_0::Error::NONE) { + return Error::NO_RESOURCES; + } } *outBufferHandle = bufferHandle; @@ -66,7 +88,13 @@ class ComposerHandleImporter { void freeBuffer(const native_handle_t* bufferHandle) { if (bufferHandle) { - mMapper->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle))); + if (mMapper2) { + mMapper2->freeBuffer( + static_cast<void*>(const_cast<native_handle_t*>(bufferHandle))); + } else if (mMapper3) { + mMapper3->freeBuffer( + static_cast<void*>(const_cast<native_handle_t*>(bufferHandle))); + } } } @@ -91,7 +119,8 @@ class ComposerHandleImporter { } private: - sp<mapper::V2_0::IMapper> mMapper; + sp<mapper::V2_0::IMapper> mMapper2; + sp<mapper::V3_0::IMapper> mMapper3; }; class ComposerHandleCache { @@ -186,6 +215,8 @@ class ComposerLayerResource { : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize), mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {} + virtual ~ComposerLayerResource() = default; + Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle, const native_handle_t** outHandle, const native_handle** outReplacedHandle) { return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); @@ -211,6 +242,8 @@ class ComposerDisplayResource { VIRTUAL, }; + virtual ~ComposerDisplayResource() = default; + ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer, uint32_t outputBufferCacheSize) : mType(type), diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp index 6e668afdca..7ba67d45b5 100644 --- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp @@ -25,21 +25,19 @@ namespace composer { namespace V2_1 { namespace vts { -Composer::Composer() { - mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>(); - init(); -} +Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {} -Composer::Composer(const std::string& name) { - mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name); - init(); -} +Composer::Composer(const std::string& name) + : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {} -void Composer::init() { - ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service"; +Composer::Composer(const sp<IComposer>& composer) : mComposer(composer) { + // ASSERT_* can only be used in functions returning void. + [this] { + ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service"; - std::vector<IComposer::Capability> capabilities = getCapabilities(); - mCapabilities.insert(capabilities.begin(), capabilities.end()); + std::vector<IComposer::Capability> capabilities = getCapabilities(); + mCapabilities.insert(capabilities.begin(), capabilities.end()); + }(); } sp<IComposer> Composer::getRaw() const { @@ -295,7 +293,6 @@ void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* write if (queueChanged) { auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor()); ASSERT_EQ(Error::NONE, static_cast<Error>(ret)); - return; } mClient->executeCommands(commandLength, commandHandles, @@ -314,6 +311,8 @@ void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* write ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles)); reader->parse(); }); + reader->reset(); + writer->reset(); } } // namespace vts diff --git a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp index 6f8f1ad480..454a89ccdc 100644 --- a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp +++ b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp @@ -26,23 +26,55 @@ namespace V2_1 { namespace vts { void TestCommandReader::parse() { + mErrors.clear(); + mCompositionChanges.clear(); while (!isEmpty()) { IComposerClient::Command command; uint16_t length; ASSERT_TRUE(beginCommand(&command, &length)); switch (command) { + case IComposerClient::Command::SELECT_DISPLAY: + ASSERT_EQ(2, length); + read64(); // display + break; case IComposerClient::Command::SET_ERROR: { ASSERT_EQ(2, length); auto loc = read(); auto err = readSigned(); - GTEST_FAIL() << "unexpected error " << err << " at location " << loc; + std::pair<uint32_t, uint32_t> error(loc, err); + mErrors.push_back(error); } break; - case IComposerClient::Command::SELECT_DISPLAY: case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES: + ASSERT_EQ(0, length % 3); + for (uint16_t count = 0; count < length / 3; ++count) { + uint64_t layerId = read64(); + uint32_t composition = read(); + + std::pair<uint64_t, uint32_t> compositionChange(layerId, composition); + mCompositionChanges.push_back(compositionChange); + } + break; case IComposerClient::Command::SET_DISPLAY_REQUESTS: + ASSERT_EQ(1, length % 3); + read(); // displayRequests, ignored for now + for (uint16_t count = 0; count < (length - 1) / 3; ++count) { + read64(); // layer + // silently eat requests to clear the client target, since we won't be testing + // client composition anyway + ASSERT_EQ(1u, read()); + } + break; case IComposerClient::Command::SET_PRESENT_FENCE: + ASSERT_EQ(1, length); + close(readFence()); + break; case IComposerClient::Command::SET_RELEASE_FENCES: + ASSERT_EQ(0, length % 3); + for (uint16_t count = 0; count < length / 3; ++count) { + read64(); + close(readFence()); + } break; default: GTEST_FAIL() << "unexpected return command " << std::hex diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h index 8d5493e8a5..c97be76d9a 100644 --- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h +++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h @@ -57,10 +57,10 @@ class Composer { std::unique_ptr<ComposerClient> createClient(); protected: - sp<IComposer> mComposer; + explicit Composer(const sp<IComposer>& composer); private: - void init(); + const sp<IComposer> mComposer; std::unordered_set<IComposer::Capability> mCapabilities; }; @@ -68,7 +68,7 @@ class Composer { // A wrapper to IComposerClient. class ComposerClient { public: - ComposerClient(const sp<IComposerClient>& client); + explicit ComposerClient(const sp<IComposerClient>& client); ~ComposerClient(); sp<IComposerClient> getRaw() const; @@ -116,7 +116,7 @@ class ComposerClient { std::unordered_map<Display, DisplayResource> mDisplayResources; private: - sp<IComposerClient> mClient; + const sp<IComposerClient> mClient; }; } // namespace vts diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h index 3888eebebd..c12debe066 100644 --- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h +++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h @@ -32,6 +32,9 @@ class TestCommandReader : public CommandReaderBase { // Parse all commands in the return command queue. Call GTEST_FAIL() for // unexpected errors or commands. void parse(); + + std::vector<std::pair<uint32_t, uint32_t>> mErrors; + std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges; }; } // namespace vts diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index 72f3f1b4bf..4018aeafd6 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -71,6 +71,7 @@ class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEn class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { protected: void SetUp() override { + VtsHalHidlTargetTestBase::SetUp(); ASSERT_NO_FATAL_FAILURE( mComposer = std::make_unique<Composer>( GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>())); @@ -85,6 +86,13 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { // explicitly disable vsync mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); mComposerCallback->setVsyncAllowed(false); + + mInvalidDisplayId = GetInvalidDisplayId(); + + // Although 0 could be an invalid display, a return value of 0 + // from GetInvalidDisplayId means all other ids are in use, a condition which + // we are assuming a device will never have + ASSERT_NE(0, mInvalidDisplayId); } void TearDown() override { @@ -93,6 +101,24 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); } + VtsHalHidlTargetTestBase::TearDown(); + } + + // returns an invalid display id (one that has not been registered to a + // display. Currently assuming that a device will never have close to + // std::numeric_limit<uint64_t>::max() displays registered while running tests + Display GetInvalidDisplayId() { + std::vector<Display> validDisplays = mComposerCallback->getDisplays(); + + uint64_t id = std::numeric_limits<uint64_t>::max(); + while (id > 0) { + if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) { + return id; + } + id--; + } + + return 0; } // use the slot count usually set by SF @@ -103,6 +129,7 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp<GraphicsComposerCallback> mComposerCallback; // the first display and is assumed never to be removed Display mPrimaryDisplay; + Display mInvalidDisplayId; private: Display waitForFirstDisplay() { @@ -172,6 +199,22 @@ TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) { } /** + * Test IComposerClient::destroyVirtualDisplay + * + * Test that passing a bad display handle to destroyVirtualDisplay + * returns a BAD_DISPLAY error + */ +TEST_F(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) { + if (mComposerClient->getMaxVirtualDisplayCount() == 0) { + GTEST_SUCCEED() << "no virtual display support"; + return; + } + + Error error = mComposerClient->getRaw()->destroyVirtualDisplay(mInvalidDisplayId); + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/** * Test IComposerClient::createLayer and IComposerClient::destroyLayer. * * Test that layers can be created and destroyed. @@ -185,6 +228,89 @@ TEST_F(GraphicsComposerHidlTest, CreateLayer) { } /** + * Test IComposerClient::createLayer + * + * Test that passing in an invalid display handle to createLayer returns + * BAD_DISPLAY. + */ +TEST_F(GraphicsComposerHidlTest, CreateLayerBadDisplay) { + Error error; + mComposerClient->getRaw()->createLayer( + mInvalidDisplayId, kBufferSlotCount, + [&](const auto& tmpOutError, const auto&) { error = tmpOutError; }); + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/** + * Test IComposerClient::destroyLayer + * + * Test that passing in an invalid display handle to destroyLayer returns + * BAD_DISPLAY + */ +TEST_F(GraphicsComposerHidlTest, DestroyLayerBadDisplay) { + Error error; + Layer layer; + ASSERT_NO_FATAL_FAILURE(layer = + mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + error = mComposerClient->getRaw()->destroyLayer(mInvalidDisplayId, layer); + + EXPECT_EQ(Error::BAD_DISPLAY, error); + + ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer)); +} + +/** + * Test IComposerClient::destroyLayer + * + * Test that passing in an invalid layer handle to destroyLayer returns + * BAD_LAYER + */ +TEST_F(GraphicsComposerHidlTest, DestroyLayerBadLayerError) { + // We haven't created any layers yet, so any id should be invalid + Error error = mComposerClient->getRaw()->destroyLayer(mPrimaryDisplay, 1); + + EXPECT_EQ(Error::BAD_LAYER, error); +} + +/** + * Test IComposerClient::getActiveConfig + * + * Test that passing in a bad display handle to getActiveConfig generates a + * BAD_DISPLAY error + */ +TEST_F(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) { + Error error; + mComposerClient->getRaw()->getActiveConfig( + mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; }); + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/** + * Test IComposerClient::getDisplayConfigs + * + * Test IComposerClient::getDisplayConfigs returns no error + * when passed in a valid display + */ +TEST_F(GraphicsComposerHidlTest, GetDisplayConfig) { + std::vector<Config> configs; + ASSERT_NO_FATAL_FAILURE(configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay)); +} + +/** + * Test IComposerClient::getDisplayConfigs + * + * Test IComposerClient::getDisplayConfigs returns BAD_DISPLAY + * when passed in an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) { + Error error; + mComposerClient->getRaw()->getDisplayConfigs( + mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; }); + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/** * Test IComposerClient::getDisplayName. */ TEST_F(GraphicsComposerHidlTest, GetDisplayName) { @@ -226,6 +352,30 @@ TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) { } /** + * Test IComposerClient::getClientTargetSupport + * + * Test that IComposerClient::getClientTargetSupport returns BAD_DISPLAY when + * passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) { + std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::WIDTH); + int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::HEIGHT); + ASSERT_LT(0, width); + ASSERT_LT(0, height); + + mComposerClient->setActiveConfig(mPrimaryDisplay, config); + + Error error = mComposerClient->getRaw()->getClientTargetSupport( + mInvalidDisplayId, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN); + EXPECT_EQ(Error::BAD_DISPLAY, error); + } +} + +/** * Test IComposerClient::getDisplayAttribute. * * Test that IComposerClient::getDisplayAttribute succeeds for the required @@ -287,6 +437,43 @@ TEST_F(GraphicsComposerHidlTest, SetActiveConfig) { } /** + * Test IComposerClient::setActiveConfig + * + * Test that config set during IComposerClient::setActiveConfig is maintained + * during a display on/off power cycle + */ +TEST_F(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) { + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::OFF)); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON)); + + std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + mComposerClient->setActiveConfig(mPrimaryDisplay, config); + ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay)); + + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::OFF)); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON)); + ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay)); + } +} + +/** + * Test IComposerClient::getColorMode + * + * Test that IComposerClient::getColorMode always returns ColorMode::NATIVE + */ +TEST_F(GraphicsComposerHidlTest, GetColorModes) { + std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay); + auto nativeModeLocation = std::find(modes.begin(), modes.end(), ColorMode::NATIVE); + + ASSERT_NE(modes.end(), nativeModeLocation); +} + +/** * Test IComposerClient::setColorMode. * * Test that IComposerClient::setColorMode succeeds for all color modes. @@ -306,6 +493,45 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode) { } /** + * Test IComposerClient::setColorMode + * + * Test that IComposerClient::setColorMode returns BAD_DISPLAY for + * an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, SetColorModeBadDisplay) { + std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay); + for (auto mode : modes) { + Error error = mComposerClient->getRaw()->setColorMode(mInvalidDisplayId, mode); + EXPECT_EQ(Error::BAD_DISPLAY, error); + } +} + +/** + * Test IComposerClient::setColorMode + * + * Test that IComposerClient::setColorMode returns BAD_PARAMETER when passed in + * an invalid color mode + */ +TEST_F(GraphicsComposerHidlTest, SetColorModeBadParameter) { + Error error = + mComposerClient->getRaw()->setColorMode(mPrimaryDisplay, static_cast<ColorMode>(-1)); + ASSERT_EQ(Error::BAD_PARAMETER, error); +} + +/** + * Test IComposerClient::getDozeSupport + * + * Test that IComposerClient::getDozeSupport returns + * BAD_DISPLAY when passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) { + Error error; + mComposerClient->getRaw()->getDozeSupport( + mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; }); + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/** * Test IComposerClient::setPowerMode. * * Test that IComposerClient::setPowerMode succeeds for all power modes. @@ -328,6 +554,99 @@ TEST_F(GraphicsComposerHidlTest, SetPowerMode) { } /** + * Test IComposerClient::setPowerMode + * + * Test IComposerClient::setPowerMode succeeds with different + * orderings of power modes + */ +TEST_F(GraphicsComposerHidlTest, SetPowerModeVariations) { + std::vector<IComposerClient::PowerMode> modes; + modes.push_back(IComposerClient::PowerMode::OFF); + modes.push_back(IComposerClient::PowerMode::ON); + modes.push_back(IComposerClient::PowerMode::OFF); + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode)); + } + + modes.clear(); + + modes.push_back(IComposerClient::PowerMode::OFF); + modes.push_back(IComposerClient::PowerMode::OFF); + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode)); + } + + modes.clear(); + if (mComposerClient->getDozeSupport(mPrimaryDisplay)) { + modes.push_back(IComposerClient::PowerMode::DOZE); + modes.push_back(IComposerClient::PowerMode::DOZE); + + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode)); + } + + modes.clear(); + + modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND); + modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND); + + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode)); + } + } + + modes.clear(); + + modes.push_back(IComposerClient::PowerMode::ON); + modes.push_back(IComposerClient::PowerMode::ON); + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode)); + } +} + +/** + * Test IComposerClient::setPowerMode + * + * Test IComposerClient::setPowerMode returns BAD_DISPLAY when passed an invalid + * display handle + */ +TEST_F(GraphicsComposerHidlTest, SetPowerModeBadDisplay) { + Error error = + mComposerClient->getRaw()->setPowerMode(mInvalidDisplayId, IComposerClient::PowerMode::ON); + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/** + * Test IComposerClient::setPowerMode + * + * Test that IComposerClient::setPowerMode returns UNSUPPORTED when passed DOZE + * or DOZE_SUSPEND on devices that do not support DOZE/DOZE_SUSPEND + */ +TEST_F(GraphicsComposerHidlTest, SetPowerModeUnsupported) { + if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) { + Error error = mComposerClient->getRaw()->setPowerMode(mPrimaryDisplay, + IComposerClient::PowerMode::DOZE); + EXPECT_EQ(Error::UNSUPPORTED, error); + + error = mComposerClient->getRaw()->setPowerMode(mPrimaryDisplay, + IComposerClient::PowerMode::DOZE_SUSPEND); + EXPECT_EQ(Error::UNSUPPORTED, error); + } +} + +/** + * Test IComposerClient::setPowerMode + * + * Tests that IComposerClient::setPowerMode returns BAD_PARAMETER when passed an invalid + * PowerMode + */ +TEST_F(GraphicsComposerHidlTest, SetPowerModeBadParameter) { + Error error = mComposerClient->getRaw()->setPowerMode( + mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1)); + ASSERT_EQ(Error::BAD_PARAMETER, error); +} + +/** * Test IComposerClient::setVsyncEnabled. * * Test that IComposerClient::setVsyncEnabled succeeds and there is no @@ -351,20 +670,29 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>()); + Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay); + mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig, + IComposerClient::Attribute::WIDTH); + mDisplayHeight = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig, + IComposerClient::Attribute::HEIGHT); mWriter = std::make_unique<CommandWriterBase>(1024); mReader = std::make_unique<TestCommandReader>(); } - void TearDown() override { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); } + void TearDown() override { + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); + } const native_handle_t* allocate() { IMapper::BufferDescriptorInfo info{}; - info.width = 64; - info.height = 64; + info.width = mDisplayWidth; + info.height = mDisplayHeight; info.layerCount = 1; info.format = PixelFormat::RGBA_8888; info.usage = - static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN | + BufferUsage::COMPOSER_OVERLAY); return mGralloc->allocate(info); } @@ -373,6 +701,8 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { std::unique_ptr<CommandWriterBase> mWriter; std::unique_ptr<TestCommandReader> mReader; + int32_t mDisplayWidth; + int32_t mDisplayHeight; private: std::unique_ptr<Gralloc> mGralloc; @@ -459,6 +789,60 @@ TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) { } /** + * Test IComposerClient::Command::PRESENT_DISPLAY + * + * Test that IComposerClient::Command::PRESENT_DISPLAY works without + * additional call to validateDisplay when only the layer buffer handle and + * surface damage have been set + */ +TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) { + mWriter->selectDisplay(mPrimaryDisplay); + mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON); + mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB); + + auto handle = allocate(); + ASSERT_NE(nullptr, handle); + + IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight}; + + Layer layer; + ASSERT_NO_FATAL_FAILURE(layer = + mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + mWriter->selectLayer(layer); + mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE); + mWriter->setLayerDisplayFrame(displayFrame); + mWriter->setLayerPlaneAlpha(1); + mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight}); + mWriter->setLayerTransform(static_cast<Transform>(0)); + mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, displayFrame)); + mWriter->setLayerZOrder(10); + mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE); + mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, displayFrame)); + mWriter->setLayerBuffer(0, handle, -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->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->selectLayer(layer); + auto handle2 = allocate(); + ASSERT_NE(nullptr, handle2); + mWriter->setLayerBuffer(0, handle2, -1); + mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, {0, 0, 10, 10})); + mWriter->presentDisplay(); + execute(); +} + +/** * Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION. */ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) { diff --git a/graphics/composer/2.2/default/Android.mk b/graphics/composer/2.2/default/Android.mk index 2f80f0c19e..7dedf616b4 100644 --- a/graphics/composer/2.2/default/Android.mk +++ b/graphics/composer/2.2/default/Android.mk @@ -12,6 +12,7 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.graphics.composer@2.1 \ android.hardware.graphics.composer@2.2 \ android.hardware.graphics.mapper@2.0 \ + android.hardware.graphics.mapper@3.0 \ libbase \ libbinder \ libcutils \ diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h index a6871fb494..c760d0a421 100644 --- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h +++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h @@ -132,24 +132,13 @@ class ComposerClientImpl : public V2_1::hal::detail::ComposerClientImpl<Interfac Return<void> getRenderIntents(Display display, ColorMode mode, IComposerClient::getRenderIntents_cb hidl_cb) override { -#ifdef USES_DISPLAY_RENDER_INTENTS std::vector<RenderIntent> intents; Error err = mHal->getRenderIntents(display, mode, &intents); hidl_cb(err, intents); -#else - (void)display; - (void)mode; - hidl_cb(Error::NONE, hidl_vec<RenderIntent>({RenderIntent::COLORIMETRIC})); -#endif return Void(); } Return<Error> setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent) override { -#ifndef USES_DISPLAY_RENDER_INTENTS - if (intent != RenderIntent::COLORIMETRIC) { - return Error::BAD_PARAMETER; - } -#endif return mHal->setColorMode_2_2(display, mode, intent); } diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp index 6a32071279..da994606bb 100644 --- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp @@ -27,32 +27,31 @@ namespace composer { namespace V2_2 { namespace vts { -using android::hardware::details::canCastInterface; -using android::hardware::details::getDescriptor; -using android::hardware::graphics::composer::V2_2::IComposerClient; +using details::canCastInterface; +using details::getDescriptor; -std::unique_ptr<ComposerClient_v2_2> Composer_v2_2::createClient_v2_2() { - std::unique_ptr<ComposerClient_v2_2> client; - mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) { +std::unique_ptr<ComposerClient> Composer::createClient() { + std::unique_ptr<ComposerClient> client; + getRaw()->createClient([&](const auto& tmpError, const auto& tmpClient) { ASSERT_EQ(Error::NONE, tmpError) << "failed to create client"; ALOGV("tmpClient is a %s", getDescriptor(&(*tmpClient)).c_str()); ASSERT_TRUE(canCastInterface( &(*tmpClient), "android.hardware.graphics.composer@2.2::IComposerClient", false)) << "Cannot create 2.2 IComposerClient"; - client = std::make_unique<ComposerClient_v2_2>(IComposerClient::castFrom(tmpClient, true)); + client = std::make_unique<ComposerClient>(IComposerClient::castFrom(tmpClient, true)); }); return client; } -sp<V2_2::IComposerClient> ComposerClient_v2_2::getRaw() const { - return mClient_v2_2; +sp<IComposerClient> ComposerClient::getRaw() const { + return mClient; } -std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient_v2_2::getPerFrameMetadataKeys( +std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient::getPerFrameMetadataKeys( Display display) { std::vector<IComposerClient::PerFrameMetadataKey> keys; - mClient_v2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) { + mClient->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) { ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR metadata keys"; keys = tmpKeys; }); @@ -60,43 +59,43 @@ std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient_v2_2::getPerFra return keys; } -void ComposerClient_v2_2::execute_v2_2(V2_1::vts::TestCommandReader* reader, - V2_2::CommandWriterBase* writer) { +void ComposerClient::execute(V2_1::vts::TestCommandReader* reader, CommandWriterBase* writer) { bool queueChanged = false; uint32_t commandLength = 0; hidl_vec<hidl_handle> commandHandles; ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles)); if (queueChanged) { - auto ret = mClient_v2_2->setInputCommandQueue(*writer->getMQDescriptor()); + auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor()); ASSERT_EQ(Error::NONE, static_cast<Error>(ret)); - return; } - mClient_v2_2->executeCommands(commandLength, commandHandles, - [&](const auto& tmpError, const auto& tmpOutQueueChanged, - const auto& tmpOutLength, const auto& tmpOutHandles) { - ASSERT_EQ(Error::NONE, tmpError); - - if (tmpOutQueueChanged) { - mClient_v2_2->getOutputCommandQueue( - [&](const auto& tmpError, const auto& tmpDescriptor) { - ASSERT_EQ(Error::NONE, tmpError); - reader->setMQDescriptor(tmpDescriptor); - }); - } - - ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles)); - reader->parse(); - }); + mClient->executeCommands(commandLength, commandHandles, + [&](const auto& tmpError, const auto& tmpOutQueueChanged, + const auto& tmpOutLength, const auto& tmpOutHandles) { + ASSERT_EQ(Error::NONE, tmpError); + + if (tmpOutQueueChanged) { + mClient->getOutputCommandQueue( + [&](const auto& tmpError, const auto& tmpDescriptor) { + ASSERT_EQ(Error::NONE, tmpError); + reader->setMQDescriptor(tmpDescriptor); + }); + } + + ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles)); + reader->parse(); + }); + reader->reset(); + writer->reset(); } -Display ComposerClient_v2_2::createVirtualDisplay_2_2(uint32_t width, uint32_t height, - PixelFormat formatHint, - uint32_t outputBufferSlotCount, - PixelFormat* outFormat) { +Display ComposerClient::createVirtualDisplay_2_2(uint32_t width, uint32_t height, + PixelFormat formatHint, + uint32_t outputBufferSlotCount, + PixelFormat* outFormat) { Display display = 0; - mClient_v2_2->createVirtualDisplay_2_2( + mClient->createVirtualDisplay_2_2( width, height, formatHint, outputBufferSlotCount, [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) { ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display"; @@ -110,29 +109,27 @@ Display ComposerClient_v2_2::createVirtualDisplay_2_2(uint32_t width, uint32_t h return display; } -bool ComposerClient_v2_2::getClientTargetSupport_2_2(Display display, uint32_t width, - uint32_t height, PixelFormat format, - Dataspace dataspace) { - Error error = - mClient_v2_2->getClientTargetSupport_2_2(display, width, height, format, dataspace); +bool ComposerClient::getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) { + Error error = mClient->getClientTargetSupport_2_2(display, width, height, format, dataspace); return error == Error::NONE; } -void ComposerClient_v2_2::setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) { - Error error = mClient_v2_2->setPowerMode_2_2(display, mode); +void ComposerClient::setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) { + Error error = mClient->setPowerMode_2_2(display, mode); ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set power mode"; } -void ComposerClient_v2_2::setReadbackBuffer(Display display, const native_handle_t* buffer, - int32_t /* releaseFence */) { +void ComposerClient::setReadbackBuffer(Display display, const native_handle_t* buffer, + int32_t /* releaseFence */) { // Ignoring fence, HIDL doesn't care - Error error = mClient_v2_2->setReadbackBuffer(display, buffer, nullptr); + Error error = mClient->setReadbackBuffer(display, buffer, nullptr); ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer"; } -void ComposerClient_v2_2::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat, - Dataspace* outDataspace) { - mClient_v2_2->getReadbackBufferAttributes( +void ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat, + Dataspace* outDataspace) { + mClient->getReadbackBufferAttributes( display, [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) { ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes"; @@ -141,42 +138,40 @@ void ComposerClient_v2_2::getReadbackBufferAttributes(Display display, PixelForm }); } -void ComposerClient_v2_2::getReadbackBufferFence(Display display, int32_t* outFence) { - hidl_handle handle; - mClient_v2_2->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) { +void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) { + mClient->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) { ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence"; - handle = tmpHandle; + const native_handle_t* nativeFenceHandle = tmpHandle.getNativeHandle(); + *outFence = dup(nativeFenceHandle->data[0]); }); - *outFence = 0; } -std::vector<ColorMode> ComposerClient_v2_2::getColorModes(Display display) { +std::vector<ColorMode> ComposerClient::getColorModes(Display display) { std::vector<ColorMode> modes; - mClient_v2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) { + mClient->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) { ASSERT_EQ(Error::NONE, tmpError) << "failed to get color modes"; modes = tmpModes; }); return modes; } -std::vector<RenderIntent> ComposerClient_v2_2::getRenderIntents(Display display, ColorMode mode) { +std::vector<RenderIntent> ComposerClient::getRenderIntents(Display display, ColorMode mode) { std::vector<RenderIntent> intents; - mClient_v2_2->getRenderIntents( - display, mode, [&](const auto& tmpError, const auto& tmpIntents) { - ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents"; - intents = tmpIntents; - }); + mClient->getRenderIntents(display, mode, [&](const auto& tmpError, const auto& tmpIntents) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents"; + intents = tmpIntents; + }); return intents; } -void ComposerClient_v2_2::setColorMode(Display display, ColorMode mode, RenderIntent intent) { - Error error = mClient_v2_2->setColorMode_2_2(display, mode, intent); +void ComposerClient::setColorMode(Display display, ColorMode mode, RenderIntent intent) { + Error error = mClient->setColorMode_2_2(display, mode, intent); ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set color mode"; } -std::array<float, 16> ComposerClient_v2_2::getDataspaceSaturationMatrix(Dataspace dataspace) { +std::array<float, 16> ComposerClient::getDataspaceSaturationMatrix(Dataspace dataspace) { std::array<float, 16> matrix; - mClient_v2_2->getDataspaceSaturationMatrix( + mClient->getDataspaceSaturationMatrix( dataspace, [&](const auto& tmpError, const auto& tmpMatrix) { ASSERT_EQ(Error::NONE, tmpError) << "failed to get datasapce saturation matrix"; std::copy_n(tmpMatrix.data(), matrix.size(), matrix.begin()); 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 1c6d7ae00b..263302124f 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 @@ -36,36 +36,31 @@ namespace composer { namespace V2_2 { namespace vts { -using android::hardware::graphics::common::V1_0::Hdr; -using android::hardware::graphics::common::V1_1::ColorMode; -using android::hardware::graphics::common::V1_1::Dataspace; -using android::hardware::graphics::common::V1_1::PixelFormat; -using android::hardware::graphics::common::V1_1::RenderIntent; -using android::hardware::graphics::composer::V2_2::IComposer; -using android::hardware::graphics::composer::V2_2::IComposerClient; - -class ComposerClient_v2_2; - -// Only thing I need for Composer_v2_2 is to create a v2_2 ComposerClient -// Everything else is the same -class Composer_v2_2 : public V2_1::vts::Composer { +using common::V1_0::Hdr; +using common::V1_1::ColorMode; +using common::V1_1::Dataspace; +using common::V1_1::PixelFormat; +using common::V1_1::RenderIntent; + +class ComposerClient; + +// A wrapper to IComposer. +class Composer : public V2_1::vts::Composer { public: - Composer_v2_2() : V2_1::vts::Composer(){}; - explicit Composer_v2_2(const std::string& name) : V2_1::vts::Composer(name){}; + using V2_1::vts::Composer::Composer; - std::unique_ptr<ComposerClient_v2_2> createClient_v2_2(); + std::unique_ptr<ComposerClient> createClient(); }; // A wrapper to IComposerClient. -class ComposerClient_v2_2 - : public android::hardware::graphics::composer::V2_1::vts::ComposerClient { +class ComposerClient : public V2_1::vts::ComposerClient { public: - ComposerClient_v2_2(const sp<IComposerClient>& client) - : V2_1::vts::ComposerClient(client), mClient_v2_2(client){}; + explicit ComposerClient(const sp<IComposerClient>& client) + : V2_1::vts::ComposerClient(client), mClient(client) {} - sp<V2_2::IComposerClient> getRaw() const; + sp<IComposerClient> getRaw() const; - void execute_v2_2(V2_1::vts::TestCommandReader* reader, V2_2::CommandWriterBase* writer); + void execute(V2_1::vts::TestCommandReader* reader, CommandWriterBase* writer); std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(Display display); @@ -73,7 +68,7 @@ class ComposerClient_v2_2 uint32_t outputBufferSlotCount, PixelFormat* outFormat); bool getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height, PixelFormat format, Dataspace dataspace); - void setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode); + 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); @@ -86,7 +81,7 @@ class ComposerClient_v2_2 std::array<float, 16> getDataspaceSaturationMatrix(Dataspace dataspace); private: - sp<V2_2::IComposerClient> mClient_v2_2; + const sp<IComposerClient> mClient; }; } // namespace vts diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index a3da8294cb..b62f3021b9 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -17,12 +17,15 @@ cc_test { name: "VtsHalGraphicsComposerV2_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], - srcs: ["VtsHalGraphicsComposerV2_2TargetTest.cpp"], + srcs: [ + "VtsHalGraphicsComposerV2_2ReadbackTest.cpp", + "VtsHalGraphicsComposerV2_2TargetTest.cpp", + ], // TODO(b/64437680): Assume these libs are always available on the device. shared_libs: [ "libfmq", - "libhidltransport", + "libhidltransport", "libsync", ], static_libs: [ diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp new file mode 100644 index 0000000000..da8858e037 --- /dev/null +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -0,0 +1,1336 @@ +/* + * Copyright 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. + */ + +#define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2" + +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> +#include <android-base/unique_fd.h> +#include <android/hardware/graphics/composer/2.2/IComposerClient.h> +#include <composer-command-buffer/2.2/ComposerCommandBuffer.h> +#include <composer-vts/2.1/GraphicsComposerCallback.h> +#include <composer-vts/2.1/TestCommandReader.h> +#include <composer-vts/2.2/ComposerVts.h> +#include <mapper-vts/2.1/MapperVts.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_2 { +namespace vts { +namespace { + +using android::hardware::hidl_handle; +using common::V1_1::BufferUsage; +using common::V1_1::Dataspace; +using common::V1_1::PixelFormat; +using mapper::V2_1::IMapper; +using mapper::V2_1::vts::Gralloc; +using V2_1::Display; +using V2_1::Layer; +using V2_1::vts::TestCommandReader; + +static const IComposerClient::Color BLACK = {0, 0, 0, 0xff}; +static const IComposerClient::Color RED = {0xff, 0, 0, 0xff}; +static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33}; +static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff}; +static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff}; + +// Test environment for graphics.composer +class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static GraphicsComposerHidlEnvironment* Instance() { + static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; + return instance; + } + virtual void registerTestServices() override { registerTestService<IComposer>(); } + + private: + GraphicsComposerHidlEnvironment() {} + GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); +}; + +class TestLayer { + public: + TestLayer(const std::shared_ptr<ComposerClient>& client, Display display) + : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {} + + // ComposerClient will take care of destroying layers, no need to explicitly + // call destroyLayers here + virtual ~TestLayer(){}; + + virtual void write(const std::shared_ptr<CommandWriterBase>& writer) { + writer->selectLayer(mLayer); + writer->setLayerDisplayFrame(mDisplayFrame); + writer->setLayerSourceCrop(mSourceCrop); + writer->setLayerZOrder(mZOrder); + writer->setLayerSurfaceDamage(mSurfaceDamage); + writer->setLayerTransform(mTransform); + writer->setLayerPlaneAlpha(mAlpha); + writer->setLayerBlendMode(mBlendMode); + } + + void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; } + void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; } + void setZOrder(uint32_t z) { mZOrder = z; } + + void setSurfaceDamage(std::vector<IComposerClient::Rect> surfaceDamage) { + mSurfaceDamage = surfaceDamage; + } + + void setTransform(Transform transform) { mTransform = transform; } + void setAlpha(float alpha) { mAlpha = alpha; } + void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; } + + static constexpr uint32_t kBufferSlotCount = 64; + + IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0}; + uint32_t mZOrder = 0; + std::vector<IComposerClient::Rect> mSurfaceDamage; + Transform mTransform = static_cast<Transform>(0); + IComposerClient::FRect mSourceCrop = {0, 0, 0, 0}; + float mAlpha = 1.0; + IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE; + + protected: + Layer mLayer; + + private: + std::shared_ptr<ComposerClient> const mComposerClient; +}; + +class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase { + public: + static int32_t GetBytesPerPixel(PixelFormat pixelFormat) { + switch (pixelFormat) { + case PixelFormat::RGBA_8888: + return 4; + case PixelFormat::RGB_888: + return 3; + default: + return -1; + } + } + + static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData, + PixelFormat pixelFormat, + std::vector<IComposerClient::Color> desiredPixelColors) { + ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == 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++) { + int pixel = row * width + col; + IComposerClient::Color srcColor = 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; + + if (bytesPerPixel == 4) { + pixelColor[3] = srcColor.a; + } + } + } + } + + protected: + using PowerMode = V2_1::IComposerClient::PowerMode; + void SetUp() override { + VtsHalHidlTargetTestBase::SetUp(); + ASSERT_NO_FATAL_FAILURE( + mComposer = std::make_unique<Composer>( + GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>())); + ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); + mComposerCallback = new V2_1::vts::GraphicsComposerCallback; + mComposerClient->registerCallback(mComposerCallback); + + // assume the first display is primary and is never removed + mPrimaryDisplay = waitForFirstDisplay(); + Config activeConfig; + ASSERT_NO_FATAL_FAILURE(activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay)); + ASSERT_NO_FATAL_FAILURE( + mDisplayWidth = mComposerClient->getDisplayAttribute( + mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH)); + ASSERT_NO_FATAL_FAILURE( + mDisplayHeight = mComposerClient->getDisplayAttribute( + mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT)); + + // explicitly disable vsync + ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false)); + mComposerCallback->setVsyncAllowed(false); + + // set up command writer/reader and gralloc + mWriter = std::make_shared<CommandWriterBase>(1024); + mReader = std::make_unique<TestCommandReader>(); + mGralloc = std::make_shared<Gralloc>(); + + mComposerClient->getRaw()->getReadbackBufferAttributes( + mPrimaryDisplay, + [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) { + mHasReadbackBuffer = readbackSupported(tmpPixelFormat, tmpDataspace, tmpError); + mPixelFormat = tmpPixelFormat; + mDataspace = tmpDataspace; + }); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON)); + } + + void TearDown() override { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF)); + EXPECT_EQ(0, mReader->mErrors.size()); + EXPECT_EQ(0, mReader->mCompositionChanges.size()); + if (mComposerCallback != nullptr) { + EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); + } + VtsHalHidlTargetTestBase::TearDown(); + } + + void clearCommandReaderState() { + mReader->mCompositionChanges.clear(); + mReader->mErrors.clear(); + } + + void execute() { + ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get())); + } + + void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) { + for (auto layer : layers) { + layer->write(mWriter); + } + execute(); + } + + void clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width, + int32_t height) { + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + int pixel = row * mDisplayWidth + col; + expectedColors[pixel] = BLACK; + } + } + } + + void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride, + IComposerClient::Rect area, IComposerClient::Color color) { + for (int row = area.top; row < area.bottom; row++) { + for (int col = area.left; col < area.right; col++) { + int pixel = row * stride + col; + expectedColors[pixel] = color; + } + } + } + + bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace, + const Error error) { + if (error != Error::NONE) { + return false; + } + // TODO: add support for RGBA_1010102 + if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) { + return false; + } + if (dataspace != Dataspace::V0_SRGB) { + return false; + } + return true; + } + + + std::unique_ptr<Composer> mComposer; + std::shared_ptr<ComposerClient> mComposerClient; + + sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback; + // the first display and is assumed never to be removed + Display mPrimaryDisplay; + int32_t mDisplayWidth; + int32_t mDisplayHeight; + std::shared_ptr<CommandWriterBase> mWriter; + std::unique_ptr<TestCommandReader> mReader; + std::shared_ptr<Gralloc> mGralloc; + + bool mHasReadbackBuffer; + PixelFormat mPixelFormat; + Dataspace mDataspace; + + static constexpr uint32_t kClientTargetSlotCount = 64; + + private: + Display waitForFirstDisplay() { + while (true) { + std::vector<Display> displays = mComposerCallback->getDisplays(); + if (displays.empty()) { + usleep(5 * 1000); + continue; + } + return displays[0]; + } + } +}; +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) { + mDisplay = display; + + mComposerClient = client; + mGralloc = gralloc; + + mPixelFormat = pixelFormat; + mDataspace = dataspace; + + mInfo.width = width; + mInfo.height = height; + mInfo.layerCount = 1; + mInfo.format = mPixelFormat; + mInfo.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE); + + mAccessRegion.top = 0; + mAccessRegion.left = 0; + mAccessRegion.width = width; + mAccessRegion.height = height; + }; + + ~ReadbackBuffer() { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + } + } + + void setReadbackBuffer() { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + mBufferHandle = nullptr; + } + mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride); + ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride)); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1)); + } + + void 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, mInfo.usage, mAccessRegion, fenceHandle); + ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888); + int32_t bytesPerPixel = GraphicsComposerReadbackTest::GetBytesPerPixel(mPixelFormat); + ASSERT_NE(-1, bytesPerPixel); + for (int row = 0; row < mInfo.height; row++) { + for (int col = 0; col < mInfo.width; col++) { + int pixel = row * mInfo.width + col; + int offset = (row * mStride + col) * bytesPerPixel; + uint8_t* pixelColor = (uint8_t*)bufData + offset; + + ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]); + ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]); + ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]); + } + } + int32_t unlockFence = mGralloc->unlock(mBufferHandle); + if (unlockFence != -1) { + sync_wait(unlockFence, -1); + close(unlockFence); + } + } + + protected: + IMapper::BufferDescriptorInfo mInfo; + IMapper::Rect mAccessRegion; + uint32_t mStride; + const native_handle_t* mBufferHandle = nullptr; + PixelFormat mPixelFormat; + Dataspace mDataspace; + Display mDisplay; + std::shared_ptr<Gralloc> mGralloc; + std::shared_ptr<ComposerClient> mComposerClient; +}; + +class TestColorLayer : public TestLayer { + public: + TestColorLayer(const std::shared_ptr<ComposerClient>& client, Display display) + : TestLayer{client, display} {} + + void write(const std::shared_ptr<CommandWriterBase>& writer) override { + TestLayer::write(writer); + writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR); + writer->setLayerColor(mColor); + } + + void setColor(IComposerClient::Color color) { mColor = color; } + + private: + IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff}; +}; + +class TestBufferLayer : public TestLayer { + public: + TestBufferLayer(const std::shared_ptr<ComposerClient>& client, + const std::shared_ptr<Gralloc>& gralloc, Display display, int32_t width, + int32_t height, PixelFormat format, + IComposerClient::Composition composition = IComposerClient::Composition::DEVICE) + : TestLayer{client, display} { + mGralloc = gralloc; + mComposition = composition; + mInfo.width = width; + mInfo.height = height; + mInfo.layerCount = 1; + mInfo.format = format; + mInfo.usage = + static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY); + + mAccessRegion.top = 0; + mAccessRegion.left = 0; + mAccessRegion.width = width; + mAccessRegion.height = height; + + setSourceCrop({0, 0, (float)width, (float)height}); + } + + ~TestBufferLayer() { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + } + } + + void write(const std::shared_ptr<CommandWriterBase>& writer) override { + TestLayer::write(writer); + writer->setLayerCompositionType(mComposition); + writer->setLayerDataspace(Dataspace::UNKNOWN); + writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame)); + if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence); + } + + void fillBuffer(std::vector<IComposerClient::Color> expectedColors) { + void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, -1); + ASSERT_NO_FATAL_FAILURE(GraphicsComposerReadbackTest::fillBuffer( + mInfo.width, mInfo.height, mStride, bufData, mInfo.format, expectedColors)); + mFillFence = mGralloc->unlock(mBufferHandle); + if (mFillFence != -1) { + sync_wait(mFillFence, -1); + close(mFillFence); + } + } + void setBuffer(std::vector<IComposerClient::Color> colors) { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + mBufferHandle = nullptr; + } + mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride); + ASSERT_NE(nullptr, mBufferHandle); + ASSERT_NO_FATAL_FAILURE(fillBuffer(colors)); + ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride)); + } + + void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) { + writer->selectLayer(mLayer); + writer->setLayerCompositionType(IComposerClient::Composition::CLIENT); + } + + IMapper::BufferDescriptorInfo mInfo; + IMapper::Rect mAccessRegion; + uint32_t mStride; + + protected: + IComposerClient::Composition mComposition; + std::shared_ptr<Gralloc> mGralloc; + int32_t mFillFence; + const native_handle_t* mBufferHandle = nullptr; +}; + +TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, + RenderIntent::COLORIMETRIC)); + + auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); + IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + // expected color for each pixel + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + // if hwc cannot handle and asks for composition change, + // just succeed the test + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN); + fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); + + auto layer = + std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, + RenderIntent::COLORIMETRIC)); + + auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); + IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + layer->write(mWriter); + + // This following buffer call should have no effect + IMapper::BufferDescriptorInfo bufferInfo{}; + bufferInfo.width = mDisplayWidth; + bufferInfo.height = mDisplayHeight; + bufferInfo.layerCount = 1; + bufferInfo.format = PixelFormat::RGBA_8888; + bufferInfo.usage = + static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN); + const native_handle_t* bufferHandle = mGralloc->allocate(bufferInfo); + mWriter->setLayerBuffer(0, bufferHandle, -1); + + // expected color for each pixel + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerReadbackTest, ClientComposition) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN); + fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); + + auto layer = + std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_FP16); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 0) { + ASSERT_EQ(1, mReader->mCompositionChanges.size()); + ASSERT_EQ(1, mReader->mCompositionChanges[0].second); + + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); + + // create client target buffer + uint32_t clientStride; + IMapper::BufferDescriptorInfo clientInfo; + clientInfo.width = layer->mInfo.width; + clientInfo.height = layer->mInfo.height; + clientInfo.layerCount = layer->mInfo.layerCount; + clientInfo.format = PixelFormat::RGBA_8888; + clientInfo.usage = + static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_CLIENT_TARGET); + const native_handle_t* clientBufferHandle = + mGralloc->allocate(clientInfo, /*import*/ true, &clientStride); + ASSERT_NE(nullptr, clientBufferHandle); + + void* clientBufData = + mGralloc->lock(clientBufferHandle, clientInfo.usage, layer->mAccessRegion, -1); + + ASSERT_NO_FATAL_FAILURE(fillBuffer(clientInfo.width, clientInfo.height, clientStride, + clientBufData, clientInfo.format, expectedColors)); + int clientFence = mGralloc->unlock(clientBufferHandle); + if (clientFence != -1) { + sync_wait(clientFence, -1); + close(clientFence); + } + + IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight}; + mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN, + std::vector<IComposerClient::Rect>(1, damage)); + + layer->setToClientComposition(mWriter); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN); + fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + auto deviceLayer = + std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight / 2, PixelFormat::RGBA_8888); + std::vector<IComposerClient::Color> deviceColors(deviceLayer->mInfo.width * + deviceLayer->mInfo.height); + fillColorsArea(deviceColors, deviceLayer->mInfo.width, + {0, 0, static_cast<int32_t>(deviceLayer->mInfo.width), + static_cast<int32_t>(deviceLayer->mInfo.height)}, + GREEN); + deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mInfo.width), + static_cast<int32_t>(deviceLayer->mInfo.height)}); + deviceLayer->setZOrder(10); + ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors)); + deviceLayer->write(mWriter); + + auto clientLayer = std::make_shared<TestBufferLayer>( + mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2, + PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT); + IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}; + clientLayer->setDisplayFrame(clientFrame); + clientLayer->setZOrder(0); + clientLayer->write(mWriter); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + IMapper::BufferDescriptorInfo clientInfo; + clientInfo.width = mDisplayWidth; + clientInfo.height = mDisplayHeight; + clientInfo.layerCount = 1; + clientInfo.format = PixelFormat::RGBA_8888; + clientInfo.usage = + static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_CLIENT_TARGET); + + uint32_t clientStride; + const native_handle_t* clientBufferHandle = + mGralloc->allocate(clientInfo, /*import*/ true, &clientStride); + ASSERT_NE(nullptr, clientBufferHandle); + + IMapper::Rect clientAccessRegion; + clientAccessRegion.left = 0; + clientAccessRegion.top = 0; + clientAccessRegion.width = mDisplayWidth; + clientAccessRegion.height = mDisplayHeight; + void* clientData = mGralloc->lock(clientBufferHandle, clientInfo.usage, clientAccessRegion, -1); + std::vector<IComposerClient::Color> clientColors(clientInfo.width * clientInfo.height); + fillColorsArea(clientColors, clientInfo.width, clientFrame, RED); + ASSERT_NO_FATAL_FAILURE(fillBuffer(clientInfo.width, clientInfo.height, clientStride, + clientData, clientInfo.format, clientColors)); + int clientFence = mGralloc->unlock(clientBufferHandle); + if (clientFence != -1) { + sync_wait(clientFence, -1); + close(clientFence); + } + + mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN, + std::vector<IComposerClient::Rect>(1, clientFrame)); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelformat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4}; + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + auto layer = + std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + + // update surface damage and recheck + redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2}; + clearColors(expectedColors, mDisplayWidth, mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors)); + layer->setSurfaceDamage( + std::vector<IComposerClient::Rect>(1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2})); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, + RenderIntent::COLORIMETRIC)); + + auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); + layer->setColor(RED); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setAlpha(0); + layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE); + + auto layer = + std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2), + static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)}); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + // update expected colors to match crop + fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, BLUE); + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, + RenderIntent::COLORIMETRIC)); + + IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2}; + IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight}; + auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); + redLayer->setColor(RED); + redLayer->setDisplayFrame(redRect); + + auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); + blueLayer->setColor(BLUE); + blueLayer->setDisplayFrame(blueRect); + blueLayer->setZOrder(5); + + std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer}; + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + + // red in front of blue + redLayer->setZOrder(10); + + // fill blue first so that red will overwrite on overlap + fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); + fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + + redLayer->setZOrder(1); + clearColors(expectedColors, mDisplayWidth, mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTest, + public ::testing::WithParamInterface<float> { + public: + void SetUp() override { + GraphicsComposerReadbackTest::SetUp(); + mBackgroundColor = BLACK; + mTopLayerColor = RED; + } + + void TearDown() override { GraphicsComposerReadbackTest::TearDown(); } + + void setBackgroundColor(IComposerClient::Color color) { mBackgroundColor = color; } + + void setTopLayerColor(IComposerClient::Color color) { mTopLayerColor = color; } + + void setUpLayers(IComposerClient::BlendMode blendMode) { + mLayers.clear(); + std::vector<IComposerClient::Color> topLayerPixelColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(topLayerPixelColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, + mTopLayerColor); + + auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); + backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + backgroundLayer->setZOrder(0); + backgroundLayer->setColor(mBackgroundColor); + + auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, + mDisplayWidth, mDisplayHeight, + PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors)); + + layer->setBlendMode(blendMode); + layer->setAlpha(GetParam()); + + mLayers.push_back(backgroundLayer); + mLayers.push_back(layer); + } + + void setExpectedColors(std::vector<IComposerClient::Color>& expectedColors) { + ASSERT_EQ(2, mLayers.size()); + clearColors(expectedColors, mDisplayWidth, mDisplayHeight); + + auto layer = mLayers[1]; + IComposerClient::BlendMode blendMode = layer->mBlendMode; + float alpha = mTopLayerColor.a / 255.0 * layer->mAlpha; + if (blendMode == IComposerClient::BlendMode::NONE) { + for (int i = 0; i < expectedColors.size(); i++) { + expectedColors[i].r = mTopLayerColor.r * layer->mAlpha; + expectedColors[i].g = mTopLayerColor.g * layer->mAlpha; + expectedColors[i].b = mTopLayerColor.b * layer->mAlpha; + expectedColors[i].a = alpha * 255.0; + } + } else if (blendMode == IComposerClient::BlendMode::PREMULTIPLIED) { + for (int i = 0; i < expectedColors.size(); i++) { + expectedColors[i].r = + mTopLayerColor.r * layer->mAlpha + mBackgroundColor.r * (1.0 - alpha); + expectedColors[i].g = + mTopLayerColor.g * layer->mAlpha + mBackgroundColor.g * (1.0 - alpha); + expectedColors[i].b = + mTopLayerColor.b * layer->mAlpha + mBackgroundColor.b * (1.0 - alpha); + expectedColors[i].a = alpha + mBackgroundColor.a * (1.0 - alpha); + } + } else if (blendMode == IComposerClient::BlendMode::COVERAGE) { + for (int i = 0; i < expectedColors.size(); i++) { + expectedColors[i].r = mTopLayerColor.r * alpha + mBackgroundColor.r * (1.0 - alpha); + expectedColors[i].g = mTopLayerColor.g * alpha + mBackgroundColor.g * (1.0 - alpha); + expectedColors[i].b = mTopLayerColor.b * alpha + mBackgroundColor.b * (1.0 - alpha); + expectedColors[i].a = mTopLayerColor.a * alpha + mBackgroundColor.a * (1.0 - alpha); + } + } + } + + protected: + std::vector<std::shared_ptr<TestLayer>> mLayers; + IComposerClient::Color mBackgroundColor; + IComposerClient::Color mTopLayerColor; +}; + +TEST_P(GraphicsComposerBlendModeReadbackTest, None) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + setUpLayers(IComposerClient::BlendMode::NONE); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +// TODO: bug 116865056: Readback returns (245, 0, 0) for layer plane +// alpha of .2, expected 10.2 +TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + + setUpLayers(IComposerClient::BlendMode::COVERAGE); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsComposerBlendModeReadbackTest, + ::testing::Values(.2, 1.0)); + +class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTest { + protected: + void SetUp() override { + GraphicsComposerReadbackTest::SetUp(); + + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, + RenderIntent::COLORIMETRIC)); + + auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); + backgroundLayer->setColor({0, 0, 0, 0}); + backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + backgroundLayer->setZOrder(0); + + mSideLength = mDisplayWidth < mDisplayHeight ? mDisplayWidth : mDisplayHeight; + IComposerClient::Rect redRect = {0, 0, mSideLength / 2, mSideLength / 2}; + IComposerClient::Rect blueRect = {mSideLength / 2, mSideLength / 2, mSideLength, + mSideLength}; + + mLayer = + std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, + mSideLength, mSideLength, PixelFormat::RGBA_8888); + mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength}); + mLayer->setZOrder(10); + + std::vector<IComposerClient::Color> baseColors(mSideLength * mSideLength); + fillColorsArea(baseColors, mSideLength, redRect, RED); + fillColorsArea(baseColors, mSideLength, blueRect, BLUE); + ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors)); + + mLayers = {backgroundLayer, mLayer}; + } + + protected: + std::shared_ptr<TestBufferLayer> mLayer; + std::vector<IComposerClient::Color> baseColors; + std::vector<std::shared_ptr<TestLayer>> mLayers; + int mSideLength; +}; + +TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + mLayer->setTransform(Transform::FLIP_H); + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED); + fillColorsArea(expectedColors, mDisplayWidth, + {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mLayer->setTransform(Transform::FLIP_V); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, + {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED); + fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) { + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth, + mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mLayer->setTransform(Transform::ROT_180); + + std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, RED); + fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mSideLength / 2, mSideLength / 2}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); +} + +} // anonymous namespace +} // namespace vts +} // namespace V2_2 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp index 951e874e92..7834b9460f 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp @@ -32,17 +32,15 @@ namespace V2_2 { namespace vts { namespace { -using android::hardware::graphics::common::V1_0::BufferUsage; -using android::hardware::graphics::common::V1_0::ColorTransform; -using android::hardware::graphics::common::V1_0::Transform; -using android::hardware::graphics::common::V1_1::ColorMode; -using android::hardware::graphics::common::V1_1::Dataspace; -using android::hardware::graphics::common::V1_1::PixelFormat; -using android::hardware::graphics::common::V1_1::RenderIntent; -using android::hardware::graphics::composer::V2_2::IComposerClient; -using android::hardware::graphics::mapper::V2_0::IMapper; -using android::hardware::graphics::mapper::V2_0::vts::Gralloc; -using GrallocError = android::hardware::graphics::mapper::V2_0::Error; +using common::V1_0::BufferUsage; +using common::V1_0::ColorTransform; +using common::V1_0::Transform; +using common::V1_1::ColorMode; +using common::V1_1::Dataspace; +using common::V1_1::PixelFormat; +using common::V1_1::RenderIntent; +using mapper::V2_0::IMapper; +using mapper::V2_0::vts::Gralloc; // Test environment for graphics.composer class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { @@ -65,9 +63,9 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { protected: void SetUp() override { ASSERT_NO_FATAL_FAILURE( - mComposer = std::make_unique<Composer_v2_2>( + mComposer = std::make_unique<Composer>( GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>())); - ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient_v2_2()); + ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); mComposerCallback = new V2_1::vts::GraphicsComposerCallback; mComposerClient->registerCallback(mComposerCallback); @@ -75,14 +73,29 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { // assume the first display is primary and is never removed mPrimaryDisplay = waitForFirstDisplay(); + Config config = mComposerClient->getActiveConfig(mPrimaryDisplay); + mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::WIDTH); + mDisplayHeight = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::HEIGHT); + // explicitly disable vsync mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); mComposerCallback->setVsyncAllowed(false); mComposerClient->getRaw()->getReadbackBufferAttributes( - mPrimaryDisplay, [&](const auto& tmpError, const auto&, const auto&) { + 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); + } }); + + mInvalidDisplayId = GetInvalidDisplayId(); } void TearDown() override { @@ -93,16 +106,39 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { } } + // returns an invalid display id (one that has not been registered to a + // display. Currently assuming that a device will never have close to + // std::numeric_limit<uint64_t>::max() displays registered while running tests + Display GetInvalidDisplayId() { + std::vector<Display> validDisplays = mComposerCallback->getDisplays(); + uint64_t id = std::numeric_limits<uint64_t>::max(); + while (id > 0) { + if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) { + return id; + } + id--; + } + + return 0; + } + // use the slot count usually set by SF static constexpr uint32_t kBufferSlotCount = 64; - std::unique_ptr<Composer_v2_2> mComposer; - std::unique_ptr<ComposerClient_v2_2> mComposerClient; + std::unique_ptr<Composer> mComposer; + std::unique_ptr<ComposerClient> mComposerClient; sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback; // the first display and is assumed never to be removed Display mPrimaryDisplay; + int32_t mDisplayWidth; + int32_t mDisplayHeight; + bool mHasReadbackBuffer; + uint64_t mInvalidDisplayId; + PixelFormat mReadbackPixelFormat; + Dataspace mReadbackDataspace; + private: Display waitForFirstDisplay() { while (true) { @@ -125,11 +161,14 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>()); - mWriter = std::make_unique<V2_2::CommandWriterBase>(1024); + mWriter = std::make_unique<CommandWriterBase>(1024); mReader = std::make_unique<V2_1::vts::TestCommandReader>(); } - void TearDown() override { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); } + void TearDown() override { + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); + } const native_handle_t* allocate() { IMapper::BufferDescriptorInfo info{}; @@ -143,9 +182,9 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { return mGralloc->allocate(info); } - void execute() { mComposerClient->execute_v2_2(mReader.get(), mWriter.get()); } + void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } - std::unique_ptr<V2_2::CommandWriterBase> mWriter; + std::unique_ptr<CommandWriterBase> mWriter; std::unique_ptr<V2_1::vts::TestCommandReader> mReader; private: @@ -191,6 +230,16 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0}); mWriter->setLayerPerFrameMetadata(hidlMetadata); execute(); + + if (mReader->mErrors.size() == 1 && + static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) { + mReader->mErrors.clear(); + GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported"; + ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer)); + return; + } + + ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer)); } /** @@ -249,9 +298,35 @@ TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) { } /** + * Test IComposerClient::getClientTargetSupport_2_2 + * + * Test that IComposerClient::getClientTargetSupport_2_2 returns + * Error::BAD_DISPLAY when passed in an invalid display handle + */ + +TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) { + std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::WIDTH); + int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::HEIGHT); + ASSERT_LT(0, width); + ASSERT_LT(0, height); + + mComposerClient->setActiveConfig(mPrimaryDisplay, config); + + Error error = mComposerClient->getRaw()->getClientTargetSupport_2_2( + mInvalidDisplayId, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN); + + EXPECT_EQ(Error::BAD_DISPLAY, error); + } +} + +/** * Test IComposerClient::setPowerMode_2_2. */ -TEST_F(GraphicsComposerHidlTest, setPowerMode_2_2) { +TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2) { std::vector<IComposerClient::PowerMode> modes; modes.push_back(IComposerClient::PowerMode::OFF); modes.push_back(IComposerClient::PowerMode::ON_SUSPEND); @@ -262,25 +337,118 @@ TEST_F(GraphicsComposerHidlTest, setPowerMode_2_2) { } } -TEST_F(GraphicsComposerHidlTest, setReadbackBuffer) { +/** + * Test IComposerClient::setPowerMode_2_2 + * + * Test that IComposerClient::setPowerMode_2_2 succeeds for different varations + * of PowerMode + */ +TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) { + std::vector<IComposerClient::PowerMode> modes; + + modes.push_back(IComposerClient::PowerMode::OFF); + modes.push_back(IComposerClient::PowerMode::OFF); + + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode)); + } + + modes.clear(); + + modes.push_back(IComposerClient::PowerMode::ON); + modes.push_back(IComposerClient::PowerMode::ON); + + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode)); + } + + modes.clear(); + + modes.push_back(IComposerClient::PowerMode::ON_SUSPEND); + modes.push_back(IComposerClient::PowerMode::ON_SUSPEND); + + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode)); + } + + if (mComposerClient->getDozeSupport(mPrimaryDisplay)) { + modes.clear(); + + modes.push_back(IComposerClient::PowerMode::DOZE); + modes.push_back(IComposerClient::PowerMode::DOZE); + + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode)); + } + + modes.clear(); + + modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND); + modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND); + + for (auto mode : modes) { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode)); + } + } +} + +/** + * Test IComposerClient::setPowerMode_2_2 + * + * Tests that IComposerClient::setPowerMode_2_2 returns BAD_DISPLAY when passed an + * invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) { + Error error = mComposerClient->getRaw()->setPowerMode_2_2(mInvalidDisplayId, + IComposerClient::PowerMode::ON); + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/** + * Test IComposerClient::setPowerMode_2_2 + * + * Test that IComposerClient::setPowerMode_2_2 returns BAD_PARAMETER when passed + * an invalid PowerMode + */ +TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) { + Error error = mComposerClient->getRaw()->setPowerMode_2_2( + mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1)); + ASSERT_EQ(Error::BAD_PARAMETER, error); +} + +/** + * Test IComposerClient::setPowerMode_2_2 + * + * Test that IComposerClient::setPowerMode_2_2 returns UNSUPPORTED when passed + * DOZE or DOZE_SUPPORT on a device that does not support these modes + */ +TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) { + if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) { + Error error = mComposerClient->getRaw()->setPowerMode_2_2(mPrimaryDisplay, + IComposerClient::PowerMode::DOZE); + EXPECT_EQ(Error::UNSUPPORTED, error); + + error = mComposerClient->getRaw()->setPowerMode_2_2( + mPrimaryDisplay, IComposerClient::PowerMode::DOZE_SUSPEND); + EXPECT_EQ(Error::UNSUPPORTED, error); + } +} + +/** + * Test IComposerClient::setReadbackBuffer + * + * Test IComposerClient::setReadbackBuffer + */ +TEST_F(GraphicsComposerHidlTest, SetReadbackBuffer) { if (!mHasReadbackBuffer) { return; } - PixelFormat pixelFormat; - Dataspace dataspace; - mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat, &dataspace); - ASSERT_LT(static_cast<PixelFormat>(0), pixelFormat); - ASSERT_NE(Dataspace::UNKNOWN, dataspace); - IMapper::BufferDescriptorInfo info{}; - Config config = mComposerClient->getActiveConfig(mPrimaryDisplay); - info.width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, - IComposerClient::Attribute::WIDTH); - info.height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, - IComposerClient::Attribute::HEIGHT); + info.width = mDisplayWidth; + info.height = mDisplayHeight; info.layerCount = 1; - info.format = static_cast<common::V1_0::PixelFormat>(pixelFormat); + info.format = static_cast<common::V1_0::PixelFormat>(mReadbackPixelFormat); // BufferUsage::COMPOSER_OUTPUT is missing info.usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); @@ -292,7 +460,49 @@ TEST_F(GraphicsComposerHidlTest, setReadbackBuffer) { mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer, -1); } -TEST_F(GraphicsComposerHidlTest, getReadbackBufferFenceInactive) { +/** + * Test IComposerClient::setReadbackBuffer + * + * Test that IComposerClient::setReadbackBuffer returns an Error::BAD_DISPLAY + * when passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) { + if (!mHasReadbackBuffer) { + return; + } + + IMapper::BufferDescriptorInfo info{}; + info.width = mDisplayWidth; + info.height = mDisplayHeight; + info.layerCount = 1; + info.format = static_cast<common::V1_0::PixelFormat>(mReadbackPixelFormat); + info.usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); + + std::unique_ptr<Gralloc> gralloc; + const native_handle_t* buffer; + ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>()); + ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(info)); + + Error error = mComposerClient->getRaw()->setReadbackBuffer(mInvalidDisplayId, buffer, nullptr); + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/** + * Test IComposerClient::setReadbackBuffer + * + * Test that IComposerClient::setReadbackBuffer returns Error::BAD_PARAMETER + * when passed an invalid buffer handle + */ +TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) { + if (!mHasReadbackBuffer) { + return; + } + + Error error = mComposerClient->getRaw()->setReadbackBuffer(mPrimaryDisplay, nullptr, nullptr); + ASSERT_EQ(Error::BAD_PARAMETER, error); +} + +TEST_F(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) { if (!mHasReadbackBuffer) { return; } @@ -313,14 +523,38 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) { mWriter->selectDisplay(mPrimaryDisplay); mWriter->selectLayer(layer); + mWriter->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR); mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0}); mWriter->setLayerFloatColor(IComposerClient::FloatColor{0.0, 0.0, 0.0, 0.0}); + execute(); + + if (mReader->mErrors.size() == 2 && + static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED && + static_cast<Error>(mReader->mErrors[1].second) == Error::UNSUPPORTED) { + mReader->mErrors.clear(); + GTEST_SUCCEED() << "SetLayerFloatColor is not supported"; + return; + } + + // ensure setting float color on layer with composition type that is not + // SOLID_COLOR does not fail + V2_1::Layer clientLayer; + ASSERT_NO_FATAL_FAILURE(clientLayer = + mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(clientLayer); + mWriter->setLayerCompositionType(IComposerClient::Composition::CLIENT); + mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0}); + execute(); + + // At this point we know that this function is supported so there should be + // no errors (checked upon TearDown) } /** * Test IComposerClient::getDataspaceSaturationMatrix. */ -TEST_F(GraphicsComposerHidlTest, getDataspaceSaturationMatrix) { +TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) { auto matrix = mComposerClient->getDataspaceSaturationMatrix(Dataspace::SRGB_LINEAR); // the last row is known ASSERT_EQ(0.0f, matrix[12]); @@ -329,6 +563,19 @@ TEST_F(GraphicsComposerHidlTest, getDataspaceSaturationMatrix) { ASSERT_EQ(1.0f, matrix[15]); } +/* + * Test IComposerClient::getDataspaceSaturationMatrix + * + * Test that IComposerClient::getDataspaceSaturationMatrix returns + * Error::BAD_PARAMETER when passed a dataspace other than + * Dataspace::SRGB_LINEAR + */ +TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) { + mComposerClient->getRaw()->getDataspaceSaturationMatrix( + Dataspace::UNKNOWN, + [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_PARAMETER, tmpError); }); +} + /** * Test IComposerClient::getColorMode_2_2. */ @@ -339,10 +586,22 @@ TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2) { EXPECT_NE(modes.cend(), nativeMode); } +/* + * Test IComposerClient::getColorMode_2_2 + * + * Test that IComposerClient::getColorMode returns Error::BAD_DISPLAY when + * passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) { + mComposerClient->getRaw()->getColorModes_2_2( + mInvalidDisplayId, + [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); }); +} + /** - * Test IComposerClient::getRenderIntent. + * Test IComposerClient::getRenderIntents. */ -TEST_F(GraphicsComposerHidlTest, GetRenderIntent) { +TEST_F(GraphicsComposerHidlTest, GetRenderIntents) { std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay); for (auto mode : modes) { std::vector<RenderIntent> intents = @@ -366,6 +625,33 @@ TEST_F(GraphicsComposerHidlTest, GetRenderIntent) { } } +/* + * Test IComposerClient::getRenderIntents + * + * Test that IComposerClient::getRenderIntent returns Error::BAD_DISPLAY when + * passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) { + std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay); + for (auto mode : modes) { + mComposerClient->getRaw()->getRenderIntents( + mInvalidDisplayId, mode, + [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_DISPLAY, tmpError); }); + } +} + +/* + * Test IComposerClient::getRenderIntents + * + * Test that IComposerClient::getRenderIntents returns Error::BAD_PARAMETER when + * pased either an invalid Color mode or an invalid Render Intent + */ +TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) { + mComposerClient->getRaw()->getRenderIntents( + mPrimaryDisplay, static_cast<ColorMode>(-1), + [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); }); +} + /** * Test IComposerClient::setColorMode_2_2. */ @@ -378,6 +664,37 @@ TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2) { mComposerClient->setColorMode(mPrimaryDisplay, mode, intent); } } + + mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE, RenderIntent::COLORIMETRIC); +} + +/* + * Test IComposerClient::setColorMode_2_2 + * + * Test that IComposerClient::setColorMode_2_2 returns an Error::BAD_DISPLAY + * when passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) { + Error error = mComposerClient->getRaw()->setColorMode_2_2(mInvalidDisplayId, ColorMode::NATIVE, + RenderIntent::COLORIMETRIC); + + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/* + * Test IComposerClient::setColorMode_2_2 + * + * Test that IComposerClient::setColorMode_2_2 returns Error::BAD_PARAMETER when + * passed an invalid Color mode or an invalid render intent + */ +TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) { + Error colorModeError = mComposerClient->getRaw()->setColorMode_2_2( + mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC); + EXPECT_EQ(Error::BAD_PARAMETER, colorModeError); + + Error renderIntentError = mComposerClient->getRaw()->setColorMode_2_2( + mPrimaryDisplay, ColorMode::NATIVE, static_cast<RenderIntent>(-1)); + EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError); } } // namespace diff --git a/graphics/composer/2.3/Android.bp b/graphics/composer/2.3/Android.bp new file mode 100644 index 0000000000..6d29348269 --- /dev/null +++ b/graphics/composer/2.3/Android.bp @@ -0,0 +1,23 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.graphics.composer@2.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IComposer.hal", + "IComposerClient.hal", + ], + interfaces: [ + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hidl.base@1.0", + ], + gen_java: false, +} + diff --git a/audio/effect/4.0/default/EnvironmentalReverbEffect.h b/graphics/composer/2.3/IComposer.hal index c0fb25c02c..90b2427c7c 100644 --- a/audio/effect/4.0/default/EnvironmentalReverbEffect.h +++ b/graphics/composer/2.3/IComposer.hal @@ -14,17 +14,24 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_ENVIRONMENTALREVERBEFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_ENVIRONMENTALREVERBEFFECT_H +package android.hardware.graphics.composer@2.3; -#include <system/audio_effects/effect_environmentalreverb.h> +import IComposerClient; -#include <android/hardware/audio/effect/4.0/IEnvironmentalReverbEffect.h> +import @2.1::Error; +import @2.2::IComposer; -#include "Effect.h" +interface IComposer extends @2.2::IComposer { -#define AUDIO_HAL_VERSION V4_0 -#include <effect/all-versions/default/EnvironmentalReverbEffect.h> -#undef AUDIO_HAL_VERSION + /** + * Creates a v2.3 client of the composer. Supersedes @2.1::createClient. + * + * @return error is NONE upon success. Otherwise, + * NO_RESOURCES when the client could not be created. + * @return client is the newly created client. + */ + @entry + @callflow(next="*") + createClient_2_3() generates (Error error, IComposerClient client); -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_ENVIRONMENTALREVERBEFFECT_H +}; diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal new file mode 100644 index 0000000000..a3b7792c05 --- /dev/null +++ b/graphics/composer/2.3/IComposerClient.hal @@ -0,0 +1,500 @@ +/* + * 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. + */ + +package android.hardware.graphics.composer@2.3; + +import android.hardware.graphics.common@1.1::RenderIntent; +import android.hardware.graphics.common@1.2::PixelFormat; +import android.hardware.graphics.common@1.2::ColorMode; +import android.hardware.graphics.common@1.2::Dataspace; +import android.hardware.graphics.common@1.2::Hdr; +import android.hardware.graphics.composer@2.1::IComposerClient.Command; +import @2.2::IComposerClient; +import @2.1::Display; +import @2.1::Error; + +interface IComposerClient extends @2.2::IComposerClient { + + // Bug: Move this enum to LLNDK after we decide where to put graphic types. + /** + * Required capabilities which are supported by the display. The + * particular set of supported capabilities for a given display may be + * retrieved using getDisplayCapabilities. + */ + enum DisplayCapability : uint32_t { + INVALID = 0, + + /** + * Indicates that the display must apply a color transform even when + * either the client or the device has chosen that all layers should + * be composed by the client. This prevents the client from applying + * the color transform during its composition step. + * If getDisplayCapabilities is supported, the global capability + * SKIP_CLIENT_COLOR_TRANSFORM is ignored. + * If getDisplayCapabilities is not supported, and the global capability + * SKIP_CLIENT_COLOR_TRANSFORM is returned by getCapabilities, + * then all displays must be treated as having + * SKIP_CLIENT_COLOR_TRANSFORM. + */ + SKIP_CLIENT_COLOR_TRANSFORM = 1, + + /** + * Indicates that the display supports PowerMode::DOZE and + * PowerMode::DOZE_SUSPEND. DOZE_SUSPEND may not provide any benefit + * over DOZE (see the definition of PowerMode for more information), + * but if both DOZE and DOZE_SUSPEND are no different from + * PowerMode::ON, the device must not claim support. + * Must be returned by getDisplayCapabilities when getDozeSupport + * indicates the display supports PowerMode::DOZE and + * PowerMode::DOZE_SUSPEND. + */ + DOZE = 2, + }; + + //Bug: Move this enum to LLNDK after we decide where to put graphic types. + /** + * PerFrameMetadataKey + * + * A set of PerFrameMetadataKey pertains specifically to blob-formatted + * metadata (as opposed to float-valued metadata). + * The list of keys that represent blobs are: + * 1. HDR10_PLUS_SEI + */ + enum PerFrameMetadataKey : @2.2::IComposerClient.PerFrameMetadataKey { + /**HDR10+ metadata + * Specifies a metadata blob adhering to + * the ST2094-40 SEI message spec, Version 1.0 + */ + HDR10_PLUS_SEI, + }; + + /** + * PerFrameMetadata + * This struct encapsulates float-valued + * metadata - key must not be in the list + * of keys representing blob-formatted metadata + * (see PerFrameMetadataKey) + */ + struct PerFrameMetadata { + PerFrameMetadataKey key; + float value; + }; + + /** + * PerFrameMetadataBlob + * This struct encapsulates blob + * metadata - key must be one of the list of keys + * associated with blob-type metadata key + * and the blob must adhere to the format specified by + * that key (See PerFrameMetadataKey). + */ + struct PerFrameMetadataBlob { + PerFrameMetadataKey key; + vec<uint8_t> blob; + }; + + enum Command : @2.2::IComposerClient.Command { + /** + * SET_LAYER_COLOR_TRANSFORM has this pseudo prototype + * + * setLayerColorTransform(float[16] matrix); + * + * This command has the following binary layout in bytes: + * + * 0 - 16 * 4: matrix + * + * Sets a matrix for color transform which will be applied on this layer + * before composition. + * + * If the device is not capable of apply the matrix on this layer, it must force + * this layer to client composition during VALIDATE_DISPLAY. + * + * The matrix provided is an affine color transformation of the following + * form: + * + * |r.r r.g r.b 0| + * |g.r g.g g.b 0| + * |b.r b.g b.b 0| + * |Tr Tg Tb 1| + * + * This matrix must be provided in row-major form: + * + * {r.r, r.g, r.b, 0, g.r, ...}. + * + * Given a matrix of this form and an input color [R_in, G_in, B_in], + * the input color must first be converted to linear space + * [R_linear, G_linear, B_linear], then the output linear color + * [R_out_linear, G_out_linear, B_out_linear] will be: + * + * R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr + * G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg + * B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb + * + * [R_out_linear, G_out_linear, B_out_linear] must then be converted to + * gamma space: [R_out, G_out, B_out] before blending. + * + * @param matrix is a 4x4 transform matrix (16 floats) as described above. + */ + SET_LAYER_COLOR_TRANSFORM = 0x40d << @2.1::IComposerClient.Command:OPCODE_SHIFT, + + /* SET_LAYER_PER_FRAME_METADATA_BLOBS has this pseudo prototype + * + * setLayerPerFrameMetadataBlobs(Display display, Layer layer, + * vec<PerFrameMetadataBlob> metadata); + * + * This command sends metadata that may be used for tone-mapping the + * associated layer. The metadata structure follows a {key, blob} + * format (see the PerFrameMetadataBlob struct). All keys must be + * returned by a prior call to getPerFrameMetadataKeys and must + * be part of the list of keys associated with blob-type metadata + * (see PerFrameMetadataKey). + * + * This method may be called every frame. + */ + SET_LAYER_PER_FRAME_METADATA_BLOBS = 0x304 << @2.1::IComposerClient.Command:OPCODE_SHIFT, + }; + + /** + * Returns the port and data that describe a physical display. The port is + * a unique number that identifies a physical connector (e.g. eDP, HDMI) + * for display output. The data blob is parsed to determine its format, + * typically EDID 1.3 as specified in VESA E-EDID Standard Release A + * Revision 1. + * + * @param display is the display to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * UNSUPPORTED when identification data is unavailable. + * @return port is the connector to which the display is connected. + * @return data is the EDID 1.3 blob identifying the display. + */ + @callflow(next="*") + getDisplayIdentificationData(Display display) + generates (Error error, + uint8_t port, + vec<uint8_t> data); + /** + * getReadbackBufferAttributes_2_3 + * Returns the format which should be used when allocating a buffer for use by + * device readback as well as the dataspace in which its contents must be + * interpreted. + * + * The width and height of this buffer must be those of the currently-active + * display configuration, and the usage flags must consist of the following: + * BufferUsage::CPU_READ | BufferUsage::GPU_TEXTURE | + * BufferUsage::COMPOSER_OUTPUT + * + * The format and dataspace provided must be sufficient such that if a + * correctly-configured buffer is passed into setReadbackBuffer, filled by + * the device, and then displayed by the client as a full-screen buffer, the + * output of the display remains the same (subject to the note about protected + * content in the description of setReadbackBuffer). + * + * If the active configuration or color mode of this display has changed + * since a previous call to this function, it must be called again prior to + * setting a readback buffer such that the returned format and dataspace will + * be updated accordingly. + * + * Parameters: + * @param display - the display on which to create the layer. + * + * @return format - the format the client should use when allocating a device + * readback buffer + * @return dataspace - the dataspace to use when interpreting the + * contents of a device readback buffer + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * UNSUPPORTED if not supported on underlying HAL + * + * See also: + * setReadbackBuffer + * getReadbackBufferFence + */ + getReadbackBufferAttributes_2_3(Display display) + generates (Error error, + PixelFormat format, + Dataspace dataspace); + + /** + * getClientTargetSupport_2_3 + * Returns whether a client target with the given properties can be + * handled by the device. + * + * This function must return true for a client target with width and + * height equal to the active display configuration dimensions, + * PixelFormat::RGBA_8888, and Dataspace::UNKNOWN. It is not required to + * return true for any other configuration. + * + * @param display is the display to query. + * @param width is the client target width in pixels. + * @param height is the client target height in pixels. + * @param format is the client target format. + * @param dataspace is the client target dataspace, as described in + * setLayerDataspace. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * UNSUPPORTED when the given configuration is not supported. + */ + @callflow(next="*") + getClientTargetSupport_2_3(Display display, + uint32_t width, + uint32_t height, + PixelFormat format, + Dataspace dataspace) + generates (Error error); + + enum FormatColorComponent : uint8_t { + /* The first component (eg, for RGBA_8888, this is R) */ + FORMAT_COMPONENT_0 = 1 << 0, + /* The second component (eg, for RGBA_8888, this is G) */ + FORMAT_COMPONENT_1 = 1 << 1, + /* The third component (eg, for RGBA_8888, this is B) */ + FORMAT_COMPONENT_2 = 1 << 2, + /* The fourth component (eg, for RGBA_8888, this is A) */ + FORMAT_COMPONENT_3 = 1 << 3, + }; + + /** + * Query for what types of color sampling the hardware supports. + * + * @param display is the display where the samples are collected. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display was passed in, or + * UNSUPPORTED when there is no efficient way to sample. + * @return format The format of the sampled pixels. + * @return dataspace The dataspace of the sampled pixels. + * @return componentMask The mask of which components can be sampled. + */ + getDisplayedContentSamplingAttributes(Display display) + generates (Error error, + PixelFormat format, + Dataspace dataspace, + bitfield<FormatColorComponent> componentMask); + + /** DisplayedContentSampling values passed to setDisplayedContentSamplingEnabled. */ + enum DisplayedContentSampling : int32_t { + INVALID = 0, + + /** Enable content sampling. */ + ENABLE = 1, + + /** Disable content sampling. */ + DISABLE = 2, + }; + + /** + * Enables or disables the collection of color content statistics + * on this display. + * + * Sampling occurs on the contents of the final composition on this display + * (i.e., the contents presented on screen). Samples should be collected after all + * color transforms have been applied. + * + * Sampling support is optional, and is set to DISABLE by default. + * On each call to ENABLE, all collected statistics must be reset. + * + * Sample data can be queried via getDisplayedContentSample(). + * + * @param display is the display to which the sampling mode is set. + * @param enabled indicates whether to enable or disable sampling. + * @param componentMask The mask of which components should be sampled. If zero, all supported + * components are to be enabled. + * @param maxFrames is the maximum number of frames that should be stored before discard. + * The sample represents the most-recently posted frames. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in, + * BAD_PARAMETER when enabled was an invalid value, or + * NO_RESOURCES when the requested ringbuffer size via maxFrames was + * not available. + * UNSUPPORTED when there is no efficient way to sample. + */ + setDisplayedContentSamplingEnabled( + Display display, DisplayedContentSampling enable, + bitfield<FormatColorComponent> componentMask, uint64_t maxFrames) + generates (Error error); + + /** + * Collects the results of display content color sampling for display. + * + * Collection of data can occur whether the sampling is in ENABLE or + * DISABLE state. + * + * @param display is the display to which the sampling is collected. + * @param maxFrames is the maximum number of frames that should be represented in the sample. + * The sample represents the most-recently posted frames. + * If maxFrames is 0, all frames are to be represented by the sample. + * @param timestamp is the timestamp after which any frames were posted that should be + * included in the sample. Timestamp is CLOCK_MONOTONIC. + * If timestamp is 0, do not filter from the sample by time. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display was passed in, or + * UNSUPPORTED when there is no efficient way to sample, or + * BAD_PARAMETER when the component is not supported by the hardware. + * @return frameCount The number of frames represented by this sample. + * @return sampleComponent0 is a histogram counting how many times a pixel of a given value + * was displayed onscreen for FORMAT_COMPONENT_0. + * The buckets of the histogram are evenly weighted, the number of buckets + * is device specific. + * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that + * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels + * were displayed onscreen in range 0x40->0x7F, etc. + * @return sampleComponent1 is the same sample definition as sampleComponent0, + * but for FORMAT_COMPONENT_1. + * @return sampleComponent2 is the same sample definition as sampleComponent0, + * but for FORMAT_COMPONENT_2. + * @return sampleComponent3 is the same sample definition as sampleComponent0, + * but for FORMAT_COMPONENT_3. + */ + getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp) + generates (Error error, + uint64_t frameCount, + vec<uint64_t> sampleComponent0, + vec<uint64_t> sampleComponent1, + vec<uint64_t> sampleComponent2, + vec<uint64_t> sampleComponent3); + + /** + * Executes commands from the input command message queue. Return values + * generated by the input commands are written to the output command + * message queue in the form of value commands. + * + * @param inLength is the length of input commands. + * @param inHandles is an array of handles referenced by the input + * commands. + * @return error is NONE upon success. Otherwise, + * BAD_PARAMETER when inLength is not equal to the length of + * commands in the input command message queue. + * NO_RESOURCES when the output command message queue was not + * properly drained. + * @param outQueueChanged indicates whether the output command message + * queue has changed. + * @param outLength is the length of output commands. + * @param outHandles is an array of handles referenced by the output + * commands. + */ + executeCommands_2_3(uint32_t inLength, + vec<handle> inHandles) + generates (Error error, + bool outQueueChanged, + uint32_t outLength, + vec<handle> outHandles); + + /** + * Returns the render intents supported by the specified display and color + * mode. + * + * For SDR color modes, RenderIntent::COLORIMETRIC must be supported. For + * HDR color modes, RenderIntent::TONE_MAP_COLORIMETRIC must be supported. + * + * @param display is the display to query. + * @param mode is the color mode to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_PARAMETER when an invalid color mode was passed in. + * @return intents is an array of render intents. + */ + getRenderIntents_2_3(Display display, ColorMode mode) + generates (Error error, + vec<RenderIntent> intents); + + /** + * Returns the color modes supported on this display. + * + * All devices must support at least ColorMode::NATIVE. + * + * @param display is the display to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return modes is an array of color modes. + */ + getColorModes_2_3(Display display) + generates (Error error, + vec<ColorMode> modes); + + /** + * Sets the color mode and render intent of the given display. + * + * The color mode and render intent change must take effect on next + * presentDisplay. + * + * All devices must support at least ColorMode::NATIVE and + * RenderIntent::COLORIMETRIC, and displays are assumed to be in this mode + * upon hotplug. + * + * @param display is the display to which the color mode is set. + * @param mode is the color mode to set to. + * @param intent is the render intent to set to. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_PARAMETER when mode or intent is invalid + * UNSUPPORTED when mode or intent is not supported on this + * display. + */ + setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) + generates (Error error); + + /** + * Provides a list of supported capabilities (as described in the + * definition of DisplayCapability above). This list must not change after + * initialization. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return capabilities is a list of supported capabilities. + */ + getDisplayCapabilities(Display display) + generates (Error error, + vec<DisplayCapability> capabilities); + + /** + * Returns the PerFrameMetadataKeys that are supported by this device. + * + * @param display is the display on which to create the layer. + * @return keys is the vector of PerFrameMetadataKey keys that are + * supported by this device. + * @return error is NONE upon success. Otherwise, + * UNSUPPORTED if not supported on underlying HAL + */ + getPerFrameMetadataKeys_2_3(Display display) + generates (Error error, + vec<PerFrameMetadataKey> keys); + + /** + * Returns the high dynamic range (HDR) capabilities of the given display, + * which are invariant with regard to the active configuration. + * + * Displays which are not HDR-capable must return no types. + * + * @param display is the display to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return types is an array of HDR types, may have 0 elements if the + * display is not HDR-capable. + * @return maxLuminance is the desired content maximum luminance for this + * display in cd/m^2. + * @return maxAverageLuminance - the desired content maximum frame-average + * luminance for this display in cd/m^2. + * @return minLuminance is the desired content minimum luminance for this + * display in cd/m^2. + */ + @callflow(next="*") + getHdrCapabilities_2_3(Display display) + generates (Error error, + vec<Hdr> types, + float maxLuminance, + float maxAverageLuminance, + float minLuminance); +}; diff --git a/graphics/composer/2.3/default/Android.bp b/graphics/composer/2.3/default/Android.bp new file mode 100644 index 0000000000..07afd6c9a6 --- /dev/null +++ b/graphics/composer/2.3/default/Android.bp @@ -0,0 +1,46 @@ +// +// 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. +// + +cc_binary { + name: "android.hardware.graphics.composer@2.3-service", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: ["service.cpp"], + init_rc: ["android.hardware.graphics.composer@2.3-service.rc"], + header_libs: [ + "android.hardware.graphics.composer@2.3-passthrough", + ], + shared_libs: [ + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "libbase", + "libbinder", + "libcutils", + "libfmq", + "libhardware", + "libhidlbase", + "libhidltransport", + "libhwc2on1adapter", + "libhwc2onfbadapter", + "liblog", + "libsync", + "libutils", + ], +} diff --git a/graphics/composer/2.3/default/OWNERS b/graphics/composer/2.3/default/OWNERS new file mode 100644 index 0000000000..820ebe6b1b --- /dev/null +++ b/graphics/composer/2.3/default/OWNERS @@ -0,0 +1,5 @@ +# Graphics team +jessehall@google.com +lpy@google.com +stoza@google.com +vhau@google.com diff --git a/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc new file mode 100644 index 0000000000..08e32d8f13 --- /dev/null +++ b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc @@ -0,0 +1,6 @@ +service vendor.hwcomposer-2-3 /vendor/bin/hw/android.hardware.graphics.composer@2.3-service + class hal animation + user system + group graphics drmrpc + capabilities SYS_NICE + onrestart restart surfaceflinger diff --git a/graphics/composer/2.3/default/service.cpp b/graphics/composer/2.3/default/service.cpp new file mode 100644 index 0000000000..347d8be278 --- /dev/null +++ b/graphics/composer/2.3/default/service.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 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 <sched.h> + +#include <android/hardware/graphics/composer/2.3/IComposer.h> +#include <binder/ProcessState.h> +#include <composer-passthrough/2.3/HwcLoader.h> +#include <hidl/HidlTransportSupport.h> + +using android::hardware::graphics::composer::V2_3::IComposer; +using android::hardware::graphics::composer::V2_3::passthrough::HwcLoader; + +int main() { + // the conventional HAL might start binder services + android::ProcessState::initWithDriver("/dev/vndbinder"); + android::ProcessState::self()->setThreadPoolMaxThreadCount(4); + android::ProcessState::self()->startThreadPool(); + + // same as SF main thread + struct sched_param param = {0}; + param.sched_priority = 2; + if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO: %d", errno); + } + + android::hardware::configureRpcThreadpool(4, true /* will join */); + + android::sp<IComposer> composer = HwcLoader::load(); + if (composer == nullptr) { + return 1; + } + if (composer->registerAsService() != android::NO_ERROR) { + ALOGE("failed to register service"); + return 1; + } + + android::hardware::joinRpcThreadpool(); + + ALOGE("service is terminating"); + return 1; +} diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS new file mode 100644 index 0000000000..b3ea6bef7b --- /dev/null +++ b/graphics/composer/2.3/utils/OWNERS @@ -0,0 +1,8 @@ +# Graphics team +lpy@google.com +stoza@google.com +vhau@google.com + +# VTS team +yim@google.com +zhuoyao@google.com diff --git a/graphics/composer/2.3/utils/command-buffer/Android.bp b/graphics/composer/2.3/utils/command-buffer/Android.bp new file mode 100644 index 0000000000..c48fe7a53c --- /dev/null +++ b/graphics/composer/2.3/utils/command-buffer/Android.bp @@ -0,0 +1,15 @@ +cc_library_headers { + name: "android.hardware.graphics.composer@2.3-command-buffer", + defaults: ["hidl_defaults"], + vendor_available: true, + shared_libs: [ + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", + ], + header_libs: [ + "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.2-command-buffer", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h new file mode 100644 index 0000000000..11863faced --- /dev/null +++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h @@ -0,0 +1,146 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warn "ComposerCommandBuffer.h included without LOG_TAG" +#endif + +#undef LOG_NDEBUG +#define LOG_NDEBUG 0 + +#include <android/hardware/graphics/composer/2.3/IComposer.h> +#include <android/hardware/graphics/composer/2.3/IComposerClient.h> +#include <composer-command-buffer/2.2/ComposerCommandBuffer.h> +#include <limits> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { + +using android::hardware::MessageQueue; +using android::hardware::graphics::common::V1_2::Dataspace; +using android::hardware::graphics::composer::V2_1::Error; +using android::hardware::graphics::composer::V2_1::IComposerCallback; +using android::hardware::graphics::composer::V2_1::Layer; +using android::hardware::graphics::composer::V2_3::IComposerClient; + +// This class helps build a command queue. Note that all sizes/lengths are in +// units of uint32_t's. +class CommandWriterBase : public V2_2::CommandWriterBase { + public: + void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) { + beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA, + metadataVec.size() * 2); + for (const auto& metadata : metadataVec) { + writeSigned(static_cast<int32_t>(metadata.key)); + writeFloat(metadata.value); + } + endCommand(); + } + + void setLayerDataspace(Dataspace dataspace) { + setLayerDataspaceInternal(static_cast<int32_t>(dataspace)); + } + + void setClientTarget(uint32_t slot, const native_handle_t* target, int acquireFence, + Dataspace dataspace, const std::vector<IComposerClient::Rect>& damage) { + setClientTargetInternal(slot, target, acquireFence, static_cast<int32_t>(dataspace), + damage); + } + + CommandWriterBase(uint32_t initialMaxSize) : V2_2::CommandWriterBase(initialMaxSize) {} + + static constexpr uint16_t kSetLayerColorTransformLength = 16; + void setLayerColorTransform(const float* matrix) { + beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM, + kSetLayerColorTransformLength); + for (int i = 0; i < 16; i++) { + writeFloat(matrix[i]); + } + endCommand(); + } + + void setLayerPerFrameMetadataBlobs( + const hidl_vec<IComposerClient::PerFrameMetadataBlob>& metadata) { + size_t commandLength = 0; + + if (metadata.size() > std::numeric_limits<uint32_t>::max()) { + LOG_FATAL("too many metadata blobs - dynamic metadata size is too large"); + return; + } + + // number of blobs + commandLength += metadata.size(); + + for (auto metadataBlob : metadata) { + commandLength += sizeof(int32_t); // key of metadata blob + commandLength += 1; // size information of metadata blob + + // metadata content size + size_t metadataSize = metadataBlob.blob.size() / sizeof(uint32_t); + commandLength += metadataSize; + commandLength += + (metadataBlob.blob.size() - (metadataSize * sizeof(uint32_t)) > 0) ? 1 : 0; + } + + if (commandLength > std::numeric_limits<uint16_t>::max()) { + LOG_FATAL("dynamic metadata size is too large"); + return; + } + + // Blobs are written as: + // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...} + uint16_t length = static_cast<uint16_t>(commandLength); + beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length); + write(static_cast<uint32_t>(metadata.size())); + for (auto metadataBlob : metadata) { + writeSigned(static_cast<int32_t>(metadataBlob.key)); + write(static_cast<uint32_t>(metadataBlob.blob.size())); + writeBlob(static_cast<uint32_t>(metadataBlob.blob.size()), metadataBlob.blob.data()); + } + endCommand(); + } + + protected: + void beginCommand_2_3(IComposerClient::Command command, uint16_t length) { + V2_2::CommandWriterBase::beginCommand_2_2( + static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length); + } + + void writeBlob(uint32_t length, const unsigned char* blob) { + memcpy(&mData[mDataWritten], blob, length); + uint32_t numElements = length / 4; + mDataWritten += numElements; + mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0; + } +}; + +// This class helps parse a command queue. Note that all sizes/lengths are in +// units of uint32_t's. +class CommandReaderBase : public V2_2::CommandReaderBase { + public: + CommandReaderBase() : V2_2::CommandReaderBase(){}; +}; + +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/audio/common/4.0/default/Android.bp b/graphics/composer/2.3/utils/hal/Android.bp index 57b2e01f3d..3ee930050c 100644 --- a/audio/common/4.0/default/Android.bp +++ b/graphics/composer/2.3/utils/hal/Android.bp @@ -12,36 +12,25 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// -cc_library_shared { - name: "android.hardware.audio.common@4.0-util", +cc_library_headers { + name: "android.hardware.graphics.composer@2.3-hal", defaults: ["hidl_defaults"], vendor_available: true, - vndk: { - enabled: true, - }, - srcs: [ - "HidlUtils.cpp", - ], - - export_include_dirs: ["."], - - static_libs: [ - ], - shared_libs: [ - "liblog", - "libutils", - "libhidlbase", - "android.hardware.audio.common-util", - "android.hardware.audio.common@4.0", + "android.hardware.graphics.composer@2.3", ], export_shared_lib_headers: [ - "android.hardware.audio.common-util" + "android.hardware.graphics.composer@2.3", ], - header_libs: [ - "libaudio_system_headers", - "libhardware_headers", + "android.hardware.graphics.composer@2.2-hal", + "android.hardware.graphics.composer@2.3-command-buffer", + ], + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.2-hal", + "android.hardware.graphics.composer@2.3-command-buffer", ], + export_include_dirs: ["include"], } diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h new file mode 100644 index 0000000000..8e11a5ae1a --- /dev/null +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h @@ -0,0 +1,89 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "Composer.h included without LOG_TAG" +#endif + +#include <android/hardware/graphics/composer/2.3/IComposer.h> +#include <composer-hal/2.2/Composer.h> +#include <composer-hal/2.3/ComposerClient.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace hal { + +namespace detail { + +// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal +template <typename Interface, typename Hal> +class ComposerImpl : public V2_2::hal::detail::ComposerImpl<Interface, Hal> { + public: + static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) { + return std::make_unique<ComposerImpl>(std::move(hal)); + } + + explicit ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_2(std::move(hal)) {} + + // IComposer 2.3 interface + + Return<void> createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) override { + std::unique_lock<std::mutex> lock(mClientMutex); + if (!waitForClientDestroyedLocked(lock)) { + hidl_cb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + sp<ComposerClient> client = ComposerClient::create(mHal.get()).release(); + if (!client) { + hidl_cb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + auto clientDestroyed = [this]() { onClientDestroyed(); }; + client->setOnClientDestroyed(clientDestroyed); + + mClient = client; + hidl_cb(Error::NONE, client); + return Void(); + } + + private: + using BaseType2_2 = V2_2::hal::detail::ComposerImpl<Interface, Hal>; + using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>; + + using BaseType2_1::mClient; + using BaseType2_1::mClientMutex; + using BaseType2_1::mHal; + using BaseType2_1::onClientDestroyed; + using BaseType2_1::waitForClientDestroyedLocked; +}; + +} // namespace detail + +using Composer = detail::ComposerImpl<IComposer, ComposerHal>; + +} // namespace hal +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h new file mode 100644 index 0000000000..a272e72d74 --- /dev/null +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h @@ -0,0 +1,199 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "ComposerClient.h included without LOG_TAG" +#endif + +#include <android/hardware/graphics/composer/2.3/IComposerClient.h> +#include <composer-hal/2.2/ComposerResources.h> +#include <composer-hal/2.3/ComposerClient.h> +#include <composer-hal/2.3/ComposerCommandEngine.h> +#include <composer-hal/2.3/ComposerHal.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace hal { + +namespace detail { + +// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal +template <typename Interface, typename Hal> +class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl<Interface, Hal> { + public: + Return<void> getPerFrameMetadataKeys_2_3( + Display display, IComposerClient::getPerFrameMetadataKeys_2_3_cb hidl_cb) override { + std::vector<IComposerClient::PerFrameMetadataKey> keys; + Error error = mHal->getPerFrameMetadataKeys_2_3(display, &keys); + hidl_cb(error, keys); + return Void(); + } + + Return<Error> setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) override { + return mHal->setColorMode_2_3(display, mode, intent); + } + + Return<void> getRenderIntents_2_3(Display display, ColorMode mode, + IComposerClient::getRenderIntents_2_3_cb hidl_cb) override { + std::vector<RenderIntent> intents; + Error err = mHal->getRenderIntents_2_3(display, mode, &intents); + hidl_cb(err, intents); + return Void(); + } + + Return<void> getColorModes_2_3(Display display, + IComposerClient::getColorModes_2_3_cb hidl_cb) override { + hidl_vec<ColorMode> modes; + Error err = mHal->getColorModes_2_3(display, &modes); + hidl_cb(err, modes); + return Void(); + } + + Return<void> getReadbackBufferAttributes_2_3( + Display display, IComposerClient::getReadbackBufferAttributes_2_3_cb hidl_cb) override { + PixelFormat format = PixelFormat::RGB_888; + Dataspace dataspace = Dataspace::UNKNOWN; + Error error = mHal->getReadbackBufferAttributes_2_3(display, &format, &dataspace); + hidl_cb(error, format, dataspace); + return Void(); + } + + Return<void> getHdrCapabilities_2_3( + Display display, IComposerClient::getHdrCapabilities_2_3_cb hidl_cb) override { + hidl_vec<Hdr> types; + float max_lumi = 0.0f; + float max_avg_lumi = 0.0f; + float min_lumi = 0.0f; + Error err = + mHal->getHdrCapabilities_2_3(display, &types, &max_lumi, &max_avg_lumi, &min_lumi); + hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi); + return Void(); + } + + Return<Error> getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) override { + Error err = mHal->getClientTargetSupport_2_3(display, width, height, format, dataspace); + return err; + } + + Return<void> getDisplayCapabilities( + Display display, IComposerClient::getDisplayCapabilities_cb hidl_cb) override { + hidl_vec<IComposerClient::DisplayCapability> capabilities; + Error error = mHal->getDisplayCapabilities(display, &capabilities); + hidl_cb(error, capabilities); + return Void(); + } + + static std::unique_ptr<ComposerClientImpl> create(Hal* hal) { + auto client = std::make_unique<ComposerClientImpl>(hal); + return client->init() ? std::move(client) : nullptr; + } + + ComposerClientImpl(Hal* hal) : BaseType2_2(hal) {} + + // IComposerClient 2.3 interface + + Return<void> getDisplayIdentificationData( + Display display, IComposerClient::getDisplayIdentificationData_cb hidl_cb) override { + uint8_t port = 0; + std::vector<uint8_t> data; + Error error = mHal->getDisplayIdentificationData(display, &port, &data); + hidl_cb(error, port, data); + return Void(); + } + + Return<void> getDisplayedContentSamplingAttributes( + uint64_t display, + IComposerClient::getDisplayedContentSamplingAttributes_cb hidl_cb) override { + PixelFormat format; + common::V1_2::Dataspace dataspace; + hidl_bitfield<IComposerClient::FormatColorComponent> componentMask; + Error error = + mHal->getDisplayedContentSamplingAttributes(display, format, dataspace, componentMask); + hidl_cb(error, format, dataspace, componentMask); + return Void(); + } + + Return<Error> setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, + uint64_t maxFrames) override { + return mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames); + } + + Return<void> getDisplayedContentSample( + uint64_t display, uint64_t maxFrames, uint64_t timestamp, + IComposerClient::getDisplayedContentSample_cb hidl_cb) override { + uint64_t frameCount; + hidl_vec<uint64_t> sampleComponent0; + hidl_vec<uint64_t> sampleComponent1; + hidl_vec<uint64_t> sampleComponent2; + hidl_vec<uint64_t> sampleComponent3; + + Error error = mHal->getDisplayedContentSample(display, maxFrames, timestamp, frameCount, + sampleComponent0, sampleComponent1, + sampleComponent2, sampleComponent3); + hidl_cb(error, frameCount, sampleComponent0, sampleComponent1, sampleComponent2, + sampleComponent3); + return Void(); + } + + Return<void> executeCommands_2_3(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles, + IComposerClient::executeCommands_2_2_cb hidl_cb) override { + std::lock_guard<std::mutex> lock(mCommandEngineMutex); + bool outChanged = false; + uint32_t outLength = 0; + hidl_vec<hidl_handle> outHandles; + Error error = + mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles); + + hidl_cb(error, outChanged, outLength, outHandles); + + mCommandEngine->reset(); + + return Void(); + } + + protected: + std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override { + return std::make_unique<ComposerCommandEngine>( + mHal, static_cast<V2_2::hal::ComposerResources*>(mResources.get())); + } + + private: + using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>; + using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>; + using BaseType2_1::mCommandEngine; + using BaseType2_1::mCommandEngineMutex; + using BaseType2_1::mHal; + using BaseType2_1::mResources; +}; + +} // namespace detail + +using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>; + +} // namespace hal +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h new file mode 100644 index 0000000000..1a40d962b8 --- /dev/null +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h @@ -0,0 +1,125 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "ComposerCommandEngine.h included without LOG_TAG" +#endif + +#include <composer-command-buffer/2.3/ComposerCommandBuffer.h> +#include <composer-hal/2.1/ComposerCommandEngine.h> +#include <composer-hal/2.2/ComposerCommandEngine.h> +#include <composer-hal/2.2/ComposerResources.h> +#include <composer-hal/2.3/ComposerHal.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace hal { + +class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine { + public: + ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources) + : BaseType2_2(hal, resources), mHal(hal) {} + + protected: + bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override { + switch (static_cast<IComposerClient::Command>(command)) { + case IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM: + return executeSetLayerColorTransform(length); + case IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS: + return executeSetLayerPerFrameMetadataBlobs(length); + default: + return BaseType2_2::executeCommand(command, length); + } + } + + bool executeSetLayerColorTransform(uint16_t length) { + if (length != CommandWriterBase::kSetLayerColorTransformLength) { + return false; + } + + float matrix[16]; + for (int i = 0; i < 16; i++) { + matrix[i] = readFloat(); + } + auto err = mHal->setLayerColorTransform(mCurrentDisplay, mCurrentLayer, matrix); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; + } + + bool executeSetLayerPerFrameMetadataBlobs(uint16_t length) { + // must have at least one metadata blob + // of at least size 1 in queue (i.e {/*numBlobs=*/1, key, size, blob}) + if (length < 4) { + return false; + } + + uint32_t numBlobs = read(); + length--; + + std::vector<IComposerClient::PerFrameMetadataBlob> metadata; + + for (size_t i = 0; i < numBlobs; i++) { + IComposerClient::PerFrameMetadataKey key = + static_cast<IComposerClient::PerFrameMetadataKey>(readSigned()); + uint32_t blobSize = read(); + + length -= 2; + + if (length * sizeof(uint32_t) < blobSize) { + return false; + } + + metadata.push_back({key, std::vector<uint8_t>()}); + IComposerClient::PerFrameMetadataBlob& metadataBlob = metadata.back(); + metadataBlob.blob.resize(blobSize); + readBlob(blobSize, metadataBlob.blob.data()); + } + auto err = mHal->setLayerPerFrameMetadataBlobs(mCurrentDisplay, mCurrentLayer, metadata); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + return true; + } + + void readBlob(uint32_t size, void* blob) { + memcpy(blob, &mData[mDataRead], size); + uint32_t numElements = size / sizeof(uint32_t); + mDataRead += numElements; + mDataRead += (size - numElements * sizeof(uint32_t) != 0) ? 1 : 0; + } + + private: + using BaseType2_1 = V2_1::hal::ComposerCommandEngine; + using BaseType2_1::mWriter; + using BaseType2_2 = V2_2::hal::ComposerCommandEngine; + + ComposerHal* mHal; +}; + +} // namespace hal +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h new file mode 100644 index 0000000000..a0812ad9a7 --- /dev/null +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h @@ -0,0 +1,129 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <composer-hal/2.2/ComposerHal.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace hal { + +using common::V1_1::RenderIntent; +using common::V1_2::ColorMode; +using common::V1_2::Dataspace; +using common::V1_2::Hdr; +using common::V1_2::PixelFormat; +using V2_1::Display; +using V2_1::Error; +using V2_1::Layer; + +class ComposerHal : public V2_2::hal::ComposerHal { + public: + Error getPerFrameMetadataKeys( + Display display, std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* outKeys) { + return getPerFrameMetadataKeys_2_3( + display, reinterpret_cast<std::vector<IComposerClient::PerFrameMetadataKey>*>(outKeys)); + } + + Error setColorMode_2_2(Display display, common::V1_1::ColorMode mode, + RenderIntent intent) override { + return setColorMode_2_3(display, static_cast<ColorMode>(mode), intent); + } + + Error getColorModes_2_2(Display display, hidl_vec<common::V1_1::ColorMode>* outModes) override { + return getColorModes_2_3(display, reinterpret_cast<hidl_vec<ColorMode>*>(outModes)); + } + + Error getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height, + common::V1_1::PixelFormat format, + common::V1_1::Dataspace dataspace) override { + return getClientTargetSupport_2_3(display, width, height, static_cast<PixelFormat>(format), + static_cast<Dataspace>(dataspace)); + } + + Error getReadbackBufferAttributes(Display display, common::V1_1::PixelFormat* outFormat, + common::V1_1::Dataspace* outDataspace) override { + return getReadbackBufferAttributes_2_3(display, reinterpret_cast<PixelFormat*>(outFormat), + reinterpret_cast<Dataspace*>(outDataspace)); + } + + Error getHdrCapabilities(Display display, hidl_vec<common::V1_0::Hdr>* outTypes, + float* outMaxLuminance, float* outMaxAverageLuminance, + float* outMinLuminance) override { + return getHdrCapabilities_2_3(display, reinterpret_cast<hidl_vec<Hdr>*>(outTypes), + outMaxLuminance, outMaxAverageLuminance, outMinLuminance); + } + + Error setLayerPerFrameMetadata( + Display display, Layer layer, + const std::vector<V2_2::IComposerClient::PerFrameMetadata>& metadata) override { + return setLayerPerFrameMetadata_2_3( + display, layer, + reinterpret_cast<const std::vector<IComposerClient::PerFrameMetadata>&>(metadata)); + } + + virtual Error getPerFrameMetadataKeys_2_3( + Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0; + + virtual Error setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) = 0; + + virtual Error getRenderIntents_2_3(Display display, ColorMode mode, + std::vector<RenderIntent>* outIntents) = 0; + + virtual Error getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) = 0; + + virtual Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) = 0; + virtual Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat, + Dataspace* outDataspace) = 0; + virtual Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes, + float* outMaxLuminance, float* outMaxAverageLuminance, + float* outMinLuminance) = 0; + virtual Error setLayerPerFrameMetadata_2_3( + Display display, Layer layer, + const std::vector<IComposerClient::PerFrameMetadata>& metadata) = 0; + virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector<uint8_t>* outData) = 0; + virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0; + virtual Error getDisplayedContentSamplingAttributes( + uint64_t display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) = 0; + virtual Error setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) = 0; + virtual Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, + uint64_t timestamp, uint64_t& frameCount, + hidl_vec<uint64_t>& sampleComponent0, + hidl_vec<uint64_t>& sampleComponent1, + hidl_vec<uint64_t>& sampleComponent2, + hidl_vec<uint64_t>& sampleComponent3) = 0; + virtual Error getDisplayCapabilities( + Display display, hidl_vec<IComposerClient::DisplayCapability>* outCapabilities) = 0; + virtual Error setLayerPerFrameMetadataBlobs( + Display display, Layer layer, + std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) = 0; +}; + +} // namespace hal +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.3/utils/passthrough/Android.bp b/graphics/composer/2.3/utils/passthrough/Android.bp new file mode 100644 index 0000000000..3ae6b1648d --- /dev/null +++ b/graphics/composer/2.3/utils/passthrough/Android.bp @@ -0,0 +1,30 @@ +// +// 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. +// + +cc_library_headers { + name: "android.hardware.graphics.composer@2.3-passthrough", + defaults: ["hidl_defaults"], + vendor: true, + header_libs: [ + "android.hardware.graphics.composer@2.2-passthrough", + "android.hardware.graphics.composer@2.3-hal", + ], + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.2-passthrough", + "android.hardware.graphics.composer@2.3-hal", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h new file mode 100644 index 0000000000..41e333ac5e --- /dev/null +++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h @@ -0,0 +1,304 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "HwcHal.h included without LOG_TAG" +#endif + +#include <type_traits> + +#include <composer-hal/2.3/ComposerHal.h> +#include <composer-passthrough/2.2/HwcHal.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace passthrough { + +namespace detail { + +using common::V1_1::RenderIntent; +using common::V1_2::ColorMode; +using common::V1_2::Dataspace; +using common::V1_2::Hdr; +using common::V1_2::PixelFormat; +using V2_1::Display; +using V2_1::Error; + +// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2 +template <typename Hal> +class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> { + public: + Error getPerFrameMetadataKeys_2_3( + Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override { + std::vector<V2_2::IComposerClient::PerFrameMetadataKey> castKeys; + Error error = getPerFrameMetadataKeys(display, &castKeys); + if (error != Error::NONE) { + return error; + } + outKeys->clear(); + for (auto key : castKeys) { + outKeys->push_back(static_cast<IComposerClient::PerFrameMetadataKey>(key)); + } + return Error::NONE; + } + + Error setLayerPerFrameMetadata_2_3( + Display display, Layer layer, + const std::vector<IComposerClient::PerFrameMetadata>& metadata) override { + return setLayerPerFrameMetadata( + display, layer, + reinterpret_cast<const std::vector<V2_2::IComposerClient::PerFrameMetadata>&>( + metadata)); + } + + Error setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) override { + return setColorMode_2_2(display, static_cast<common::V1_1::ColorMode>(mode), intent); + } + + Error getRenderIntents_2_3(Display display, ColorMode mode, + std::vector<RenderIntent>* outIntents) override { + return getRenderIntents(display, static_cast<common::V1_1::ColorMode>(mode), outIntents); + } + + Error getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) override { + return getColorModes_2_2(display, + reinterpret_cast<hidl_vec<common::V1_1::ColorMode>*>(outModes)); + } + + Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance, + float* outMaxAverageLuminance, float* outMinLuminance) override { + return getHdrCapabilities(display, reinterpret_cast<hidl_vec<common::V1_0::Hdr>*>(outTypes), + outMaxLuminance, outMaxAverageLuminance, outMinLuminance); + } + + Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) override { + return getClientTargetSupport_2_2(display, width, height, + static_cast<common::V1_1::PixelFormat>(format), + static_cast<common::V1_1::Dataspace>(dataspace)); + } + + Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat, + Dataspace* outDataspace) override { + return getReadbackBufferAttributes( + display, reinterpret_cast<common::V1_1::PixelFormat*>(outFormat), + reinterpret_cast<common::V1_1::Dataspace*>(outDataspace)); + } + + Error getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector<uint8_t>* outData) override { + if (!mDispatch.getDisplayIdentificationData) { + return Error::UNSUPPORTED; + } + + uint32_t size = 0; + int32_t error = + mDispatch.getDisplayIdentificationData(mDevice, display, outPort, &size, nullptr); + if (error != HWC2_ERROR_NONE) { + return static_cast<Error>(error); + } + + std::vector<uint8_t> data(size); + error = + mDispatch.getDisplayIdentificationData(mDevice, display, outPort, &size, data.data()); + if (error != HWC2_ERROR_NONE) { + return static_cast<Error>(error); + } + + data.resize(size); + *outData = std::move(data); + return Error::NONE; + } + + Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override { + if (!mDispatch.setLayerColorTransform) { + return Error::UNSUPPORTED; + } + int32_t err = mDispatch.setLayerColorTransform(mDevice, display, layer, matrix); + return static_cast<Error>(err); + } + + Error getDisplayedContentSamplingAttributes( + uint64_t display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) override { + if (!mDispatch.getDisplayedContentSamplingAttributes) { + return Error::UNSUPPORTED; + } + int32_t formatRaw = 0; + int32_t dataspaceRaw = 0; + uint8_t componentMaskRaw = 0; + int32_t errorRaw = mDispatch.getDisplayedContentSamplingAttributes( + mDevice, display, &formatRaw, &dataspaceRaw, &componentMaskRaw); + auto error = static_cast<Error>(errorRaw); + if (error == Error::NONE) { + format = static_cast<PixelFormat>(formatRaw); + dataspace = static_cast<Dataspace>(dataspaceRaw); + componentMask = + static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(componentMaskRaw); + } + return error; + }; + + Error setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, + uint64_t maxFrames) override { + if (!mDispatch.setDisplayedContentSamplingEnabled) { + return Error::UNSUPPORTED; + } + return static_cast<Error>(mDispatch.setDisplayedContentSamplingEnabled( + mDevice, display, static_cast<int32_t>(enable), componentMask, maxFrames)); + } + + Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp, + uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0, + hidl_vec<uint64_t>& sampleComponent1, + hidl_vec<uint64_t>& sampleComponent2, + hidl_vec<uint64_t>& sampleComponent3) override { + if (!mDispatch.getDisplayedContentSample) { + return Error::UNSUPPORTED; + } + + int32_t size[4] = {0}; + auto errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp, + &frameCount, size, nullptr); + if (errorRaw != HWC2_ERROR_NONE) { + return static_cast<Error>(errorRaw); + } + + sampleComponent0.resize(size[0]); + sampleComponent1.resize(size[1]); + sampleComponent2.resize(size[2]); + sampleComponent3.resize(size[3]); + uint64_t* samples[] = {sampleComponent0.data(), sampleComponent1.data(), + sampleComponent2.data(), sampleComponent3.data()}; + errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp, + &frameCount, size, samples); + return static_cast<Error>(errorRaw); + } + + Error getDisplayCapabilities( + Display display, hidl_vec<IComposerClient::DisplayCapability>* outCapabilities) override { + if (!mDispatch.getDisplayCapabilities) { + return Error::UNSUPPORTED; + } + + uint32_t count = 0; + int32_t error = mDispatch.getDisplayCapabilities(mDevice, display, &count, nullptr); + if (error != HWC2_ERROR_NONE) { + return static_cast<Error>(error); + } + outCapabilities->resize(count); + error = mDispatch.getDisplayCapabilities( + mDevice, display, &count, + reinterpret_cast<std::underlying_type<IComposerClient::DisplayCapability>::type*>( + outCapabilities->data())); + if (error != HWC2_ERROR_NONE) { + *outCapabilities = hidl_vec<IComposerClient::DisplayCapability>(); + return static_cast<Error>(error); + } + return Error::NONE; + } + + Error setLayerPerFrameMetadataBlobs( + Display display, Layer layer, + std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override { + if (!mDispatch.setLayerPerFrameMetadataBlobs) { + return Error::UNSUPPORTED; + } + + std::vector<IComposerClient::PerFrameMetadataKey> keys; + std::vector<uint32_t> sizes; + std::vector<uint8_t> blobs; + + for (auto metadataBlob : metadata) { + keys.push_back(metadataBlob.key); + sizes.push_back(metadataBlob.blob.size()); + + int writeIndex = blobs.size(); + blobs.resize(blobs.size() + metadataBlob.blob.size()); + memcpy(blobs.data() + writeIndex, metadataBlob.blob.data(), metadataBlob.blob.size()); + } + + int32_t err = mDispatch.setLayerPerFrameMetadataBlobs( + mDevice, display, layer, static_cast<uint32_t>(metadata.size()), + reinterpret_cast<int32_t*>(keys.data()), reinterpret_cast<uint32_t*>(sizes.data()), + blobs.data()); + return static_cast<Error>(err); + } + + protected: + bool initDispatch() override { + if (!BaseType2_2::initDispatch()) { + return false; + } + + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA, + &mDispatch.getDisplayIdentificationData); + this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM, + &mDispatch.setLayerColorTransform); + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, + &mDispatch.getDisplayedContentSamplingAttributes); + this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED, + &mDispatch.setDisplayedContentSamplingEnabled); + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE, + &mDispatch.getDisplayedContentSample); + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES, + &mDispatch.getDisplayCapabilities); + this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_PER_FRAME_METADATA_BLOBS, + &mDispatch.setLayerPerFrameMetadataBlobs); + return true; + } + + private: + struct { + HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData; + HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform; + HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES getDisplayedContentSamplingAttributes; + HWC2_PFN_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED setDisplayedContentSamplingEnabled; + HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLE getDisplayedContentSample; + HWC2_PFN_GET_DISPLAY_CAPABILITIES getDisplayCapabilities; + HWC2_PFN_SET_LAYER_PER_FRAME_METADATA_BLOBS setLayerPerFrameMetadataBlobs; + } mDispatch = {}; + + using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>; + using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>; + using BaseType2_1::getHdrCapabilities; + using BaseType2_1::mDevice; + using BaseType2_2::getClientTargetSupport_2_2; + using BaseType2_2::getColorModes_2_2; + using BaseType2_2::getPerFrameMetadataKeys; + using BaseType2_2::getReadbackBufferAttributes; + using BaseType2_2::getRenderIntents; + using BaseType2_2::setColorMode_2_2; + using BaseType2_2::setLayerPerFrameMetadata; +}; + +} // namespace detail + +using HwcHal = detail::HwcHalImpl<hal::ComposerHal>; + +} // namespace passthrough +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h new file mode 100644 index 0000000000..afef475e78 --- /dev/null +++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h @@ -0,0 +1,79 @@ +/* + * Copyright 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. + */ + +#pragma once + +#ifndef LOG_TAG +#warning "HwcLoader.h included without LOG_TAG" +#endif + +#include <composer-hal/2.3/Composer.h> +#include <composer-hal/2.3/ComposerHal.h> +#include <composer-passthrough/2.2/HwcLoader.h> +#include <composer-passthrough/2.3/HwcHal.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace passthrough { + +class HwcLoader : public V2_2::passthrough::HwcLoader { + public: + static IComposer* load() { + const hw_module_t* module = loadModule(); + if (!module) { + return nullptr; + } + + auto hal = createHalWithAdapter(module); + if (!hal) { + return nullptr; + } + + return createComposer(std::move(hal)).release(); + } + + // create a ComposerHal instance + static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) { + auto hal = std::make_unique<HwcHal>(); + return hal->initWithModule(module) ? std::move(hal) : nullptr; + } + + // create a ComposerHal instance, insert an adapter if necessary + static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) { + bool adapted; + hwc2_device_t* device = openDeviceWithAdapter(module, &adapted); + if (!device) { + return nullptr; + } + auto hal = std::make_unique<HwcHal>(); + return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr; + } + + // create an IComposer instance + static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) { + return hal::Composer::create(std::move(hal)); + } +}; + +} // namespace passthrough +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp new file mode 100644 index 0000000000..19438cbe26 --- /dev/null +++ b/graphics/composer/2.3/utils/vts/Android.bp @@ -0,0 +1,42 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.graphics.composer@2.3-vts", + defaults: ["hidl_defaults"], + srcs: [ + "ComposerVts.cpp", + ], + static_libs: [ + "VtsHalHidlTargetTestBase", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.1-vts", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.2-vts", + "android.hardware.graphics.composer@2.3", + ], + header_libs: [ + "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.2-command-buffer", + "android.hardware.graphics.composer@2.3-command-buffer", + ], + cflags: [ + "-O0", + "-g", + "-DLOG_TAG=\"ComposerVts\"", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp new file mode 100644 index 0000000000..0e541ed2e3 --- /dev/null +++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp @@ -0,0 +1,194 @@ +/* + * 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 <composer-vts/2.3/ComposerVts.h> + +#include <VtsHalHidlTargetTestBase.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace vts { + +using V2_1::Error; + +Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {} + +Composer::Composer(const std::string& name) + : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {} + +Composer::Composer(const sp<IComposer>& composer) + : V2_2::vts::Composer(composer), mComposer(composer) {} + +std::unique_ptr<ComposerClient> Composer::createClient() { + std::unique_ptr<ComposerClient> client; + mComposer->createClient_2_3([&client](const auto& tmpError, const auto& tmpClient) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create client"; + client = std::make_unique<ComposerClient>(tmpClient); + }); + + return client; +} + +sp<IComposerClient> ComposerClient::getRaw() const { + return mClient; +} + +bool ComposerClient::getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector<uint8_t>* outData) { + bool supported = true; + mClient->getDisplayIdentificationData( + display, [&](const auto& tmpError, const auto& tmpPort, const auto& tmpData) { + if (tmpError == Error::UNSUPPORTED) { + supported = false; + return; + } + ASSERT_EQ(Error::NONE, tmpError) << "failed to get display identification data"; + + *outPort = tmpPort; + *outData = tmpData; + ASSERT_FALSE(outData->empty()) << "data is empty"; + }); + + return supported; +} + +std::vector<ColorMode> ComposerClient::getColorModes_2_3(Display display) { + std::vector<ColorMode> modes; + mClient->getColorModes_2_3(display, [&](const auto& tmpError, const auto& tmpModes) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get color modes"; + modes = tmpModes; + }); + return modes; +} + +void ComposerClient::setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) { + Error error = mClient->setColorMode_2_3(display, mode, intent); + ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set color mode"; +} + +std::vector<RenderIntent> ComposerClient::getRenderIntents_2_3(Display display, ColorMode mode) { + std::vector<RenderIntent> intents; + mClient->getRenderIntents_2_3(display, mode, [&](const auto& tmpError, const auto& tmpIntents) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents"; + intents = tmpIntents; + }); + return intents; +} + +void ComposerClient::getReadbackBufferAttributes_2_3(Display display, PixelFormat* outPixelFormat, + Dataspace* outDataspace) { + mClient->getReadbackBufferAttributes_2_3( + 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; + }); +} + +bool ComposerClient::getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) { + Error error = mClient->getClientTargetSupport_2_3(display, width, height, format, dataspace); + return error == Error::NONE; +} + +std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient::getPerFrameMetadataKeys_2_3( + Display display) { + std::vector<IComposerClient::PerFrameMetadataKey> keys; + mClient->getPerFrameMetadataKeys_2_3(display, [&](const auto& tmpError, const auto& tmpKeys) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get perFrameMetadataKeys"; + keys = tmpKeys; + }); + return keys; +} + +std::vector<Hdr> ComposerClient::getHdrCapabilities_2_3(Display display, float* outMaxLuminance, + float* outMaxAverageLuminance, + float* outMinLuminance) { + std::vector<Hdr> types; + mClient->getHdrCapabilities_2_3( + display, [&](const auto& tmpError, const auto& tmpTypes, const auto& tmpMaxLuminance, + const auto& tmpMaxAverageLuminance, const auto& tmpMinLuminance) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR capabilities"; + types = tmpTypes; + *outMaxLuminance = tmpMaxLuminance; + *outMaxAverageLuminance = tmpMaxAverageLuminance; + *outMinLuminance = tmpMinLuminance; + }); + + return types; +} + +Error ComposerClient::getDisplayedContentSamplingAttributes( + uint64_t display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) { + auto error = Error::BAD_PARAMETER; + mClient->getDisplayedContentSamplingAttributes( + display, [&](const auto& tmpError, const auto& tmpFormat, const auto& tmpDataspace, + const auto& tmpComponentMask) { + error = tmpError; + format = tmpFormat; + dataspace = tmpDataspace; + componentMask = tmpComponentMask; + }); + return error; +} + +Error ComposerClient::setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) { + return mClient->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames); +} + +Error ComposerClient::getDisplayedContentSample(uint64_t display, uint64_t maxFrames, + uint64_t timestamp, uint64_t& frameCount, + hidl_vec<uint64_t>& sampleComponent0, + hidl_vec<uint64_t>& sampleComponent1, + hidl_vec<uint64_t>& sampleComponent2, + hidl_vec<uint64_t>& sampleComponent3) { + auto error = Error::BAD_PARAMETER; + mClient->getDisplayedContentSample( + display, maxFrames, timestamp, + [&](const auto& tmpError, const auto& tmpFrameCount, const auto& tmpSamples0, + const auto& tmpSamples1, const auto& tmpSamples2, const auto& tmpSamples3) { + error = tmpError; + frameCount = tmpFrameCount; + sampleComponent0 = tmpSamples0; + sampleComponent1 = tmpSamples1; + sampleComponent2 = tmpSamples2; + sampleComponent3 = tmpSamples3; + }); + return error; +} + +std::vector<IComposerClient::DisplayCapability> ComposerClient::getDisplayCapabilities( + Display display) { + std::vector<IComposerClient::DisplayCapability> capabilities; + mClient->getDisplayCapabilities( + display, [&](const auto&, const auto& tmpCapabilities) { capabilities = tmpCapabilities; }); + + return capabilities; +} + +} // namespace vts +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h new file mode 100644 index 0000000000..ad4ef0b51e --- /dev/null +++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +#pragma once + +#include <memory> +#include <vector> + +#include <VtsHalHidlTargetTestBase.h> +#include <android/hardware/graphics/composer/2.3/IComposer.h> +#include <android/hardware/graphics/composer/2.3/IComposerClient.h> +#include <composer-vts/2.2/ComposerVts.h> +#include <utils/StrongPointer.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace vts { + +using common::V1_1::RenderIntent; +using common::V1_2::ColorMode; +using common::V1_2::Dataspace; +using common::V1_2::Hdr; +using common::V1_2::PixelFormat; +using V2_1::Display; +using V2_1::Error; +using V2_3::IComposer; +using V2_3::IComposerClient; + +class ComposerClient; + +// A wrapper to IComposer. +class Composer : public V2_2::vts::Composer { + public: + Composer(); + explicit Composer(const std::string& name); + + std::unique_ptr<ComposerClient> createClient(); + + protected: + explicit Composer(const sp<IComposer>& composer); + + private: + const sp<IComposer> mComposer; +}; + +// A wrapper to IComposerClient. +class ComposerClient : public V2_2::vts::ComposerClient { + public: + explicit ComposerClient(const sp<IComposerClient>& client) + : V2_2::vts::ComposerClient(client), mClient(client) {} + + sp<IComposerClient> getRaw() const; + + bool getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector<uint8_t>* outData); + Error getDisplayedContentSamplingAttributes( + uint64_t display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask); + Error setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames); + Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp, + uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0, + hidl_vec<uint64_t>& sampleComponent1, + hidl_vec<uint64_t>& sampleComponent2, + hidl_vec<uint64_t>& sampleComponent3); + + std::vector<ColorMode> getColorModes_2_3(Display display); + + void setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent); + + std::vector<RenderIntent> getRenderIntents_2_3(Display display, ColorMode mode); + + void getReadbackBufferAttributes_2_3(Display display, PixelFormat* outPixelFormat, + Dataspace* outDataspace); + + std::vector<Hdr> getHdrCapabilities_2_3(Display display, float* outMaxLuminance, + float* outMaxAverageLuminance, float* outMinLuminance); + + bool getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace); + std::vector<IComposerClient::DisplayCapability> getDisplayCapabilities(Display display); + + std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys_2_3(Display display); + + private: + const sp<IComposerClient> mClient; +}; + +} // namespace vts +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp new file mode 100644 index 0000000000..7548cb521e --- /dev/null +++ b/graphics/composer/2.3/vts/functional/Android.bp @@ -0,0 +1,45 @@ +// +// 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. +// + +cc_test { + name: "VtsHalGraphicsComposerV2_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"], + + // TODO(b/64437680): Assume these libs are always available on the device. + shared_libs: [ + "libfmq", + "libhidltransport", + "libsync", + ], + static_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.1-vts", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.2-vts", + "android.hardware.graphics.composer@2.3", + "android.hardware.graphics.composer@2.3-vts", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.0-vts", + "android.hardware.graphics.mapper@2.1", + ], + header_libs: [ + "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.2-command-buffer", + "android.hardware.graphics.composer@2.3-command-buffer", + ], +} diff --git a/graphics/composer/2.3/vts/functional/OWNERS b/graphics/composer/2.3/vts/functional/OWNERS new file mode 100644 index 0000000000..b3ea6bef7b --- /dev/null +++ b/graphics/composer/2.3/vts/functional/OWNERS @@ -0,0 +1,8 @@ +# Graphics team +lpy@google.com +stoza@google.com +vhau@google.com + +# VTS team +yim@google.com +zhuoyao@google.com diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp new file mode 100644 index 0000000000..de74e28cc7 --- /dev/null +++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp @@ -0,0 +1,618 @@ +/* + * 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. + */ + +#define LOG_TAG "graphics_composer_hidl_hal_test@2.3" + +#include <algorithm> + +#include <VtsHalHidlTargetTestBase.h> +#include <android-base/logging.h> +#include <android/hardware/graphics/mapper/2.0/IMapper.h> +#include <composer-command-buffer/2.3/ComposerCommandBuffer.h> +#include <composer-vts/2.1/GraphicsComposerCallback.h> +#include <composer-vts/2.1/TestCommandReader.h> +#include <composer-vts/2.3/ComposerVts.h> +#include <mapper-vts/2.0/MapperVts.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace vts { +namespace { + +using common::V1_0::BufferUsage; +using common::V1_1::RenderIntent; +using common::V1_2::ColorMode; +using common::V1_2::Dataspace; +using common::V1_2::PixelFormat; +using mapper::V2_0::IMapper; +using mapper::V2_0::vts::Gralloc; + +// Test environment for graphics.composer +class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static GraphicsComposerHidlEnvironment* Instance() { + static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<IComposer>(); } + + private: + GraphicsComposerHidlEnvironment() {} + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); +}; + +class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE( + mComposer = std::make_unique<Composer>( + GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>())); + ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); + + mComposerCallback = new V2_1::vts::GraphicsComposerCallback; + mComposerClient->registerCallback(mComposerCallback); + + // assume the first display is primary and is never removed + mPrimaryDisplay = waitForFirstDisplay(); + + mInvalidDisplayId = GetInvalidDisplayId(); + + // explicitly disable vsync + mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); + mComposerCallback->setVsyncAllowed(false); + + mWriter = std::make_unique<CommandWriterBase>(1024); + mReader = std::make_unique<V2_1::vts::TestCommandReader>(); + } + + void TearDown() override { + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + if (mComposerCallback != nullptr) { + EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); + } + } + + // returns an invalid display id (one that has not been registered to a + // display. Currently assuming that a device will never have close to + // std::numeric_limit<uint64_t>::max() displays registered while running tests + Display GetInvalidDisplayId() { + std::vector<Display> validDisplays = mComposerCallback->getDisplays(); + uint64_t id = std::numeric_limits<uint64_t>::max(); + while (id > 0) { + if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) { + return id; + } + id--; + } + + return 0; + } + + void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + + // use the slot count usually set by SF + static constexpr uint32_t kBufferSlotCount = 64; + + std::unique_ptr<Composer> mComposer; + std::unique_ptr<ComposerClient> mComposerClient; + sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback; + // the first display and is assumed never to be removed + Display mPrimaryDisplay; + Display mInvalidDisplayId; + std::unique_ptr<CommandWriterBase> mWriter; + std::unique_ptr<V2_1::vts::TestCommandReader> mReader; + + private: + Display waitForFirstDisplay() { + while (true) { + std::vector<Display> displays = mComposerCallback->getDisplays(); + if (displays.empty()) { + usleep(5 * 1000); + continue; + } + + return displays[0]; + } + } +}; + +// Tests for IComposerClient::Command. +class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp()); + + ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>()); + + mWriter = std::make_unique<CommandWriterBase>(1024); + mReader = std::make_unique<V2_1::vts::TestCommandReader>(); + } + + void TearDown() override { + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); + } + + const native_handle_t* allocate() { + IMapper::BufferDescriptorInfo info{}; + info.width = 64; + info.height = 64; + info.layerCount = 1; + info.format = static_cast<common::V1_0::PixelFormat>(PixelFormat::RGBA_8888); + info.usage = + static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + + return mGralloc->allocate(info); + } + + void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + + std::unique_ptr<CommandWriterBase> mWriter; + std::unique_ptr<V2_1::vts::TestCommandReader> mReader; + + private: + std::unique_ptr<Gralloc> mGralloc; +}; + +/** + * Test IComposerClient::getDisplayIdentificationData. + * + * TODO: Check that ports are unique for multiple displays. + */ +TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) { + uint8_t port0; + std::vector<uint8_t> data0; + if (mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) { + uint8_t port1; + std::vector<uint8_t> data1; + ASSERT_TRUE(mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port1, &data1)); + + ASSERT_EQ(port0, port1) << "ports are not stable"; + ASSERT_TRUE(data0.size() == data1.size() && + std::equal(data0.begin(), data0.end(), data1.begin())) + << "data is not stable"; + } +} + +/** + * Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { + Layer layer; + ASSERT_NO_FATAL_FAILURE(layer = + mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + + /** + * DISPLAY_P3 is a color space that uses the DCI_P3 primaries, + * the D65 white point and the SRGB transfer functions. + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.265 0.690 + * blue 0.150 0.060 + * red 0.680 0.320 + * white (D65) 0.3127 0.3290 + */ + + std::vector<IComposerClient::PerFrameMetadata> hidlMetadata; + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_X, 0.3127}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_Y, 0.3290}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_LUMINANCE, 100.0}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MIN_LUMINANCE, 0.1}); + hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0}); + hidlMetadata.push_back( + {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0}); + mWriter->setLayerPerFrameMetadata(hidlMetadata); + execute(); + + if (mReader->mErrors.size() == 1 && + static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) { + mReader->mErrors.clear(); + GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported"; + ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer)); + return; + } + + ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer)); +} + +/** + * Test IComposerClient::getHdrCapabilities_2_3 + */ +TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) { + float maxLuminance; + float maxAverageLuminance; + float minLuminance; + ASSERT_NO_FATAL_FAILURE(mComposerClient->getHdrCapabilities_2_3( + mPrimaryDisplay, &maxLuminance, &maxAverageLuminance, &minLuminance)); + ASSERT_TRUE(maxLuminance >= minLuminance); +} + +/** + * Test IComposerClient::getPerFrameMetadataKeys_2_3 + */ +TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) { + std::vector<IComposerClient::PerFrameMetadataKey> keys; + mComposerClient->getRaw()->getPerFrameMetadataKeys_2_3( + mPrimaryDisplay, [&](const auto tmpError, const auto outKeys) { + if (tmpError != Error::UNSUPPORTED) { + ASSERT_EQ(Error::NONE, tmpError); + keys = outKeys; + } + }); +} + +/** + * TestIComposerClient::getReadbackBufferAttributes_2_3 + */ +TEST_F(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) { + Dataspace dataspace; + PixelFormat pixelFormat; + + mComposerClient->getRaw()->getReadbackBufferAttributes_2_3( + mPrimaryDisplay, + [&](const auto tmpError, const auto outPixelFormat, const auto outDataspace) { + if (tmpError != Error::UNSUPPORTED) { + ASSERT_EQ(Error::NONE, tmpError); + dataspace = outDataspace; + pixelFormat = outPixelFormat; + } + }); +} + +/** + * Test IComposerClient::getClientTargetSupport_2_3 + */ +TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) { + std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::WIDTH); + int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::HEIGHT); + ASSERT_LT(0, width); + ASSERT_LT(0, height); + + mComposerClient->setActiveConfig(mPrimaryDisplay, config); + + ASSERT_TRUE(mComposerClient->getClientTargetSupport_2_3( + mPrimaryDisplay, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN)); + } +} +/** + * Test IComposerClient::getClientTargetSupport_2_3 + * + * Test that IComposerClient::getClientTargetSupport_2_3 returns + * Error::BAD_DISPLAY when passed in an invalid display handle + */ + +TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) { + std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::WIDTH); + int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, + IComposerClient::Attribute::HEIGHT); + ASSERT_LT(0, width); + ASSERT_LT(0, height); + + mComposerClient->setActiveConfig(mPrimaryDisplay, config); + + Error error = mComposerClient->getRaw()->getClientTargetSupport_2_3( + mInvalidDisplayId, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN); + + EXPECT_EQ(Error::BAD_DISPLAY, error); + } +} + +/** + * Test IComposerClient::getRenderIntents_2_3 + */ +TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3) { + std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); + for (auto mode : modes) { + std::vector<RenderIntent> intents = + mComposerClient->getRenderIntents_2_3(mPrimaryDisplay, mode); + + bool isHdr; + switch (mode) { + case ColorMode::BT2100_PQ: + case ColorMode::BT2100_HLG: + isHdr = true; + break; + default: + isHdr = false; + break; + } + RenderIntent requiredIntent = + isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC; + + auto iter = std::find(intents.cbegin(), intents.cend(), requiredIntent); + EXPECT_NE(intents.cend(), iter); + } +} + +/* + * Test IComposerClient::getRenderIntents_2_3 + * + * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_DISPLAY when + * passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) { + std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); + for (auto mode : modes) { + mComposerClient->getRaw()->getRenderIntents_2_3( + mInvalidDisplayId, mode, + [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_DISPLAY, tmpError); }); + } +} + +/* + * Test IComposerClient::getRenderIntents_2_3 + * + * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_PARAMETER when + * pased either an invalid Color mode or an invalid Render Intent + */ +TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) { + mComposerClient->getRaw()->getRenderIntents_2_3( + mPrimaryDisplay, static_cast<ColorMode>(-1), + [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); }); +} + +/** + * IComposerClient::getColorModes_2_3 + */ +TEST_F(GraphicsComposerHidlTest, GetColorModes_2_3) { + std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); + + auto native = std::find(colorModes.cbegin(), colorModes.cend(), ColorMode::NATIVE); + ASSERT_NE(colorModes.cend(), native); +} + +/* + * Test IComposerClient::getColorModes_2_3 + * + * Test that IComposerClient::getColorModes_2_3 returns Error::BAD_DISPLAY when + * passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) { + mComposerClient->getRaw()->getColorModes_2_3( + mInvalidDisplayId, + [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); }); +} + +/** + * IComposerClient::setColorMode_2_3 + */ +TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3) { + std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); + for (auto mode : colorModes) { + std::vector<RenderIntent> intents = + mComposerClient->getRenderIntents_2_3(mPrimaryDisplay, mode); + for (auto intent : intents) { + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode_2_3(mPrimaryDisplay, mode, intent)); + } + } + + ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode_2_3(mPrimaryDisplay, ColorMode::NATIVE, + RenderIntent::COLORIMETRIC)); +} + +/* + * Test IComposerClient::setColorMode_2_3 + * + * Test that IComposerClient::setColorMode_2_3 returns an Error::BAD_DISPLAY + * when passed an invalid display handle + */ +TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) { + Error error = mComposerClient->getRaw()->setColorMode_2_3(mInvalidDisplayId, ColorMode::NATIVE, + RenderIntent::COLORIMETRIC); + + ASSERT_EQ(Error::BAD_DISPLAY, error); +} + +/* + * Test IComposerClient::setColorMode_2_3 + * + * Test that IComposerClient::setColorMode_2_3 returns Error::BAD_PARAMETER when + * passed an invalid Color mode or an invalid render intent + */ +TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) { + Error colorModeError = mComposerClient->getRaw()->setColorMode_2_3( + mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC); + EXPECT_EQ(Error::BAD_PARAMETER, colorModeError); + + Error renderIntentError = mComposerClient->getRaw()->setColorMode_2_3( + mPrimaryDisplay, ColorMode::NATIVE, static_cast<RenderIntent>(-1)); + EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError); +} + +/** + * Test IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM. + * TODO Add color to the layer, use matrix to keep only red component, + * and check. + */ +TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) { + Layer layer; + ASSERT_NO_FATAL_FAILURE(layer = + mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + + // clang-format off + const std::array<float, 16> matrix = {{ + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }}; + // clang-format on + + mWriter->setLayerColorTransform(matrix.data()); + execute(); + + if (mReader->mErrors.size() == 1 && + static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) { + mReader->mErrors.clear(); + GTEST_SUCCEED() << "setLayerColorTransform is not supported"; + return; + } +} + +TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) { + int constexpr invalid = -1; + auto format = static_cast<PixelFormat>(invalid); + auto dataspace = static_cast<Dataspace>(invalid); + auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid); + auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format, + dataspace, componentMask); + + if (error == Error::UNSUPPORTED) { + SUCCEED() << "Device does not support optional extension. Test skipped"; + return; + } + + EXPECT_EQ(error, Error::NONE); + EXPECT_NE(format, static_cast<PixelFormat>(invalid)); + EXPECT_NE(dataspace, static_cast<Dataspace>(invalid)); + EXPECT_NE(componentMask, + static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid)); +}; + +TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) { + auto const maxFrames = 10; + auto const enableAllComponents = 0; + auto error = mComposerClient->setDisplayedContentSamplingEnabled( + mPrimaryDisplay, IComposerClient::DisplayedContentSampling::ENABLE, enableAllComponents, + maxFrames); + if (error == Error::UNSUPPORTED) { + SUCCEED() << "Device does not support optional extension. Test skipped"; + return; + } + EXPECT_EQ(error, Error::NONE); + + error = mComposerClient->setDisplayedContentSamplingEnabled( + mPrimaryDisplay, IComposerClient::DisplayedContentSampling::DISABLE, enableAllComponents, + maxFrames); + EXPECT_EQ(error, Error::NONE); +} + +TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) { + int constexpr invalid = -1; + auto format = static_cast<PixelFormat>(invalid); + auto dataspace = static_cast<Dataspace>(invalid); + auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid); + auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format, + dataspace, componentMask); + + uint64_t maxFrames = 10; + uint64_t timestamp = 0; + uint64_t frameCount = 0; + hidl_array<hidl_vec<uint64_t>, 4> histogram; + error = mComposerClient->getDisplayedContentSample(mPrimaryDisplay, maxFrames, timestamp, + frameCount, histogram[0], histogram[1], + histogram[2], histogram[3]); + if (error == Error::UNSUPPORTED) { + SUCCEED() << "Device does not support optional extension. Test skipped"; + return; + } + + EXPECT_EQ(error, Error::NONE); + EXPECT_LE(frameCount, maxFrames); + for (auto i = 0; i < histogram.size(); i++) { + if (componentMask & (1 << i)) { + EXPECT_NE(histogram[i].size(), 0); + } else { + EXPECT_EQ(histogram[i].size(), 0); + } + } +} + +/* + * getDisplayCapabilities is required in composer 2.3 + * Test some constraints. + */ +TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) { + auto capabilities = mComposerClient->getDisplayCapabilities(mPrimaryDisplay); + bool hasDozeSupport = std::find(capabilities.begin(), capabilities.end(), + IComposerClient::DisplayCapability::DOZE) != capabilities.end(); + EXPECT_EQ(mComposerClient->getDozeSupport(mPrimaryDisplay), hasDozeSupport); +} + +TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { + mComposerClient->getRaw()->getDisplayCapabilities( + mInvalidDisplayId, + [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_DISPLAY, tmpError); }); +} + +TEST_F(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) { + Layer layer; + ASSERT_NO_FATAL_FAILURE(layer = + mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + + std::vector<IComposerClient::PerFrameMetadataBlob> metadata; + metadata.push_back( + {IComposerClient::PerFrameMetadataKey::HDR10_PLUS_SEI, std::vector<uint8_t>(1, 0xff)}); + + mWriter->setLayerPerFrameMetadataBlobs(metadata); + execute(); + + if (mReader->mErrors.size() == 1 && + static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) { + mReader->mErrors.clear(); + GTEST_SUCCEED() << "setLayerDynamicPerFrameMetadata is not supported"; + return; + } +} + +} // namespace +} // namespace vts +} // namespace V2_3 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android + +int main(int argc, char** argv) { + using android::hardware::graphics::composer::V2_3::vts::GraphicsComposerHidlEnvironment; + ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + return status; +} diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp index aa9beff735..5ec0af2cda 100644 --- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp +++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp @@ -16,6 +16,10 @@ #define LOG_TAG "VtsHalGraphicsMapperV2_0TargetTest" +#include <chrono> +#include <thread> +#include <vector> + #include <VtsHalHidlTargetTestBase.h> #include <android-base/logging.h> #include <mapper-vts/2.0/MapperVts.h> @@ -125,6 +129,36 @@ TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) { } /** + * Test that IAllocator::allocate is thread-safe. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) { + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo)); + + std::atomic<bool> timeUp(false); + std::atomic<uint64_t> allocationCount(0); + auto threadLoop = [&]() { + while (!timeUp) { + mGralloc->getAllocator()->allocate( + descriptor, 1, [&](const auto&, const auto&, const auto&) { allocationCount++; }); + } + }; + + std::vector<std::thread> threads; + for (int i = 0; i < 8; i++) { + threads.push_back(std::thread(threadLoop)); + } + + std::this_thread::sleep_for(std::chrono::seconds(3)); + timeUp = true; + LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations"; + + for (auto& thread : threads) { + thread.join(); + } +} + +/** * Test IMapper::createDescriptor with valid descriptor info. */ TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) { diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h index 08d604e906..c9836e5447 100644 --- a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h +++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h @@ -28,7 +28,7 @@ namespace passthrough { using V2_0::BufferDescriptor; using V2_0::Error; -using android::hardware::graphics::common::V1_0::BufferUsage; +using android::hardware::graphics::common::V1_1::BufferUsage; namespace detail { @@ -72,6 +72,8 @@ class Gralloc1HalImpl : public V2_0::passthrough::detail::Gralloc1HalImpl<Hal> { Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo, BufferDescriptor* outDescriptor) override { + if (gralloc1UsageUnsupported(descriptorInfo.usage)) + return Error::BAD_DESCRIPTOR; return createDescriptor( V2_0::IMapper::BufferDescriptorInfo{ descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount, @@ -163,6 +165,16 @@ class Gralloc1HalImpl : public V2_0::passthrough::detail::Gralloc1HalImpl<Hal> { return consumerUsage; } + static bool gralloc1UsageUnsupported(uint64_t usage) { + // Certain newer public usage bits should not be used with gralloc1. + // We use a blacklist instead of a whitelist here in order to avoid + // breaking private usage flags. + constexpr uint64_t unsupportedMask = BufferUsage::GPU_CUBE_MAP | + BufferUsage::GPU_MIPMAP_COMPLETE; + + return usage & unsupportedMask; + } + private: using BaseType2_0 = V2_0::passthrough::detail::Gralloc1HalImpl<Hal>; using BaseType2_0::createDescriptor; diff --git a/graphics/mapper/3.0/Android.bp b/graphics/mapper/3.0/Android.bp new file mode 100644 index 0000000000..b2f0aa69b5 --- /dev/null +++ b/graphics/mapper/3.0/Android.bp @@ -0,0 +1,26 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.graphics.mapper@3.0", + root: "android.hardware", + vndk: { + enabled: true, + support_system_process: true, + }, + srcs: [ + "types.hal", + "IMapper.hal", + ], + interfaces: [ + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hidl.base@1.0", + ], + types: [ + "Error", + "YCbCrLayout", + ], + gen_java: false, +} + diff --git a/graphics/mapper/3.0/IMapper.hal b/graphics/mapper/3.0/IMapper.hal new file mode 100644 index 0000000000..a0e4d7afc7 --- /dev/null +++ b/graphics/mapper/3.0/IMapper.hal @@ -0,0 +1,304 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.mapper@3.0; + +import android.hardware.graphics.common@1.1::BufferUsage; +import android.hardware.graphics.common@1.1::PixelFormat; +import android.hardware.graphics.common@1.2::Rect; + +interface IMapper { + struct BufferDescriptorInfo { + /** + * The width specifies how many columns of pixels must be in the + * allocated buffer, but does not necessarily represent the offset in + * columns between the same column in adjacent rows. The rows may be + * padded. + */ + uint32_t width; + + /** + * The height specifies how many rows of pixels must be in the + * allocated buffer. + */ + uint32_t height; + + /** + * The number of image layers that must be in the allocated buffer. + */ + uint32_t layerCount; + + /** Buffer pixel format. */ + PixelFormat format; + + /** + * Buffer usage mask; valid flags can be found in the definition of + * BufferUsage. + */ + bitfield<BufferUsage> usage; + }; + + struct Rect { + int32_t left; + int32_t top; + int32_t width; + int32_t height; + }; + + /** + * Creates a buffer descriptor. The descriptor can be used with IAllocator + * to allocate buffers. + * + * Since the buffer descriptor fully describes a buffer, any device + * dependent or device independent checks must be performed here whenever + * possible. Specifically, when layered buffers are not supported, this + * function must return `UNSUPPORTED` if `description.layers` is great than + * 1. + * + * @param description Attributes of the descriptor. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_VALUE` if any of the specified attributes are invalid or + * inconsistent. + * - `NO_RESOURCES` if the creation cannot be fullfilled due to + * unavailability of resources. + * - `UNSUPPORTED` when any of the specified attributes are not + * supported. + * @return descriptor Newly created buffer descriptor. + */ + createDescriptor(BufferDescriptorInfo description) + generates (Error error, + BufferDescriptor descriptor); + + /** + * Imports a raw buffer handle to create an imported buffer handle for use + * with the rest of the mapper or with other in-process libraries. + * + * A buffer handle is considered raw when it is cloned (e.g., with + * `native_handle_clone()`) from another buffer handle locally, or when it + * is received from another HAL server/client or another process. A raw + * buffer handle must not be used to access the underlying graphic + * buffer. It must be imported to create an imported handle first. + * + * This function must at least validate the raw handle before creating the + * imported handle. It must also support importing the same raw handle + * multiple times to create multiple imported handles. The imported handle + * must be considered valid everywhere in the process, including in + * another instance of the mapper. + * + * Because of passthrough HALs, a raw buffer handle received from a HAL + * may actually have been imported in the process. importBuffer() must treat + * such a handle as if it is raw and must not return `BAD_BUFFER`. The + * returned handle is independent from the input handle as usual, and + * freeBuffer() must be called on it when it is no longer needed. + * + * @param rawHandle Raw buffer handle to import. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the raw handle is invalid. + * - `NO_RESOURCES` if the raw handle cannot be imported due to + * unavailability of resources. + * @return buffer Imported buffer handle that has the type + * `buffer_handle_t` which is a handle type. + */ + importBuffer(handle rawHandle) generates (Error error, pointer buffer); + + /** + * Frees a buffer handle. Buffer handles returned by importBuffer() must be + * freed with this function when no longer needed. + * + * This function must free up all resources allocated by importBuffer() for + * the imported handle. For example, if the imported handle was created + * with `native_handle_create()`, this function must call + * `native_handle_close()` and `native_handle_delete()`. + * + * @param buffer Imported buffer handle. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid. + */ + freeBuffer(pointer buffer) generates (Error error); + + /** + * Validates that the buffer can be safely accessed by a caller who assumes + * the specified @p description and @p stride. This must at least validate + * that the buffer size is large enough. Validating the buffer against + * individual buffer attributes is optional. + * + * @param buffer Buffer to validate against. + * @param description Attributes of the buffer. + * @param stride Stride returned by IAllocator::allocate(). + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid. + * - `BAD_VALUE` if the buffer cannot be safely accessed. + */ + validateBufferSize(pointer buffer, + BufferDescriptorInfo description, + uint32_t stride) + generates (Error error); + + /** + * Calculates the transport size of a buffer. An imported buffer handle is a + * raw buffer handle with the process-local runtime data appended. This + * function, for example, allows a caller to omit the process-local runtime + * data at the tail when serializing the imported buffer handle. + * + * Note that a client might or might not omit the process-local runtime data + * when sending an imported buffer handle. The mapper must support both + * cases on the receiving end. + * + * @param buffer Buffer to get the transport size from. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid. + * @return numFds The number of file descriptors needed for transport. + * @return numInts The number of integers needed for transport. + */ + getTransportSize(pointer buffer) + generates (Error error, + uint32_t numFds, + uint32_t numInts); + + /** + * Locks the given buffer for the specified CPU usage. + * + * Locking the same buffer simultaneously from multiple threads is + * permitted, but if any of the threads attempt to lock the buffer for + * writing, the behavior is undefined, except that it must not cause + * process termination or block the client indefinitely. Leaving the + * buffer content in an indeterminate state or returning an error are both + * acceptable. + * + * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must + * "lock in place". The buffers must be directly accessible via mapping. + * + * The client must not modify the content of the buffer outside of + * @p accessRegion, and the device need not guarantee that content outside + * of @p accessRegion is valid for reading. The result of reading or writing + * outside of @p accessRegion is undefined, except that it must not cause + * process termination. + * + * On success, @p data must be filled with a pointer to the locked buffer + * memory. This address will represent the top-left corner of the entire + * buffer, even if @p accessRegion does not begin at the top-left corner. + * + * On success, bytesPerPixel must contain the number of bytes per pixel in + * the buffer. If the bytesPerPixel is unknown or variable, a value of -1 + * should be returned. bytesPerStride must contain the bytes per stride of + * the buffer. If the bytesPerStride is unknown or variable, a value of -1 + * should be returned. + * + * @param buffer Buffer to lock. + * @param cpuUsage CPU usage flags to request. See +ndk + * libnativewindow#AHardwareBuffer_UsageFlags for possible values. + * @param accessRegion Portion of the buffer that the client intends to + * access. + * @param acquireFence Handle containing a file descriptor referring to a + * sync fence object, which will be signaled when it is safe for the + * mapper to lock the buffer. @p acquireFence may be an empty fence if + * it is already safe to lock. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this + * function. + * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or + * is incompatible with the buffer. + * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note + * that locking may succeed at a later time. + * @return data CPU-accessible pointer to the buffer data. + * @return bytesPerPixel the number of bytes per pixel in the buffer + * @return bytesPerStride the number of bytes per stride of the buffer + */ + lock(pointer buffer, + uint64_t cpuUsage, + Rect accessRegion, + handle acquireFence) + generates (Error error, + pointer data, + int32_t bytesPerPixel, + int32_t bytesPerStride); + + /** + * Locks a YCbCr buffer for the specified CPU usage. + * + * This is largely the same as lock(), except that instead of returning a + * pointer directly to the buffer data, it returns a `YCbCrLayout` struct + * describing how to access the data planes. + * + * This function must work on buffers with + * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well + * as with any other formats requested by multimedia codecs when they are + * configured with a flexible-YUV-compatible color format. + * + * @param buffer Buffer to lock. + * @param cpuUsage CPU usage flags to request. See +ndk + * libnativewindow#AHardwareBuffer_UsageFlags for possible values. + * @param accessRegion Portion of the buffer that the client intends to + * access. + * @param acquireFence Handle containing a file descriptor referring to a + * sync fence object, which will be signaled when it is safe for the + * mapper to lock the buffer. @p acquireFence may be empty if it is + * already safe to lock. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this + * function. + * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or + * is incompatible with the buffer. + * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note + * that locking may succeed at a later time. + * @return layout Data layout of the locked buffer. + */ + lockYCbCr(pointer buffer, + uint64_t cpuUsage, + Rect accessRegion, + handle acquireFence) + generates (Error error, + YCbCrLayout layout); + + /** + * Unlocks a buffer to indicate all CPU accesses to the buffer have + * completed. + * + * @param buffer Buffer to unlock. + * @return error Error status of the call, which may be + * - `NONE` upon success. + * - `BAD_BUFFER` if the buffer is invalid or not locked. + * @return releaseFence Handle containing a file descriptor referring to a + * sync fence object. The sync fence object will be signaled when the + * mapper has completed any pending work. @p releaseFence may be an + * empty fence. + */ + unlock(pointer buffer) generates (Error error, handle releaseFence); + + /** + * Test whether the given BufferDescriptorInfo is allocatable. + * + * If this function returns true, it means that a buffer with the given + * description can be allocated on this implementation, unless resource + * exhaustion occurs. If this function returns false, it means that the + * allocation of the given description will never succeed. + * + * @param description the description of the buffer + * @return supported whether the description is supported + */ + isSupported(BufferDescriptorInfo description) + generates (Error error, + bool supported); + +}; + diff --git a/graphics/mapper/3.0/types.hal b/graphics/mapper/3.0/types.hal new file mode 100644 index 0000000000..f94abd3964 --- /dev/null +++ b/graphics/mapper/3.0/types.hal @@ -0,0 +1,84 @@ +/* + * Copyright 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. + */ + +package android.hardware.graphics.mapper@3.0; + +/** + * Error values that may be returned by a method of IAllocator or IMapper. + */ +enum Error : int32_t { + /** + * No error. + */ + NONE = 0, + /** + * Invalid BufferDescriptor. + */ + BAD_DESCRIPTOR = 1, + /** + * Invalid buffer handle. + */ + BAD_BUFFER = 2, + /** + * Invalid HardwareBufferDescription. + */ + BAD_VALUE = 3, + /** + * Resource unavailable. + */ + NO_RESOURCES = 5, + /** + * Permanent failure. + */ + UNSUPPORTED = 7, +}; + +/** + * A buffer descriptor is an implementation-defined opaque data returned by + * createDescriptor(). It describes the properties of a buffer and is consumed + * by the allocator. + */ +typedef vec<uint32_t> BufferDescriptor; + +/** + * Structure for describing YCbCr formats for consumption by applications. + * This is used with PixelFormat::YCBCR_*_888. + * + * Buffer chroma subsampling is defined in the format. + * e.g. PixelFormat::YCBCR_420_888 has subsampling 4:2:0. + * + * Buffers must have a 8 bit depth. + * + * y, cb, and cr point to the first byte of their respective planes. + * + * Stride describes the distance in bytes from the first value of one row of + * the image to the first value of the next row. It includes the width of the + * image plus padding. + * yStride is the stride of the luma plane. + * cStride is the stride of the chroma planes. + * + * chromaStep is the distance in bytes from one chroma pixel value to the + * next. This is 2 bytes for semiplanar (because chroma values are interleaved + * and each chroma value is one byte) and 1 for planar. + */ +struct YCbCrLayout { + pointer y; + pointer cb; + pointer cr; + uint32_t yStride; + uint32_t cStride; + uint32_t chromaStep; +}; diff --git a/graphics/mapper/3.0/utils/OWNERS b/graphics/mapper/3.0/utils/OWNERS new file mode 100644 index 0000000000..96f6d51573 --- /dev/null +++ b/graphics/mapper/3.0/utils/OWNERS @@ -0,0 +1,3 @@ +# Graphics team +marissaw@google.com +stoza@google.com diff --git a/graphics/mapper/3.0/utils/vts/Android.bp b/graphics/mapper/3.0/utils/vts/Android.bp new file mode 100644 index 0000000000..c3d480a565 --- /dev/null +++ b/graphics/mapper/3.0/utils/vts/Android.bp @@ -0,0 +1,34 @@ +// +// 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. +// + +cc_library_static { + name: "android.hardware.graphics.mapper@3.0-vts", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["MapperVts.cpp"], + cflags: [ + "-O0", + "-g", + ], + static_libs: [ + "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.mapper@3.0", + ], + export_static_lib_headers: [ + "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.mapper@3.0", + ], + export_include_dirs: ["include"], +} diff --git a/graphics/mapper/3.0/utils/vts/MapperVts.cpp b/graphics/mapper/3.0/utils/vts/MapperVts.cpp new file mode 100644 index 0000000000..f2b7594b3f --- /dev/null +++ b/graphics/mapper/3.0/utils/vts/MapperVts.cpp @@ -0,0 +1,288 @@ +/* + * Copyright 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 <mapper-vts/3.0/MapperVts.h> + +#include <VtsHalHidlTargetTestBase.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V3_0 { +namespace vts { + +Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName) { + init(allocatorServiceName, mapperServiceName); +} + +void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) { + mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName); + ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service"; + + mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName); + ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service"; + ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; +} + +Gralloc::~Gralloc() { + for (auto bufferHandle : mClonedBuffers) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + native_handle_close(buffer); + native_handle_delete(buffer); + } + mClonedBuffers.clear(); + + for (auto bufferHandle : mImportedBuffers) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer; + } + mImportedBuffers.clear(); +} + +sp<IAllocator> Gralloc::getAllocator() const { + return mAllocator; +} + +std::string Gralloc::dumpDebugInfo() { + std::string debugInfo; + mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); + + return debugInfo; +} + +const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) { + const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle()); + EXPECT_NE(nullptr, bufferHandle); + + if (bufferHandle) { + mClonedBuffers.insert(bufferHandle); + } + + return bufferHandle; +} + +std::vector<const native_handle_t*> Gralloc::allocate(const BufferDescriptor& descriptor, + uint32_t count, bool import, + uint32_t* outStride) { + std::vector<const native_handle_t*> bufferHandles; + bufferHandles.reserve(count); + mAllocator->allocate( + descriptor, count, + [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers"; + ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array"; + + for (uint32_t i = 0; i < count; i++) { + if (import) { + ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(importBuffer(tmpBuffers[i]))); + } else { + ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(cloneBuffer(tmpBuffers[i]))); + } + } + + if (outStride) { + *outStride = tmpStride; + } + }); + + if (::testing::Test::HasFatalFailure()) { + bufferHandles.clear(); + } + + return bufferHandles; +} + +const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, + bool import, uint32_t* outStride) { + BufferDescriptor descriptor = createDescriptor(descriptorInfo); + if (::testing::Test::HasFatalFailure()) { + return nullptr; + } + + auto buffers = allocate(descriptor, 1, import, outStride); + if (::testing::Test::HasFatalFailure()) { + return nullptr; + } + + return buffers[0]; +} + +sp<IMapper> Gralloc::getMapper() const { + return mMapper; +} + +BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) { + BufferDescriptor descriptor; + mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor"; + descriptor = tmpDescriptor; + }); + + return descriptor; +} + +const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) { + const native_handle_t* bufferHandle = nullptr; + mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to import buffer %p" << rawHandle.getNativeHandle(); + bufferHandle = static_cast<const native_handle_t*>(tmpBuffer); + }); + + if (bufferHandle) { + mImportedBuffers.insert(bufferHandle); + } + + return bufferHandle; +} + +void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + if (mImportedBuffers.erase(bufferHandle)) { + Error error = mMapper->freeBuffer(buffer); + ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer; + } else { + mClonedBuffers.erase(bufferHandle); + native_handle_close(buffer); + native_handle_delete(buffer); + } +} + +void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); + hidl_handle acquireFenceHandle; + if (acquireFence >= 0) { + auto h = native_handle_init(acquireFenceStorage, 1, 0); + h->data[0] = acquireFence; + acquireFenceHandle = h; + } + + *outBytesPerPixel = -1; + *outBytesPerStride = -1; + + void* data = nullptr; + mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpData, int32_t tmpBytesPerPixel, + int32_t tmpBytesPerStride) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer; + data = tmpData; + *outBytesPerPixel = tmpBytesPerPixel; + *outBytesPerStride = tmpBytesPerStride; + }); + + if (acquireFence >= 0) { + close(acquireFence); + } + + return data; +} + +YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); + hidl_handle acquireFenceHandle; + if (acquireFence >= 0) { + auto h = native_handle_init(acquireFenceStorage, 1, 0); + h->data[0] = acquireFence; + acquireFenceHandle = h; + } + + YCbCrLayout layout = {}; + mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpLayout) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to lockYCbCr buffer " << buffer; + layout = tmpLayout; + }); + + if (acquireFence >= 0) { + close(acquireFence); + } + + return layout; +} + +int Gralloc::unlock(const native_handle_t* bufferHandle) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + int releaseFence = -1; + mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock buffer " << buffer; + + auto fenceHandle = tmpReleaseFence.getNativeHandle(); + if (fenceHandle) { + ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle; + if (fenceHandle->numFds == 1) { + releaseFence = dup(fenceHandle->data[0]); + ASSERT_LT(0, releaseFence) << "failed to dup fence fd"; + } else { + ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle; + } + } + }); + + return releaseFence; +} + +bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, + uint32_t stride) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + Error error = mMapper->validateBufferSize(buffer, descriptorInfo, stride); + return error == Error::NONE; +} + +void Gralloc::getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + *outNumFds = 0; + *outNumInts = 0; + mMapper->getTransportSize( + buffer, [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get transport size"; + ASSERT_GE(bufferHandle->numFds, int(tmpNumFds)) << "invalid numFds " << tmpNumFds; + ASSERT_GE(bufferHandle->numInts, int(tmpNumInts)) << "invalid numInts " << tmpNumInts; + + *outNumFds = tmpNumFds; + *outNumInts = tmpNumInts; + }); +} + +bool Gralloc::isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) { + bool supported = false; + mMapper->isSupported(descriptorInfo, [&](const auto& tmpError, const auto& tmpSupported) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to check is supported"; + supported = tmpSupported; + }); + return supported; +} + +} // namespace vts +} // namespace V3_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h new file mode 100644 index 0000000000..ba79ca42b7 --- /dev/null +++ b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h @@ -0,0 +1,102 @@ +/* + * Copyright 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 <string> +#include <unordered_set> +#include <vector> + +#include <android/hardware/graphics/allocator/3.0/IAllocator.h> +#include <android/hardware/graphics/mapper/3.0/IMapper.h> +#include <utils/StrongPointer.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V3_0 { +namespace vts { + +using android::hardware::graphics::allocator::V3_0::IAllocator; + +// A wrapper to IAllocator and IMapper. +class Gralloc { + public: + Gralloc(const std::string& allocatorServiceName = "default", + const std::string& mapperServiceName = "default"); + ~Gralloc(); + + // IAllocator methods + + sp<IAllocator> getAllocator() const; + + std::string dumpDebugInfo(); + + // When import is false, this simply calls IAllocator::allocate. When import + // is true, the returned buffers are also imported into the mapper. + // + // Either case, the returned buffers must be freed with freeBuffer. + std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor, uint32_t count, + bool import = true, uint32_t* outStride = nullptr); + const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, + bool import = true, uint32_t* outStride = nullptr); + + // IMapper methods + + sp<IMapper> getMapper() const; + + BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo); + + const native_handle_t* importBuffer(const hidl_handle& rawHandle); + void freeBuffer(const native_handle_t* bufferHandle); + + // We use fd instead of hidl_handle in these functions to pass fences + // in and out of the mapper. The ownership of the fd is always transferred + // with each of these functions. + void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride); + YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, int acquireFence); + int unlock(const native_handle_t* bufferHandle); + + bool validateBufferSize(const native_handle_t* bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride); + void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts); + + bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo); + + private: + void init(const std::string& allocatorServiceName, const std::string& mapperServiceName); + const native_handle_t* cloneBuffer(const hidl_handle& rawHandle); + + sp<IAllocator> mAllocator; + sp<IMapper> mMapper; + + // Keep track of all cloned and imported handles. When a test fails with + // ASSERT_*, the destructor will free the handles for the test. + std::unordered_set<const native_handle_t*> mClonedBuffers; + std::unordered_set<const native_handle_t*> mImportedBuffers; +}; + +} // namespace vts +} // namespace V3_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/graphics/mapper/3.0/vts/OWNERS b/graphics/mapper/3.0/vts/OWNERS new file mode 100644 index 0000000000..96f6d51573 --- /dev/null +++ b/graphics/mapper/3.0/vts/OWNERS @@ -0,0 +1,3 @@ +# Graphics team +marissaw@google.com +stoza@google.com diff --git a/audio/effect/2.0/vts/functional/Android.bp b/graphics/mapper/3.0/vts/functional/Android.bp index 068314f5c6..77075a5a88 100644 --- a/audio/effect/2.0/vts/functional/Android.bp +++ b/graphics/mapper/3.0/vts/functional/Android.bp @@ -1,5 +1,5 @@ // -// Copyright (C) 2016 The Android Open Source Project +// Copyright 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. @@ -15,23 +15,16 @@ // cc_test { - name: "VtsHalAudioEffectV2_0TargetTest", + name: "VtsHalGraphicsMapperV3_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], - srcs: [ - "VtsHalAudioEffectV2_0TargetTest.cpp", - "ValidateAudioEffectsConfiguration.cpp" - ], + srcs: ["VtsHalGraphicsMapperV3_0TargetTest.cpp"], static_libs: [ - "android.hardware.audio.common.test.utility", - "android.hardware.audio.common@2.0", - "android.hardware.audio.effect@2.0", - "android.hidl.allocator@1.0", - "android.hidl.memory@1.0", - "libeffectsconfig", - "libicuuc", - "libicuuc_stubdata", - "libandroidicu", - "libxml2", + "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.common@1.0", + "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@3.0-vts", ], test_suites: ["general-tests"], } diff --git a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp new file mode 100644 index 0000000000..cfae635658 --- /dev/null +++ b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp @@ -0,0 +1,493 @@ +/* + * Copyright 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. + */ + +#define LOG_TAG "VtsHalGraphicsMapperV3_0TargetTest" + +#include <chrono> +#include <thread> +#include <vector> + +#include <VtsHalHidlTargetTestBase.h> +#include <android-base/logging.h> +#include <mapper-vts/3.0/MapperVts.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V3_0 { +namespace vts { +namespace { + +using android::hardware::graphics::common::V1_0::BufferUsage; +using android::hardware::graphics::common::V1_1::PixelFormat; + +// Test environment for graphics.mapper. +class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static GraphicsMapperHidlEnvironment* Instance() { + static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { + registerTestService<IAllocator>(); + registerTestService<IMapper>(); + } +}; + +class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE( + mGralloc = std::make_unique<Gralloc>( + GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(), + GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>())); + + mDummyDescriptorInfo.width = 64; + mDummyDescriptorInfo.height = 64; + mDummyDescriptorInfo.layerCount = 1; + mDummyDescriptorInfo.format = PixelFormat::RGBA_8888; + mDummyDescriptorInfo.usage = + static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + } + + void TearDown() override {} + + std::unique_ptr<Gralloc> mGralloc; + IMapper::BufferDescriptorInfo mDummyDescriptorInfo{}; +}; + +/** + * Test IAllocator::dumpDebugInfo by calling it. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) { + mGralloc->dumpDebugInfo(); +} + +/** + * Test IAllocator::allocate with valid buffer descriptors. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) { + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo)); + + for (uint32_t count = 0; count < 5; count++) { + std::vector<const native_handle_t*> bufferHandles; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandles = + mGralloc->allocate(descriptor, count, false, &stride)); + + if (count >= 1) { + EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride"; + } + + for (auto bufferHandle : bufferHandles) { + mGralloc->freeBuffer(bufferHandle); + } + } +} + +/** + * Test IAllocator::allocate with invalid buffer descriptors. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) { + // this assumes any valid descriptor is non-empty + BufferDescriptor descriptor; + mGralloc->getAllocator()->allocate(descriptor, 1, + [&](const auto& tmpError, const auto&, const auto&) { + EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError); + }); +} + +/** + * Test IAllocator::allocate does not leak. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) { + auto info = mDummyDescriptorInfo; + info.width = 1024; + info.height = 1024; + + for (int i = 0; i < 2048; i++) { + auto bufferHandle = mGralloc->allocate(info, false); + mGralloc->freeBuffer(bufferHandle); + } +} + +/** + * Test that IAllocator::allocate is thread-safe. + */ +TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) { + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo)); + + std::atomic<bool> timeUp(false); + std::atomic<uint64_t> allocationCount(0); + auto threadLoop = [&]() { + while (!timeUp) { + mGralloc->getAllocator()->allocate( + descriptor, 1, [&](const auto&, const auto&, const auto&) { allocationCount++; }); + } + }; + + std::vector<std::thread> threads; + for (int i = 0; i < 8; i++) { + threads.push_back(std::thread(threadLoop)); + } + + std::this_thread::sleep_for(std::chrono::seconds(3)); + timeUp = true; + LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations"; + + for (auto& thread : threads) { + thread.join(); + } +} + +/** + * Test IMapper::createDescriptor with valid descriptor info. + */ +TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) { + ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo)); +} + +/** + * Test IMapper::createDescriptor with invalid descriptor info. + */ +TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) { + auto info = mDummyDescriptorInfo; + info.width = 0; + mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE"; + }); +} + +/** + * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers. + */ +TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) { + const native_handle_t* bufferHandle; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle)); +} + +/** + * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers. + */ +TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) { + const native_handle_t* clonedBufferHandle; + ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false)); + + // A cloned handle is a raw handle. Check that we can import it multiple + // times. + const native_handle_t* importedBufferHandles[2]; + ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] = mGralloc->importBuffer(clonedBufferHandle)); + ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] = mGralloc->importBuffer(clonedBufferHandle)); + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0])); + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1])); + + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle)); +} + +/** + * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances. + */ +TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) { + const native_handle_t* rawHandle; + ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false)); + + native_handle_t* importedHandle = nullptr; + mGralloc->getMapper()->importBuffer(rawHandle, [&](const auto& tmpError, const auto& buffer) { + ASSERT_EQ(Error::NONE, tmpError); + importedHandle = static_cast<native_handle_t*>(buffer); + }); + + // free the imported handle with another mapper + std::unique_ptr<Gralloc> anotherGralloc; + ASSERT_NO_FATAL_FAILURE( + anotherGralloc = std::make_unique<Gralloc>( + GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(), + GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>())); + Error error = mGralloc->getMapper()->freeBuffer(importedHandle); + ASSERT_EQ(Error::NONE, error); + + ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle)); +} + +/** + * Test IMapper::importBuffer and IMapper::freeBuffer do not leak. + */ +TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) { + auto info = mDummyDescriptorInfo; + info.width = 1024; + info.height = 1024; + + for (int i = 0; i < 2048; i++) { + auto bufferHandle = mGralloc->allocate(info, true); + mGralloc->freeBuffer(bufferHandle); + } +} + +/** + * Test IMapper::importBuffer with invalid buffers. + */ +TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) { + native_handle_t* invalidHandle = nullptr; + mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "importBuffer with nullptr did not fail with BAD_BUFFER"; + }); + + invalidHandle = native_handle_create(0, 0); + mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "importBuffer with invalid handle did not fail with BAD_BUFFER"; + }); + native_handle_delete(invalidHandle); +} + +/** + * Test IMapper::freeBuffer with invalid buffers. + */ +TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) { + native_handle_t* invalidHandle = nullptr; + Error error = mGralloc->getMapper()->freeBuffer(invalidHandle); + EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER"; + + invalidHandle = native_handle_create(0, 0); + error = mGralloc->getMapper()->freeBuffer(invalidHandle); + EXPECT_EQ(Error::BAD_BUFFER, error) + << "freeBuffer with invalid handle did not fail with BAD_BUFFER"; + native_handle_delete(invalidHandle); + + const native_handle_t* clonedBufferHandle; + ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false)); + error = mGralloc->getMapper()->freeBuffer(invalidHandle); + EXPECT_EQ(Error::BAD_BUFFER, error) + << "freeBuffer with un-imported handle did not fail with BAD_BUFFER"; + + mGralloc->freeBuffer(clonedBufferHandle); +} + +/** + * Test IMapper::lock and IMapper::unlock. + */ +TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) { + const auto& info = mDummyDescriptorInfo; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride)); + + // lock buffer for writing + const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width), + static_cast<int32_t>(info.height)}; + int fence = -1; + uint8_t* data; + int32_t bytesPerPixel = -1; + int32_t bytesPerStride = -1; + ASSERT_NO_FATAL_FAILURE( + data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence, + &bytesPerPixel, &bytesPerStride))); + + // Valid return values are -1 for unsupported or the number bytes for supported which is >=0 + EXPECT_GT(bytesPerPixel, -1); + EXPECT_GT(bytesPerStride, -1); + + // RGBA_8888 + size_t strideInBytes = stride * 4; + size_t writeInBytes = info.width * 4; + + for (uint32_t y = 0; y < info.height; y++) { + memset(data, y, writeInBytes); + data += strideInBytes; + } + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + + bytesPerPixel = -1; + bytesPerStride = -1; + + // lock again for reading + ASSERT_NO_FATAL_FAILURE( + data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence, + &bytesPerPixel, &bytesPerStride))); + for (uint32_t y = 0; y < info.height; y++) { + for (size_t i = 0; i < writeInBytes; i++) { + EXPECT_EQ(static_cast<uint8_t>(y), data[i]); + } + data += strideInBytes; + } + + EXPECT_GT(bytesPerPixel, -1); + EXPECT_GT(bytesPerStride, -1); + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + if (fence >= 0) { + close(fence); + } +} + +/** + * Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can + * write to and read from it. + */ +TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::YV12; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride)); + + // lock buffer for writing + const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width), + static_cast<int32_t>(info.height)}; + int fence = -1; + YCbCrLayout layout; + ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence)); + + auto yData = static_cast<uint8_t*>(layout.y); + auto cbData = static_cast<uint8_t*>(layout.cb); + auto crData = static_cast<uint8_t*>(layout.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast<uint8_t>(info.height * y + x); + + yData[layout.yStride * y + x] = val; + if (y % 2 == 0 && x % 2 == 0) { + cbData[layout.cStride * y / 2 + x / 2] = val; + crData[layout.cStride * y / 2 + x / 2] = val; + } + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + + // lock again for reading + ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence)); + + yData = static_cast<uint8_t*>(layout.y); + cbData = static_cast<uint8_t*>(layout.cb); + crData = static_cast<uint8_t*>(layout.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast<uint8_t>(info.height * y + x); + + EXPECT_EQ(val, yData[layout.yStride * y + x]); + if (y % 2 == 0 && x % 2 == 0) { + EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]); + EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]); + } + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle)); + if (fence >= 0) { + close(fence); + } +} + +/** + * Test IMapper::unlock with invalid buffers. + */ +TEST_F(GraphicsMapperHidlTest, UnlockNegative) { + native_handle_t* invalidHandle = nullptr; + mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "unlock with nullptr did not fail with BAD_BUFFER"; + }); + + invalidHandle = native_handle_create(0, 0); + mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "unlock with invalid handle did not fail with BAD_BUFFER"; + }); + native_handle_delete(invalidHandle); + + ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>( + mGralloc->allocate(mDummyDescriptorInfo, false))); + mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "unlock with un-imported handle did not fail with BAD_BUFFER"; + }); + mGralloc->freeBuffer(invalidHandle); + +// disabled as it fails on many existing drivers +#if 0 + ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>( + mGralloc->allocate(mDummyDescriptorInfo, true))); + mGralloc->getMapper()->unlock( + invalidHandle, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "unlock with unlocked handle did not fail with BAD_BUFFER"; + }); + mGralloc->freeBuffer(invalidHandle); +#endif +} + +/** + * Test IMapper::isSupported with required format RGBA_8888 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) { + const auto& info = mDummyDescriptorInfo; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); + ASSERT_TRUE(supported); +} + +/** + * Test IMapper::isSupported with required format YV12 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::YV12; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); + ASSERT_TRUE(supported); +} + +/** + * Test IMapper::isSupported with optional format Y16 + */ +TEST_F(GraphicsMapperHidlTest, IsSupportedY16) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::Y16; + bool supported = false; + + ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info)); +} + +} // namespace +} // namespace vts +} // namespace V3_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android + +int main(int argc, char** argv) { + using android::hardware::graphics::mapper::V3_0::vts::GraphicsMapperHidlEnvironment; + ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/input/classifier/1.0/Android.bp b/input/classifier/1.0/Android.bp new file mode 100644 index 0000000000..6815a513c1 --- /dev/null +++ b/input/classifier/1.0/Android.bp @@ -0,0 +1,18 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.input.classifier@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IInputClassifier.hal", + ], + interfaces: [ + "android.hardware.input.common@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} + diff --git a/input/classifier/1.0/IInputClassifier.hal b/input/classifier/1.0/IInputClassifier.hal new file mode 100644 index 0000000000..7397fea127 --- /dev/null +++ b/input/classifier/1.0/IInputClassifier.hal @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package android.hardware.input.classifier@1.0; + +import android.hardware.input.common@1.0::Classification; +import android.hardware.input.common@1.0::MotionEvent; + +interface IInputClassifier { + + /** + * Returns the classification for the current sequence of input events. + */ + classify(MotionEvent event) generates (Classification classification); + + /** + * Called by the framework to reset the HAL internal state. The reset may be called + * to prevent an inconsistent stream of events to be sent to the HAL. + */ + reset(); + + /** + * Called by the framework to reset the HAL internal state for a specific device. + * The reset may be called once device reset is received by the framework. + */ + resetDevice(int32_t deviceId); + +}; diff --git a/input/classifier/1.0/default/Android.bp b/input/classifier/1.0/default/Android.bp new file mode 100644 index 0000000000..ddd883ce38 --- /dev/null +++ b/input/classifier/1.0/default/Android.bp @@ -0,0 +1,23 @@ +cc_binary { + name: "android.hardware.input.classifier@1.0-service-example", + init_rc: ["android.hardware.input.classifier@1.0-service-example.rc"], + relative_install_path: "hw", + vendor: true, + vintf_fragments: ["manifest_input.classifier.xml"], + srcs: [ + "InputClassifier.cpp", + "service.cpp", + ], + shared_libs: [ + "android.hardware.input.classifier@1.0", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], +} diff --git a/input/classifier/1.0/default/InputClassifier.cpp b/input/classifier/1.0/default/InputClassifier.cpp new file mode 100644 index 0000000000..a78bbc5c94 --- /dev/null +++ b/input/classifier/1.0/default/InputClassifier.cpp @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#define LOG_TAG "InputClassifierHAL" + +#include "InputClassifier.h" +#include <inttypes.h> +#include <log/log.h> +#include <utils/Timers.h> + +using namespace android::hardware::input::common::V1_0; + +namespace android { +namespace hardware { +namespace input { +namespace classifier { +namespace V1_0 { +namespace implementation { + +// Methods from ::android::hardware::input::classifier::V1_0::IInputClassifier follow. +Return<Classification> InputClassifier::classify(const MotionEvent& event) { + /** + * In this example implementation, we will see how many "pixels" inside the video frame + * exceed the value of 250. If more than 6 such pixels are present, then treat the event + * as a "DEEP_PRESS". + */ + if (event.frames.size() == 0) { + return Classification::NONE; + } + ALOGI("Frame(O) timestamp = %" PRIu64 ", received %zu frame(s)", event.frames[0].timestamp, + event.frames.size()); + for (const VideoFrame& frame : event.frames) { + size_t count = 0; + for (size_t i = 0; i < frame.data.size(); i++) { + if (frame.data[i] > 250) { + count++; + } + } + if (count > 6) { + return Classification::DEEP_PRESS; + } + } + + return Classification::NONE; +} + +Return<void> InputClassifier::reset() { + // We don't have any internal state in this example implementation, + // so no work needed here. + return Void(); +} + +Return<void> InputClassifier::resetDevice(int32_t /*deviceId*/) { + // We don't have any internal per-device state in this example implementation, + // so no work needed here. + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace classifier +} // namespace input +} // namespace hardware +} // namespace android diff --git a/input/classifier/1.0/default/InputClassifier.h b/input/classifier/1.0/default/InputClassifier.h new file mode 100644 index 0000000000..eef370e706 --- /dev/null +++ b/input/classifier/1.0/default/InputClassifier.h @@ -0,0 +1,49 @@ +/* + * 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 ANDROID_HARDWARE_INPUT_CLASSIFIER_V1_0_INPUTCLASSIFIER_H +#define ANDROID_HARDWARE_INPUT_CLASSIFIER_V1_0_INPUTCLASSIFIER_H + +#include <android/hardware/input/classifier/1.0/IInputClassifier.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace input { +namespace classifier { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::Return; + +struct InputClassifier : public IInputClassifier { + // Methods from ::android::hardware::input::classifier::V1_0::IInputClassifier follow. + + Return<android::hardware::input::common::V1_0::Classification> classify( + const android::hardware::input::common::V1_0::MotionEvent& event) override; + + Return<void> reset() override; + Return<void> resetDevice(int32_t deviceId) override; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace classifier +} // namespace input +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_INPUT_CLASSIFIER_V1_0_INPUTCLASSIFIER_H diff --git a/input/classifier/1.0/default/android.hardware.input.classifier@1.0-service-example.rc b/input/classifier/1.0/default/android.hardware.input.classifier@1.0-service-example.rc new file mode 100644 index 0000000000..f799bf4359 --- /dev/null +++ b/input/classifier/1.0/default/android.hardware.input.classifier@1.0-service-example.rc @@ -0,0 +1,9 @@ +service vendor.input.classifier-1-0 /vendor/bin/hw/android.hardware.input.classifier@1.0-service-example + # Must be specified if "disabled" is set. This HAL will only start if requested via getService + interface android.hardware.input.classifier@1.0::IInputClassifier default + class hal + user nobody + # will not be restarted if it exits until it is requested to be restarted + oneshot + # will only be started when requested + disabled diff --git a/input/classifier/1.0/default/manifest_input.classifier.xml b/input/classifier/1.0/default/manifest_input.classifier.xml new file mode 100644 index 0000000000..863416918f --- /dev/null +++ b/input/classifier/1.0/default/manifest_input.classifier.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.input.classifier</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IInputClassifier</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/input/classifier/1.0/default/service.cpp b/input/classifier/1.0/default/service.cpp new file mode 100644 index 0000000000..6ef2118e74 --- /dev/null +++ b/input/classifier/1.0/default/service.cpp @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.input.classifier@1.0" + +#include <inttypes.h> + +#include <hidl/HidlTransportSupport.h> +#include <log/log.h> + +#include "InputClassifier.h" +#include "android/hardware/input/classifier/1.0/IInputClassifier.h" + +using android::sp; +using android::status_t; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::input::classifier::V1_0::IInputClassifier; +using android::hardware::input::classifier::V1_0::implementation::InputClassifier; + +int main() { + sp<IInputClassifier> classifier = new InputClassifier(); + + configureRpcThreadpool(1, true); + const status_t status = classifier->registerAsService(); + + if (status != android::OK) { + ALOGE("Could not register InputClassifier HAL!"); + return EXIT_FAILURE; // or handle error + } + + joinRpcThreadpool(); + LOG_ALWAYS_FATAL("Under normal operation, joinRpcThreadpool should never return"); + return EXIT_FAILURE; +} diff --git a/input/common/1.0/Android.bp b/input/common/1.0/Android.bp new file mode 100644 index 0000000000..68a77f13d9 --- /dev/null +++ b/input/common/1.0/Android.bp @@ -0,0 +1,34 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.input.common@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + types: [ + "Action", + "Axis", + "Button", + "Classification", + "EdgeFlag", + "Flag", + "Meta", + "MotionEvent", + "PointerCoords", + "PointerProperties", + "PolicyFlag", + "Source", + "SourceClass", + "ToolType", + "VideoFrame", + ], + gen_java: true, +} + diff --git a/input/common/1.0/types.hal b/input/common/1.0/types.hal new file mode 100644 index 0000000000..1a07f3b76d --- /dev/null +++ b/input/common/1.0/types.hal @@ -0,0 +1,829 @@ +/* + * 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. + */ + +package android.hardware.input.common@1.0; + + +/** + * Constants that identify each individual axis of a motion event. + */ +enum Axis : uint64_t { + /** + * Axis constant: X axis of a motion event. + * + * - For a touch screen, reports the absolute X screen position of the center of + * the touch contact area. The units are display pixels. + * - For a touch pad, reports the absolute X surface position of the center of the touch + * contact area. The units are device-dependent. + * - For a mouse, reports the absolute X screen position of the mouse pointer. + * The units are display pixels. + * - For a trackball, reports the relative horizontal displacement of the trackball. + * The value is normalized to a range from -1.0 (left) to 1.0 (right). + * - For a joystick, reports the absolute X position of the joystick. + * The value is normalized to a range from -1.0 (left) to 1.0 (right). + */ + X = 0, + /** + * Axis constant: Y axis of a motion event. + * + * - For a touch screen, reports the absolute Y screen position of the center of + * the touch contact area. The units are display pixels. + * - For a touch pad, reports the absolute Y surface position of the center of the touch + * contact area. The units are device-dependent. + * - For a mouse, reports the absolute Y screen position of the mouse pointer. + * The units are display pixels. + * - For a trackball, reports the relative vertical displacement of the trackball. + * The value is normalized to a range from -1.0 (up) to 1.0 (down). + * - For a joystick, reports the absolute Y position of the joystick. + * The value is normalized to a range from -1.0 (up or far) to 1.0 (down or near). + */ + Y = 1, + /** + * Axis constant: Pressure axis of a motion event. + * + * - For a touch screen or touch pad, reports the approximate pressure applied to the surface + * by a finger or other tool. The value is normalized to a range from + * 0 (no pressure at all) to 1 (normal pressure), although values higher than 1 + * may be generated depending on the calibration of the input device. + * - For a trackball, the value is set to 1 if the trackball button is pressed + * or 0 otherwise. + * - For a mouse, the value is set to 1 if the primary mouse button is pressed + * or 0 otherwise. + */ + PRESSURE = 2, + /** + * Axis constant: Size axis of a motion event. + * + * - For a touch screen or touch pad, reports the approximate size of the contact area in + * relation to the maximum detectable size for the device. The value is normalized + * to a range from 0 (smallest detectable size) to 1 (largest detectable size), + * although it is not a linear scale. This value is of limited use. + * To obtain calibrated size information, see + * {@link TOUCH_MAJOR} or {@link TOOL_MAJOR}. + */ + SIZE = 3, + /** + * Axis constant: TouchMajor axis of a motion event. + * + * - For a touch screen, reports the length of the major axis of an ellipse that + * represents the touch area at the point of contact. + * The units are display pixels. + * - For a touch pad, reports the length of the major axis of an ellipse that + * represents the touch area at the point of contact. + * The units are device-dependent. + */ + TOUCH_MAJOR = 4, + /** + * Axis constant: TouchMinor axis of a motion event. + * + * - For a touch screen, reports the length of the minor axis of an ellipse that + * represents the touch area at the point of contact. + * The units are display pixels. + * - For a touch pad, reports the length of the minor axis of an ellipse that + * represents the touch area at the point of contact. + * The units are device-dependent. + * + * When the touch is circular, the major and minor axis lengths will be equal to one another. + */ + TOUCH_MINOR = 5, + /** + * Axis constant: ToolMajor axis of a motion event. + * + * - For a touch screen, reports the length of the major axis of an ellipse that + * represents the size of the approaching finger or tool used to make contact. + * - For a touch pad, reports the length of the major axis of an ellipse that + * represents the size of the approaching finger or tool used to make contact. + * The units are device-dependent. + * + * When the touch is circular, the major and minor axis lengths will be equal to one another. + * + * The tool size may be larger than the touch size since the tool may not be fully + * in contact with the touch sensor. + */ + TOOL_MAJOR = 6, + /** + * Axis constant: ToolMinor axis of a motion event. + * + * - For a touch screen, reports the length of the minor axis of an ellipse that + * represents the size of the approaching finger or tool used to make contact. + * - For a touch pad, reports the length of the minor axis of an ellipse that + * represents the size of the approaching finger or tool used to make contact. + * The units are device-dependent. + * + * When the touch is circular, the major and minor axis lengths will be equal to one another. + * + * The tool size may be larger than the touch size since the tool may not be fully + * in contact with the touch sensor. + */ + TOOL_MINOR = 7, + /** + * Axis constant: Orientation axis of a motion event. + * + * - For a touch screen or touch pad, reports the orientation of the finger + * or tool in radians relative to the vertical plane of the device. + * An angle of 0 radians indicates that the major axis of contact is oriented + * upwards, is perfectly circular or is of unknown orientation. A positive angle + * indicates that the major axis of contact is oriented to the right. A negative angle + * indicates that the major axis of contact is oriented to the left. + * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians + * (finger pointing fully right). + * - For a stylus, the orientation indicates the direction in which the stylus + * is pointing in relation to the vertical axis of the current orientation of the screen. + * The range is from -PI radians to PI radians, where 0 is pointing up, + * -PI/2 radians is pointing left, -PI or PI radians is pointing down, and PI/2 radians + * is pointing right. See also {@link TILT}. + */ + ORIENTATION = 8, + /** + * Axis constant: Vertical Scroll axis of a motion event. + * + * - For a mouse, reports the relative movement of the vertical scroll wheel. + * The value is normalized to a range from -1.0 (down) to 1.0 (up). + * + * The framework may use this axis to scroll views vertically. + */ + VSCROLL = 9, + /** + * Axis constant: Horizontal Scroll axis of a motion event. + * + * - For a mouse, reports the relative movement of the horizontal scroll wheel. + * The value is normalized to a range from -1.0 (left) to 1.0 (right). + * + * The framework may use this axis to scroll views horizontally. + */ + HSCROLL = 10, + /** + * Axis constant: Z axis of a motion event. + * + * - For a joystick, reports the absolute Z position of the joystick. + * The value is normalized to a range from -1.0 (high) to 1.0 (low). + * <em>On game pads with two analog joysticks, this axis is often reinterpreted + * to report the absolute X position of the second joystick instead.</em> + */ + Z = 11, + /** + * Axis constant: X Rotation axis of a motion event. + * + * - For a joystick, reports the absolute rotation angle about the X axis. + * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). + */ + RX = 12, + /** + * Axis constant: Y Rotation axis of a motion event. + * + * - For a joystick, reports the absolute rotation angle about the Y axis. + * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). + */ + RY = 13, + /** + * Axis constant: Z Rotation axis of a motion event. + * + * - For a joystick, reports the absolute rotation angle about the Z axis. + * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). + * On game pads with two analog joysticks, this axis is often reinterpreted + * to report the absolute Y position of the second joystick instead. + */ + RZ = 14, + /** + * Axis constant: Hat X axis of a motion event. + * + * - For a joystick, reports the absolute X position of the directional hat control. + * The value is normalized to a range from -1.0 (left) to 1.0 (right). + */ + HAT_X = 15, + /** + * Axis constant: Hat Y axis of a motion event. + * + * - For a joystick, reports the absolute Y position of the directional hat control. + * The value is normalized to a range from -1.0 (up) to 1.0 (down). + */ + HAT_Y = 16, + /** + * Axis constant: Left Trigger axis of a motion event. + * + * - For a joystick, reports the absolute position of the left trigger control. + * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed). + */ + LTRIGGER = 17, + /** + * Axis constant: Right Trigger axis of a motion event. + * + * - For a joystick, reports the absolute position of the right trigger control. + * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed). + */ + RTRIGGER = 18, + /** + * Axis constant: Throttle axis of a motion event. + * + * - For a joystick, reports the absolute position of the throttle control. + * The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed). + */ + THROTTLE = 19, + /** + * Axis constant: Rudder axis of a motion event. + * + * - For a joystick, reports the absolute position of the rudder control. + * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right). + */ + RUDDER = 20, + /** + * Axis constant: Wheel axis of a motion event. + * + * - For a joystick, reports the absolute position of the steering wheel control. + * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right). + */ + WHEEL = 21, + /** + * Axis constant: Gas axis of a motion event. + * + * - For a joystick, reports the absolute position of the gas (accelerator) control. + * The value is normalized to a range from 0.0 (no acceleration) + * to 1.0 (maximum acceleration). + */ + GAS = 22, + /** + * Axis constant: Brake axis of a motion event. + * + * - For a joystick, reports the absolute position of the brake control. + * The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking). + */ + BRAKE = 23, + /** + * Axis constant: Distance axis of a motion event. + * + * - For a stylus, reports the distance of the stylus from the screen. + * A value of 0.0 indicates direct contact and larger values indicate increasing + * distance from the surface. + */ + DISTANCE = 24, + /** + * Axis constant: Tilt axis of a motion event. + * + * - For a stylus, reports the tilt angle of the stylus in radians where + * 0 radians indicates that the stylus is being held perpendicular to the + * surface, and PI/2 radians indicates that the stylus is being held flat + * against the surface. + */ + TILT = 25, + /** + * Axis constant: Generic scroll axis of a motion event. + * + * - This is used for scroll axis motion events that can't be classified as strictly + * vertical or horizontal. The movement of a rotating scroller is an example of this. + */ + SCROLL = 26, + /** + * Axis constant: The movement of x position of a motion event. + * + * - For a mouse, reports a difference of x position between the previous position. + * This is useful when pointer is captured, in that case the mouse pointer doesn't + * change the location but this axis reports the difference which allows the app + * to see how the mouse is moved. + */ + RELATIVE_X = 27, + /** + * Axis constant: The movement of y position of a motion event. + * + * Same as {@link RELATIVE_X}, but for y position. + */ + RELATIVE_Y = 28, + /** + * Axis constant: Generic 1 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_1 = 32, + /** + * Axis constant: Generic 2 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_2 = 33, + /** + * Axis constant: Generic 3 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_3 = 34, + /** + * Axis constant: Generic 4 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_4 = 35, + /** + * Axis constant: Generic 5 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_5 = 36, + /** + * Axis constant: Generic 6 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_6 = 37, + /** + * Axis constant: Generic 7 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_7 = 38, + /** + * Axis constant: Generic 8 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_8 = 39, + /** + * Axis constant: Generic 9 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_9 = 40, + /** + * Axis constant: Generic 10 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_10 = 41, + /** + * Axis constant: Generic 11 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_11 = 42, + /** + * Axis constant: Generic 12 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_12 = 43, + /** + * Axis constant: Generic 13 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_13 = 44, + /** + * Axis constant: Generic 14 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_14 = 45, + /** + * Axis constant: Generic 15 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_15 = 46, + /** + * Axis constant: Generic 16 axis of a motion event. + * The interpretation of a generic axis is device-specific. + */ + GENERIC_16 = 47, +}; + +/** + * Tool type of a pointer + */ +enum ToolType: uint8_t { + UNKNOWN = 0, + FINGER = 1, + STYLUS = 2, + MOUSE = 3, + ERASER = 4, +}; + +/** + * Properties of a particular pointer. Analogous to Android's PointerProperties. + */ +struct PointerProperties { + /** + * A number identifying a specific pointer. When a pointer is lifted, + * this value may be reused by another new pointer, even during the + * same gesture. For example, if there are two pointers touching the screen + * at the same time, they might have pointer ID's of 0 and 1. If the + * pointer with id = 0 is lifted, while the pointer with id = 1 remains, and + * a new pointer is placed on the screen, then the new pointer may receive + * an id of 0. While a pointer is active, it is guaranteed to keep the same + * id. + */ + int32_t id; + /** + * Type of tool used to make contact, such as a finger or stylus, if known. + */ + ToolType toolType; +}; + +/** + * Pointer coordinate data. Analogous to Android's PointerCoords. + */ +struct PointerCoords { + /** + * Bitfield of axes that are present in this structure. + */ + bitfield<Axis> bits; + /** + * The values corresponding to each non-zero axis. This vector only + * contains non-zero entries. If an axis that is not currently specified + * in "bits" is requested, a zero value is returned. + * There are only as many values stored here + * as there are non-zero bits in the "bits" field. + * The values are position-packed. So the first non-zero axis will be + * at position 0, the next non-zero axis will be at position 1, and so on. + */ + vec<float> values; +}; + +enum SourceClass: uint8_t { + NONE = 0 << 0, + BUTTON = 1 << 0, + POINTER = 1 << 1, + NAVIGATION = 1 << 2, + POSITION = 1 << 3, + JOYSTICK = 1 << 4, +}; + +/** + * Input sources + */ +enum Source: uint32_t { + UNKNOWN = 0, + KEYBOARD = (1 << 8) | SourceClass:BUTTON, + DPAD = (1 << 9) | SourceClass:BUTTON, + GAMEPAD = (1 << 10) | SourceClass:BUTTON, + TOUCHSCREEN = (1 << 12) | SourceClass:POINTER, + MOUSE = (1 << 13) | SourceClass:POINTER, + STYLUS = (1 << 14) | SourceClass:POINTER, + BLUETOOTH_STYLUS = (1 << 15) | STYLUS, + TRACKBALL = (1 << 16) | SourceClass:NAVIGATION, + MOUSE_RELATIVE = (1 << 17) | SourceClass:NAVIGATION, + TOUCHPAD = (1 << 20) | SourceClass:POSITION, + TOUCH_NAVIGATION = (1 << 21) | SourceClass:NONE, + ROTARY_ENCODER = (1 << 22) | SourceClass:NONE, + JOYSTICK = (1 << 24) | SourceClass:JOYSTICK, + ANY = 0xFFFFFF00, +}; + +/** Motion event actions */ +enum Action: int32_t { + /** A pressed gesture has started, the motion contains the initial starting location. */ + DOWN = 0, + /** + * A pressed gesture has finished, the motion contains the final release location + * as well as any intermediate points since the last down or move event. + */ + UP = 1, + /** + * A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and + * AMOTION_EVENT_ACTION_UP). The motion contains the most recent point. + */ + MOVE = 2, + /** + * The current gesture has been aborted. + * You will not receive any more points in it. You must treat this as + * an up event, but not perform any action that you normally would. + */ + CANCEL = 3, + /** + * A movement has happened outside of the normal bounds of the UI element. + * This does not provide a full gesture, but only the initial location of the movement/touch. + */ + OUTSIDE = 4, + /** + * A non-primary pointer has gone down. + */ + POINTER_DOWN = 5, + /** + * A non-primary pointer has gone up. + */ + POINTER_UP = 6, + /** + * A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE). + * The motion contains the most recent point, as well as any intermediate points since + * the last hover move event. + */ + HOVER_MOVE = 7, + /** + * The motion event contains relative vertical and/or horizontal scroll offsets. + * Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL + * and AMOTION_EVENT_AXIS_HSCROLL. + * The pointer may or may not be down when this event is dispatched. + * The framework will always deliver this action to the window under the pointer, which + * may not be the window currently touched. + */ + SCROLL = 8, + /** + * The pointer is not down but has entered the boundaries of a window or view. + */ + HOVER_ENTER = 9, + /** + * The pointer is not down but has exited the boundaries of a window or view. + */ + HOVER_EXIT = 10, + /** + * One or more buttons have been pressed. + */ + BUTTON_PRESS = 11, + /** + * One or more buttons have been released. + */ + BUTTON_RELEASE = 12, +}; + +/** Edge flags */ +enum EdgeFlag : int32_t { + /** No edges are intersected */ + NONE = 0, + /** Motion intersected top edge of the screen */ + TOP = 1 << 0, + /** Motion intersected bottom edge of the screen */ + BOTTOM = 1 << 1, + /** Motion intersected left edge of the screen */ + LEFT = 1 << 2, + /** Motion intersected right edge of the screen */ + RIGHT = 1 << 3, +}; + +/** Policy flags */ +enum PolicyFlag : uint32_t { + // The following flags originate in RawEvents + + /** Event should wake the device */ + WAKE = 1 << 0, + /** Key is virtual, and should generate haptic feedback */ + VIRTUAL = 1 << 1, + /** Key is the special function modifier */ + FUNCTION = 1 << 2, + /** + * Key represents a special gesture that has been detected + * by the touch firmware or driver. + */ + GESTURE = 1 << 3, + + // The following flags may be generated here in the InputClassifier HAL + // or in later InputListener stages + + /** Event was injected */ + INJECTED = 1 << 24, + /** + * Event comes from a trusted source, such as a directly attached input + * device or an application with system-wide event injection permission. + */ + TRUSTED = 1 << 25, + /** Event has passed through an input filter. */ + FILTERED = 1 << 26, + /** Disable automatic key repeating behaviour. */ + DISABLE_KEY_REPEAT = 1 << 27, + + // The following flags are set by the input reader policy as it intercepts each event + + /** Device was in an interactive state when the event was intercepted */ + INTERACTIVE = 1 << 29, + /** Event should be dispatched to applications */ + PASS_TO_USER = 1 << 30, +}; + +/** + * Buttons that are associated with motion events. + */ +enum Button : int32_t { + NONE = 0, + PRIMARY = 1 << 0, + SECONDARY = 1 << 1, + TERTIARY = 1 << 2, + BACK = 1 << 3, + FORWARD = 1 << 4, + STYLUS_PRIMARY = 1 << 5, + STYLUS_SECONDARY = 1 << 6, +}; + +/** + * Meta key / modifier state + */ +enum Meta : int32_t { + NONE = 0, + + /** One of the ALT meta keys is pressed. */ + ALT_ON = 1 << 1, // 0x02 + + /** The left ALT meta key is pressed. */ + ALT_LEFT_ON = 1 << 4, // 0x10 + + /** The right ALT meta key is pressed. */ + ALT_RIGHT_ON = 1 << 5, // 0x20 + + /** One of the SHIFT meta keys is pressed. */ + SHIFT_ON = 1 << 0, // 0x01 + + /** The left SHIFT meta key is pressed. */ + SHIFT_LEFT_ON = 1 << 6, // 0x40 + + /** The right SHIFT meta key is pressed. */ + SHIFT_RIGHT_ON = 1 << 7, // 0x80 + + /** The SYM meta key is pressed. */ + SYM_ON = 1 << 2, // 0x04 + + /** The FUNCTION meta key is pressed. */ + FUNCTION_ON = 1 << 3, // 0x08 + + /** One of the CTRL meta keys is pressed. */ + CTRL_ON = 1 << 12, // 0x1000 + + /** The left CTRL meta key is pressed. */ + CTRL_LEFT_ON = 1 << 13, // 0x2000 + + /** The right CTRL meta key is pressed. */ + CTRL_RIGHT_ON = 1 << 14, // 0x4000 + + /** One of the META meta keys is pressed. */ + META_ON = 1 << 16, // 0x10000 + + /** The left META meta key is pressed. */ + META_LEFT_ON = 1 << 17, // 0x20000 + + /** The right META meta key is pressed. */ + META_RIGHT_ON = 1 << 18, //0x40000 + + /** The CAPS LOCK meta key is on. */ + CAPS_LOCK_ON = 1 << 20, // 0x100000 + + /** The NUM LOCK meta key is on. */ + NUM_LOCK_ON = 1 << 21, // 0x200000 + + /** The SCROLL LOCK meta key is on. */ + SCROLL_LOCK_ON = 1 << 22, // 0x400000 +}; + +/** + * Motion event flags + */ +enum Flag : int32_t { + /** + * Indicates that the window that received this motion event is partly + * or wholly obscured by another visible window above it. This flag is set to true + * even if the event did not directly pass through the obscured area. + * A security sensitive application can check this flag to identify situations in which + * a malicious application may have covered up part of its content for the purpose + * of misleading the user or hijacking touches. An appropriate response might be + * to drop the suspect touches or to take additional precautions to confirm the user's + * actual intent. + */ + WINDOW_IS_OBSCURED = 1 << 0, + /** + * This flag indicates that the event has been generated by a gesture generator. It + * could be used, for example, to determine whether touch slop should be applied. + */ + IS_GENERATED_GESTURE = 1 << 3, // 0x8 + /** + * Motion event is inconsistent with previously sent motion events. + */ + TAINTED = 1 << 31, // 0x80000000 +}; + +/** + * Touch heatmap. + * + * The array is a 2-D row-major matrix with dimensions (height, width). + * The heatmap data does not rotate when device orientation changes. + * + * Example: + * + * If the data in the array is: + * data[i] = i for i in 0 .. 59, + * then it can be represented as follows: + * + * <-- width -- > + * 0 1 2 3 4 5 ^ + * 6 7 8 9 10 11 | + * 12 12 14 15 16 17 | + * 18 ... 23 | height + * 24 ... 29 | + * 30 ... 35 | + * 36 ... 41 | + * 42 ... 47 | + * 48 ... 53 | + * 54 ... 59 v + * + * Looking at the device in standard portrait orientation, + * the element "0" is the top left of the screen, + * "5" is at the top right, and "59" is the bottom right. + * Here width=6, and height=10. + */ +struct VideoFrame { + /** + * Video frame data. + * Size of the data is width * height. + */ + vec<int16_t> data; + uint32_t width; + uint32_t height; + /** + * Time at which the frame was collected, in nanoseconds. + * Measured with the same clock that is used to populate MotionEvent times. + */ + uint64_t timestamp; +}; + +/** + * Analogous to Android's native MotionEvent / NotifyMotionArgs. + * Stores the basic information about pointer movements. + */ +struct MotionEvent { + // InputEvent fields + /** + * The id of the device which produced this event. + */ + int32_t deviceId; + /** + * The source type of this event. + */ + Source source; + /** + * The display id associated with this event. + */ + int32_t displayId; + + // NotifyMotionArgs fields + /** + * Time when the initial touch down occurred, in nanoseconds. + */ + int64_t downTime; + /** + * Time when this event occurred, in nanoseconds. + */ + int64_t eventTime; + /** + * The kind of action being performed. + */ + Action action; + /** + * For ACTION_POINTER_DOWN or ACTION_POINTER_UP, this contains the associated pointer index. + * The index may be used to get information about the pointer that has gone down or up. + */ + uint8_t actionIndex; + /** + * The button that has been modified during a press or release action. + */ + Button actionButton; + /** + * The motion event flags. + */ + bitfield<Flag> flags; + /** + * The motion event policy flags. + */ + bitfield<PolicyFlag> policyFlags; + /** + * The edges, if any, that were touched by this motion event. + */ + bitfield<EdgeFlag> edgeFlags; + /** + * The state of any meta / modifier keys that were in effect when the event was generated. + */ + bitfield<Meta> metaState; + /** + * The state of buttons that are pressed. + */ + bitfield<Button> buttonState; + /** + * The precision of the X coordinate being reported. + */ + float xPrecision; + /** + * The precision of the Y coordinate being reported. + */ + float yPrecision; + /** + * The properties of each pointer present in this motion event. + */ + vec<PointerProperties> pointerProperties; + /** + * The coordinates of each pointer. + */ + vec<PointerCoords> pointerCoords; + + // Additional fields from NotifyMotionArgs + /** + * Device time at which the event occurred, in microseconds. + * Will wrap after a little over an hour. + */ + uint32_t deviceTimestamp; + /** + * The video frames, if any, associated with the current or previous motion events. + */ + vec<VideoFrame> frames; +}; + + +enum Classification : uint8_t { + NONE = 0, + /** + * Too early to classify the gesture, need more events. + */ + AMBIGUOUS_GESTURE = 1, + /** + * User is force-pressing the screen. + */ + DEEP_PRESS = 2, +}; diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp index 784ae30c04..a9c6f6ca93 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -181,7 +181,35 @@ X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) { return d2i_X509(nullptr, &p, blob.size()); } -bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain) { +bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain, const std::string& msg, + const std::string& signature) { + { + EVP_MD_CTX md_ctx_verify; + X509_Ptr signing_cert(parse_cert_blob(chain[0])); + EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get())); + EXPECT_TRUE(signing_pubkey); + ERR_print_errors_cb( + [](const char* str, size_t len, void* ctx) -> int { + (void)ctx; + std::cerr << std::string(str, len) << std::endl; + return 1; + }, + nullptr); + + EVP_MD_CTX_init(&md_ctx_verify); + + bool result = false; + EXPECT_TRUE((result = EVP_DigestVerifyInit(&md_ctx_verify, NULL, EVP_sha256(), NULL, + signing_pubkey.get()))); + EXPECT_TRUE( + (result = result && EVP_DigestVerifyUpdate(&md_ctx_verify, msg.c_str(), msg.size()))); + EXPECT_TRUE((result = result && EVP_DigestVerifyFinal( + &md_ctx_verify, + reinterpret_cast<const uint8_t*>(signature.c_str()), + signature.size()))); + EVP_MD_CTX_cleanup(&md_ctx_verify); + if (!result) return false; + } for (size_t i = 0; i < chain.size(); ++i) { X509_Ptr key_cert(parse_cert_blob(chain[i])); X509_Ptr signing_cert; @@ -3833,8 +3861,8 @@ TEST_F(AttestationTest, RsaAttestation) { ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() .Authorization(TAG_NO_AUTH_REQUIRED) .RsaSigningKey(2048, 65537) - .Digest(Digest::NONE) - .Padding(PaddingMode::NONE) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) .Authorization(TAG_INCLUDE_UNIQUE_ID))); hidl_vec<hidl_vec<uint8_t>> cert_chain; @@ -3844,7 +3872,13 @@ TEST_F(AttestationTest, RsaAttestation) { .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")), &cert_chain)); EXPECT_GE(cert_chain.size(), 2U); - EXPECT_TRUE(verify_chain(cert_chain)); + + string message = "12345678901234567890123456789012"; + string signature = SignMessage(message, AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)); + + EXPECT_TRUE(verify_chain(cert_chain, message, signature)); EXPECT_TRUE(verify_attestation_record("challenge", "foo", // key_characteristics_.softwareEnforced, // key_characteristics_.hardwareEnforced, // @@ -3890,7 +3924,11 @@ TEST_F(AttestationTest, EcAttestation) { .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")), &cert_chain)); EXPECT_GE(cert_chain.size(), 2U); - EXPECT_TRUE(verify_chain(cert_chain)); + + string message(1024, 'a'); + string signature = SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256)); + + EXPECT_TRUE(verify_chain(cert_chain, message, signature)); EXPECT_TRUE(verify_attestation_record("challenge", "foo", // key_characteristics_.softwareEnforced, // diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp new file mode 100644 index 0000000000..1f8bbdb888 --- /dev/null +++ b/media/bufferpool/2.0/Android.bp @@ -0,0 +1,28 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.media.bufferpool@2.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IAccessor.hal", + "IClientManager.hal", + "IConnection.hal", + "IObserver.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + types: [ + "Buffer", + "BufferInvalidationMessage", + "BufferStatus", + "BufferStatusMessage", + "ResultStatus", + ], + gen_java: false, +} + diff --git a/media/bufferpool/2.0/IAccessor.hal b/media/bufferpool/2.0/IAccessor.hal new file mode 100644 index 0000000000..b8895180b5 --- /dev/null +++ b/media/bufferpool/2.0/IAccessor.hal @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package android.hardware.media.bufferpool@2.0; + +import IConnection; +import IObserver; +/** + * IAccessor creates IConnection which is used from IClientManager in order to + * use functionality of the specified buffer pool. + */ +interface IAccessor { + + /** + * Registers a new client and creates IConnection to the buffer pool for + * the client. IConnection and FMQ are used by IClientManager in order to + * communicate with the buffer pool. Via FMQ IClientManager sends + * BufferStatusMesage(s) to the buffer pool. + * + * FMQ is used to send buffer ownership status changes to a buffer pool + * from a buffer pool client. A buffer pool synchronizes FMQ messages when + * there is a hidl request from the clients. Every client has its own + * connection and FMQ to communicate with the buffer pool. So sending an + * FMQ message on behalf of other clients is not possible. + * + * FMQ messages are sent when a buffer is acquired or released. Also, FMQ + * messages are sent when a buffer is transferred from a client to another + * client. FMQ has its own ID from a buffer pool. A client is specified + * with the ID. + * + * To transfer a buffer, a sender must send an FMQ message. The message + * must include a receiver's ID and a transaction ID. A receiver must send + * the transaction ID to fetch a buffer from a buffer pool. Since the + * sender already registered the receiver via an FMQ message, The buffer + * pool must verify the receiver with the transaction ID. In order to + * prevent faking a receiver, a connection to a buffer pool from client is + * made and kept private. Also part of transaction ID is a sender ID in + * order to prevent fake transactions from other clients. This must be + * verified with an FMQ message from a buffer pool. + + * @param observer The buffer pool event observer from the client. + * Observer is provided to ensure FMQ messages are processed even when + * client processes are idle. Buffer invalidation caused by + * reconfiguration does not call observer. Buffer invalidation caused + * by termination of pipeline call observer in order to ensure + * invalidation is done after pipeline completion. + * + * @return status The status of the call. + * OK - A connection is made successfully. + * NO_MEMORY - Memory allocation failure occurred. + * ALREADY_EXISTS - A connection was already made. + * CRITICAL_ERROR - Other errors. + * @return connection The IConnection have interfaces + * to get shared buffers from the buffer pool. + * @return connectionId Id of IConnection. The Id identifies + * sender and receiver in FMQ messages during buffer transfer. + * @return msgId Id of the most recent message from buffer pool. + * @return toFmqDesc FMQ descriptor. The descriptor is used to + * post buffer status messages. + * @return fromFmqDesc FMQ descriptor. The descriptor is used to + * receive buffer invalidation messages from the buffer pool. + */ + connect(IObserver observer) + generates (ResultStatus status, IConnection connection, + int64_t connectionId, + uint32_t msgId, + fmq_sync<BufferStatusMessage> toFmqDesc, + fmq_unsync<BufferInvalidationMessage> fromFmqDesc); +}; diff --git a/media/bufferpool/2.0/IClientManager.hal b/media/bufferpool/2.0/IClientManager.hal new file mode 100644 index 0000000000..9253bda90f --- /dev/null +++ b/media/bufferpool/2.0/IClientManager.hal @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package android.hardware.media.bufferpool@2.0; + +import IAccessor; + +/** + * IClientManager manages IConnection(s) inside a process. A locally + * created IConnection represents a communication node(receiver) with the + * specified buffer pool(IAccessor). + * IConnection(s) are not exposed to other processes(IClientManager). + * IClientManager instance must be unique within a process. + */ +interface IClientManager { + + /** + * 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. + * + * @param bufferPool a buffer pool which is specified with the IAccessor. + * The specified buffer pool is the owner of received buffers. + * @return status The status of the call. + * OK - A sender was set successfully. + * NO_MEMORY - Memory allocation failure occurred. + * ALREADY_EXISTS - A sender was registered already. + * CRITICAL_ERROR - Other errors. + * @return connectionId the Id of the communication node to the buffer pool. + * This id is used in FMQ to notify IAccessor that a buffer has been + * sent to that connection during transfers. + */ + registerSender(IAccessor bufferPool) generates + (ResultStatus status, int64_t connectionId); +}; diff --git a/media/bufferpool/2.0/IConnection.hal b/media/bufferpool/2.0/IConnection.hal new file mode 100644 index 0000000000..629f83c902 --- /dev/null +++ b/media/bufferpool/2.0/IConnection.hal @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package android.hardware.media.bufferpool@2.0; + +/** + * A connection to a buffer pool which handles requests from a buffer pool + * client. The connection must be made in order to receive buffers from + * other buffer pool clients. + */ +interface IConnection { + + /** + * Retrieves a buffer using bufferId. The method must be called from + * receiving side of buffer during transferring only when the specified + * buffer is neither cached nor used. This fails if the specified + * transaction is not valid. + * + * @param transactionId Unique transaction id for buffer transferring. + * @param bufferId Id of the buffer to be fetched. + * @return status The status of the call. + * OK - A buffer was fetched successfully. + * NO_MEMORY - Memory allocation failure occurred. + * NOT_FOUND - A buffer was not found due to invalidation. + * CRITICAL_ERROR - Other errors. + * @return buffer The actual buffer which is specified with bufferId. + */ + fetch(uint64_t transactionId, uint32_t bufferId) generates + (ResultStatus status, Buffer buffer); +}; diff --git a/media/bufferpool/2.0/IObserver.hal b/media/bufferpool/2.0/IObserver.hal new file mode 100644 index 0000000000..62f247e14a --- /dev/null +++ b/media/bufferpool/2.0/IObserver.hal @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package android.hardware.media.bufferpool@2.0; + +/** + * IObserver listens on notifications from the buffer pool. On receiving + * notifications, FMQ messages from the specific buffer pool which are already + * in the FMQ are processed. + */ +interface IObserver { + + /** + * The specific buffer pool sent a message to the client. Calling this + * method from the buffer pool enforces a buffer pool client process the + * message. + * + * @param connectionId the connection Id of the specific buffer pool client + * @param msgId Id of the most recent message + */ + oneway onMessage(int64_t connectionId, uint32_t msgId); +}; diff --git a/media/bufferpool/2.0/README.md b/media/bufferpool/2.0/README.md new file mode 100644 index 0000000000..ed985d8291 --- /dev/null +++ b/media/bufferpool/2.0/README.md @@ -0,0 +1,54 @@ +1. Overview + +A buffer pool enables processes to transfer buffers asynchronously. +Without a buffer pool, a process calls a synchronous method of the other +process and waits until the call finishes transferring a buffer. This adds +unwanted latency due to context switching. With help from a buffer pool, a +process can pass buffers asynchronously and reduce context switching latency. + +Passing an interface and a handle adds extra latency also. To mitigate the +latency, passing IDs with local cache is used. For security concerns about +rogue clients, FMQ is used to communicate between a buffer pool and a client +process. FMQ is used to send buffer ownership change status from a client +process to a buffer pool. Except FMQ, a buffer pool does not use any shared +memory. + +2. FMQ + +FMQ is used to send buffer ownership status changes to a buffer pool from a +buffer pool client. A buffer pool synchronizes FMQ messages when there is a +hidl request from the clients. Every client has its own connection and FMQ +to communicate with the buffer pool. So sending an FMQ message on behalf of +other clients is not possible. + +FMQ messages are sent when a buffer is acquired or released. Also, FMQ messages +are sent when a buffer is transferred from a client to another client. FMQ has +its own ID from a buffer pool. A client is specified with the ID. + +To transfer a buffer, a sender must send an FMQ message. The message must +include a receiver's ID and a transaction ID. A receiver must send the +transaction ID to fetch a buffer from a buffer pool. Since the sender already +registered the receiver via an FMQ message, The buffer pool must verify the +receiver with the transaction ID. In order to prevent faking a receiver, a +connection to a buffer pool from client is made and kept privately. Also part of +transaction ID is a sender ID in order to prevent fake transactions from other +clients. This must be verified with an FMQ message from a buffer pool. + +FMQ messages are defined in BufferStatus and BufferStatusMessage of 'types.hal'. + +3. Interfaces + +IConnection +A connection to a buffer pool from a buffer pool client. The connection +provides the functionalities to share buffers between buffer pool clients. +The connection must be unique for each client. + +IAccessor +An accessor to a buffer pool which makes a connection to the buffer pool. +IAccesssor#connect creates an IConnection. + +IClientManager +A manager of buffer pool clients and clients' connections to buffer pools. It +sets up a process to be a receiver of buffers from a buffer pool. The manager +is unique in a process. + diff --git a/media/bufferpool/2.0/types.hal b/media/bufferpool/2.0/types.hal new file mode 100644 index 0000000000..597e7b3722 --- /dev/null +++ b/media/bufferpool/2.0/types.hal @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package android.hardware.media.bufferpool@2.0; + +enum ResultStatus : int32_t { + OK = 0, + + NO_MEMORY = 1, + ALREADY_EXISTS = 2, + NOT_FOUND = 3, + CRITICAL_ERROR = 4, +}; + +/** + * Generic buffer for fast recycling for media/stagefright. + * + * During media pipeline buffer references are created, shared and + * destroyed frequently. The underlying buffers are allocated on demand + * by a buffer pool, and are recycled to the buffer pool when they are + * no longer referenced by the clients. + * + * E.g. ion or gralloc buffer + */ +struct Buffer { + uint32_t id; + handle buffer; +}; + +/** + * Buffer ownership status for the specified client. + * Buffer transfer status for the specified buffer transafer transaction. + * BufferStatus is posted along with BufferStatusMessage from a client to + * the buffer pool for synchronization after status change. + */ +enum BufferStatus : int32_t { + /** No longer used by the specified client. */ + NOT_USED = 0, + /** Buffer is acquired by the specified client. */ + USED = 1, + /** Buffer is sent by the specified client. */ + TRANSFER_TO = 2, + /** Buffer transfer is acked by the receiver client. */ + TRANSFER_FROM = 3, + /** Buffer transfer is timed out by receiver client. */ + TRANSFER_TIMEOUT = 4, + /** Buffer transfer is not acked by the receiver. */ + TRANSFER_LOST = 5, + /** Buffer fetch request from the client. */ + TRANSFER_FETCH = 6, + /** Buffer transaction succeeded. */ + TRANSFER_OK = 7, + /** Buffer transaction failure. */ + TRANSFER_ERROR = 8, + /** Buffer invalidation ack. */ + INVALIDATION_ACK = 9, +}; + +/** + * Buffer ownership status change message. This message is + * sent via fmq to the buffer pool from client processes. + */ +struct BufferStatusMessage { + /** + * Transaction Id = (SenderId : sender local transaction Id) + * Transaction Id is created from sender and posted via fmq within + * TRANSFER_TO message. + */ + uint64_t transactionId; + uint32_t bufferId; + BufferStatus newStatus; + /** Used by the buffer pool. not by client. */ + int64_t connectionId; + /** Valid only when TRANSFER_TO is posted. */ + int64_t targetConnectionId; + /** + * Used by the buffer pool, not by client. + * Monotonic timestamp in Us since fixed point in time as decided + * by the sender of the message + */ + int64_t timestampUs; +}; + +/* + * Buffer pool sends a buffer invalidation message to clients in order to + * ensure fast reclamation of the buffers. Clients must free the invalidated + * buffers as soon as possible upon receiving the message. + */ +struct BufferInvalidationMessage { + uint32_t messageId; + /** + * Buffers from fromBufferId to toBufferId must be invalidated. + * fromBufferId is inclusive, but toBufferId is not inclusive. + * If fromBufferId > toBufferID, wrap happens. In that case + * the wrap is based on UINT32_MAX. + */ + uint32_t fromBufferId; + uint32_t toBufferId; +}; diff --git a/media/c2/1.0/Android.bp b/media/c2/1.0/Android.bp new file mode 100644 index 0000000000..56c78b2e6e --- /dev/null +++ b/media/c2/1.0/Android.bp @@ -0,0 +1,52 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.media.c2@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IComponent.hal", + "IComponentInterface.hal", + "IComponentListener.hal", + "IComponentStore.hal", + "IConfigurable.hal", + "IInputSink.hal", + "IInputSurface.hal", + "IInputSurfaceConnection.hal", + ], + interfaces: [ + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.common@1.0", + "android.hardware.media.bufferpool@2.0", + "android.hardware.media.omx@1.0", + "android.hardware.media@1.0", + "android.hidl.base@1.0", + ], + types: [ + "BaseBlock", + "Block", + "Buffer", + "FieldDescriptor", + "FieldId", + "FieldSupportedValues", + "FieldSupportedValuesQuery", + "FieldSupportedValuesQueryResult", + "FrameData", + "InfoBuffer", + "ParamDescriptor", + "ParamField", + "ParamFieldValues", + "SettingResult", + "Status", + "StructDescriptor", + "Work", + "WorkBundle", + "WorkOrdinal", + "Worklet", + ], + gen_java: false, +} + diff --git a/media/c2/1.0/IComponent.hal b/media/c2/1.0/IComponent.hal new file mode 100644 index 0000000000..7fd551fc2b --- /dev/null +++ b/media/c2/1.0/IComponent.hal @@ -0,0 +1,365 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer; +import android.hardware.media.omx@1.0::IGraphicBufferSource; + +import IConfigurable; +import IComponentInterface; +import IComponentListener; +import IInputSurface; +import IInputSurfaceConnection; + +/** + * Interface for a Codec2 component corresponding to API level 1.0 or below. + * Components have two states: stopped and running. The running state has three + * sub-states: executing, tripped and error. + * + * All methods in `IComponent` must not block. If a method call cannot be + * completed in a timely manner, it must return `TIMED_OUT` in the return + * status. + */ +interface IComponent { + + // METHODS AVAILABLE WHEN RUNNING + // ========================================================================= + + /** + * Queues up work for the component. + * + * This method must be supported in running (including tripped) states. + * + * It is acceptable for this method to return `OK` and return an error value + * using the IComponentListener::onWorkDone() callback. + * + * @param workBundle `WorkBundle` object containing a list of `Work` objects + * to queue to the component. + * @return status Status of the call, which may be + * - `OK` - Works in @p workBundle were successfully queued. + * - `BAD_INDEX` - Some component id in some `Worklet` is not valid. + * - `CANNOT_DO` - The components are not tunneled but some `Work` object + * contains tunneling information. + * - `NO_MEMORY` - Not enough memory to queue @p workBundle. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + queue(WorkBundle workBundle) generates (Status status); + + /** + * Discards and abandons any pending `Work` items for the component. + * + * This method must be supported in running (including tripped) states. + * + * `Work` that could be immediately abandoned/discarded must be returned in + * @p flushedWorkBundle. The order in which queued `Work` items are + * discarded can be arbitrary. + * + * `Work` that could not be abandoned or discarded immediately must be + * marked to be discarded at the earliest opportunity, and must be returned + * via IComponentListener::onWorkDone(). This must be completed within + * 500ms. + * + * @return status Status of the call, which may be + * - `OK` - The component has been successfully flushed. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return flushedWorkBundle `WorkBundle` object containing flushed `Work` + * items. + */ + flush( + ) generates ( + Status status, + WorkBundle flushedWorkBundle + ); + + /** + * Drains the component, and optionally downstream components. This is a + * signalling method; as such it does not wait for any work completion. + * + * The last `Work` item is marked as "drain-till-here", so the component is + * notified not to wait for further `Work` before it processes what is + * already queued. This method can also be used to set the end-of-stream + * flag after `Work` has been queued. Client can continue to queue further + * `Work` immediately after this method returns. + * + * This method must be supported in running (including tripped) states. + * + * `Work` that is completed must be returned via + * IComponentListener::onWorkDone(). + * + * @param withEos Whether to drain the component with marking end-of-stream. + * @return status Status of the call, which may be + * - `OK` - The drain request has been successfully recorded. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + drain(bool withEos) generates (Status status); + + /** + * Starts using a surface for output. + * + * This method must not block. + * + * @param blockPoolId Id of the `C2BlockPool` to be associated with the + * output surface. + * @param surface Output surface. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `CANNOT_DO` - The component does not support an output surface. + * - `REFUSED` - The output surface cannot be accessed. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + setOutputSurface( + uint64_t blockPoolId, + IGraphicBufferProducer surface + ) generates ( + Status status + ); + + /** + * Starts using an input surface. + * + * The component must be in running state. + * + * @param inputSurface Input surface to connect to. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `CANNOT_DO` - The component does not support an input surface. + * - `BAD_STATE` - The component is not in running state. + * - `DUPLICATE` - The component is already connected to an input surface. + * - `REFUSED` - The input surface is already in use. + * - `NO_MEMORY` - Not enough memory to start the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return connection `IInputSurfaceConnection` object, which can be used to + * query and configure properties of the connection. This cannot be + * null. + */ + connectToInputSurface( + IInputSurface inputSurface + ) generates ( + Status status, + IInputSurfaceConnection connection + ); + + /** + * Starts using an OMX input surface. + * + * The component must be in running state. + * + * This method is similar to connectToInputSurface(), but it takes an OMX + * input surface (as a pair of `IGraphicBufferProducer` and + * `IGraphicBufferSource`) instead of Codec2's own `IInputSurface`. + * + * @param producer Producer component of an OMX input surface. + * @param source Source component of an OMX input surface. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `CANNOT_DO` - The component does not support an OMX input surface. + * - `BAD_STATE` - The component is not in running state. + * - `DUPLICATE` - The component is already connected to an input surface. + * - `REFUSED` - The input surface is already in use. + * - `NO_MEMORY` - Not enough memory to start the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return connection `IInputSurfaceConnection` object, which can be used to + * query and configure properties of the connection. This cannot be + * null. + */ + connectToOmxInputSurface( + IGraphicBufferProducer producer, + IGraphicBufferSource source + ) generates ( + Status status, + IInputSurfaceConnection connection + ); + + /** + * Stops using an input surface. + * + * The component must be in running state. + * + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `CANNOT_DO` - The component does not support an input surface. + * - `BAD_STATE` - The component is not in running state. + * - `NOT_FOUND` - The component is not connected to an input surface. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + disconnectFromInputSurface() generates (Status Status); + + /** + * Creates a local `C2BlockPool` backed by the given allocator and returns + * its id. + * + * The returned @p blockPoolId is the only way the client can refer to a + * `C2BlockPool` object in the component. The id can be passed to + * setOutputSurface() or used in some C2Param objects later. + * + * The created `C2BlockPool` object can be destroyed by calling + * destroyBlockPool(), reset() or release(). reset() and release() must + * destroy all `C2BlockPool` objects that have been created. + * + * @param allocatorId Id of a `C2Allocator`. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `NO_MEMORY` - Not enough memory to create the pool. + * - `BAD_VALUE` - @p allocatorId is not recognized. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return blockPoolId Id of the created C2BlockPool object. This may be + * used in setOutputSurface() if the allocator + * @return configurable Configuration interface for the created pool. This + * must not be null. + */ + createBlockPool(uint32_t allocatorId) generates ( + Status status, + uint64_t blockPoolId, + IConfigurable configurable + ); + + /** + * Destroys a local block pool previously created by createBlockPool(). + * + * @param blockPoolId Id of a `C2BlockPool` that was previously returned by + * createBlockPool(). + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `NOT_FOUND` - The supplied blockPoolId is not valid. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + destroyBlockPool(uint64_t blockPoolId) generates (Status status); + + // STATE CHANGE METHODS + // ========================================================================= + + /** + * Starts the component. + * + * This method must be supported in stopped state as well as tripped state. + * + * If the return value is `OK`, the component must be in the running state. + * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is + * expected as a response to this call. Otherwise, the component must be in + * the stopped state. + * + * If a component is in the tripped state and start() is called while the + * component configuration still results in a trip, start() must succeed and + * a new onTripped() callback must be used to communicate the configuration + * conflict that results in the new trip. + * + * @return status Status of the call, which may be + * - `OK` - The component has started successfully. + * - `BAD_STATE` - Component is not in stopped or tripped state. + * - `DUPLICATE` - When called during another start call from another + * thread. + * - `NO_MEMORY` - Not enough memory to start the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + start() generates (Status status); + + /** + * Stops the component. + * + * This method must be supported in running (including tripped) state. + * + * This method must return withing 500ms. + * + * Upon this call, all pending `Work` must be abandoned. + * + * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is + * expected as a response to this call. For all other return values, the + * component must be in the stopped state. + * + * This does not alter any settings and tunings that may have resulted in a + * tripped state. + * + * @return status Status of the call, which may be + * - `OK` - The component has stopped successfully. + * - `BAD_STATE` - Component is not in running state. + * - `DUPLICATE` - When called during another stop call from another + * thread. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + stop() generates (Status status); + + /** + * Resets the component. + * + * This method must be supported in all (including tripped) states other + * than released. + * + * This method must be supported during any other blocking call. + * + * This method must return withing 500ms. + * + * When this call returns, if @p status is `OK`, all `Work` items must + * have been abandoned, and all resources (including `C2BlockPool` objects + * previously created by createBlockPool()) must have been released. + * + * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is + * expected as a response to this call. For all other return values, the + * component must be in the stopped state. + * + * This brings settings back to their default, "guaranteeing" no tripped + * state. + * + * @return status Status of the call, which may be + * - `OK` - The component has been reset. + * - `BAD_STATE` - Component is in released state. + * - `DUPLICATE` - When called during another reset call from another + * thread. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + reset() generates (Status status); + + /** + * Releases the component. + * + * This method must be supported in stopped state. + * + * This method destroys the component. Upon return, if @p status is `OK` or + * `DUPLICATE`, all resources must have been released. + * + * @return status Status of the call, which may be + * - `OK` - The component has been released. + * - `BAD_STATE` - The component is running. + * - `DUPLICATE` - The component is already released. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + release() generates (Status status); + + /** + * Returns the @ref IComponentInterface instance associated to this + * component. + * + * An @p IConfigurable instance for the component can be obtained by calling + * IComponentInterface::getConfigurable() on the returned @p intf. + * + * @return intf `IComponentInterface` instance. This must not be null. + */ + getInterface() generates (IComponentInterface intf); +}; + diff --git a/media/c2/1.0/IComponentInterface.hal b/media/c2/1.0/IComponentInterface.hal new file mode 100644 index 0000000000..a007d02fe3 --- /dev/null +++ b/media/c2/1.0/IComponentInterface.hal @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +import IConfigurable; + +/** + * Component interface object. This object contains all of the configurations of + * a potential or actual component. It can be created and used independently of + * an actual Codec2 component to query supported parameters for various + * component settings, and configurations for a potential component. + * + * An actual component exposes this interface via IComponent::getInterface(). + */ +interface IComponentInterface { + /** + * Returns the @ref IConfigurable instance associated to this component + * interface. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); +}; + diff --git a/media/c2/1.0/IComponentListener.hal b/media/c2/1.0/IComponentListener.hal new file mode 100644 index 0000000000..70d5fb289e --- /dev/null +++ b/media/c2/1.0/IComponentListener.hal @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +/** + * Callback interface for handling notifications from @ref IComponent. + */ +interface IComponentListener { + + /** + * Notify the listener that some `Work` items have been completed. + * + * All the input buffers in the returned `Work` objects must not be used by + * the component after onWorkDone() is called. + * + * @param workBundle List of completed `Work` objects. + */ + oneway onWorkDone(WorkBundle workBundle); + + /** + * Notify the listener that the component is tripped. + * + * @param settingResults List of failures. + */ + oneway onTripped(vec<SettingResult> settingResults); + + /** + * Notify the listener of an error. + * + * @param status Error type. @p status may be `OK`, which means that an + * error has occurred, but the error type does not fit into the type + * `Status`. In this case, additional information is provided by + * @p errorCode. + * @param errorCode Additional error information. The framework may not + * recognize the meaning of this value. + */ + oneway onError(Status status, uint32_t errorCode); + + /** + * Information about rendering of a frame to a `Surface`. + */ + struct RenderedFrame { + /** + * Id of the `BufferQueue` containing the rendered buffer. + * + * This value must have been obtained by an earlier call to + * IGraphicBufferProducer::getUniqueId(). + */ + uint64_t bufferQueueId; + /** + * Id of the slot of the rendered buffer. + * + * This value must have been obtained by an earlier call to + * IGraphicBufferProducer::dequeueBuffer() or + * IGraphicBufferProducer::attachBuffer(). + */ + int32_t slotId; + /** + * Timestamp the rendering happened. + * + * The reference point for the timestamp is determined by the + * `BufferQueue` that performed the rendering. + */ + int64_t timestampNs; + }; + + /** + * Notify the listener that frames have been rendered. + * + * @param renderedFrames List of @ref RenderedFrame objects. + */ + oneway onFramesRendered(vec<RenderedFrame> renderedFrames); + + /** + * Identifying information for an input buffer previously queued to the + * component via IComponent::queue(). + */ + struct InputBuffer { + /** + * This value comes from `Work::input.ordinal.frameIndex` in a `Work` + * object that was previously queued. + */ + uint64_t frameIndex; + /** + * This value is an index into `Work::input.buffers` (which is an array) + * in a `Work` object that was previously queued. + */ + uint32_t arrayIndex; + }; + + /** + * Notify the listener that some input buffers are no longer needed by the + * component, and hence can be released or reused by the client. + * + * Input buffers that are contained in a `Work` object returned by an + * earlier onWorkDone() call are assumed released, so they must not appear + * in any onInputBuffersReleased() calls. That means + * onInputBuffersReleased() must only report input buffers that are released + * before the output in the same `Work` item is produced. However, it is + * possible for an input buffer to be returned by onWorkDone() after it has + * been reported by onInputBuffersReleased(). + * + * @note onWorkDone() and onInputBuffersReleased() both notify the client + * that input buffers are no longer needed. However, in order to minimize + * IPC calls, onInputBuffersReleased() should be called only when + * onWorkDone() cannot be called, e.g., the component needs more input + * before an output can be produced. + * + * @param inputBuffers List of `InputBuffer` objects, identifying input + * buffers that are no longer needed by the component. + */ + oneway onInputBuffersReleased(vec<InputBuffer> inputBuffers); +}; + diff --git a/media/c2/1.0/IComponentStore.hal b/media/c2/1.0/IComponentStore.hal new file mode 100644 index 0000000000..2aa6a70b5d --- /dev/null +++ b/media/c2/1.0/IComponentStore.hal @@ -0,0 +1,224 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +import android.hardware.media.bufferpool@2.0::IClientManager; +import IComponentInterface; +import IComponentListener; +import IComponent; +import IConfigurable; +import IInputSurface; + +/** + * Entry point for Codec2 HAL. + * + * All methods in `IComponentStore` must not block. If a method call cannot be + * completed in a timely manner, it must return `TIMED_OUT` in the return + * status. The only exceptions are getPoolClientManager() and getConfigurable(), + * which must always return immediately. + */ +interface IComponentStore { + + /** + * Creates a component by name. + * + * @param name Name of the component to create. This must match one of the + * names returned by listComponents(). + * @param listener Callback receiver. + * @param pool `IClientManager` object of the BufferPool in the client + * process. This may be null if the client does not own a BufferPool. + * @return status Status of the call, which may be + * - `OK` - The component was created successfully. + * - `NOT_FOUND` - There is no component with the given name. + * - `NO_MEMORY` - Not enough memory to create the component. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return comp The created component if @p status is `OK`. + * + * @sa IComponentListener. + */ + createComponent( + string name, + IComponentListener listener, + IClientManager pool + ) generates ( + Status status, + IComponent comp + ); + + /** + * Creates a component interface by name. + * + * @param name Name of the component interface to create. This should match + * one of the names returned by listComponents(). + * @return status Status of the call, which may be + * - `OK` - The component interface was created successfully. + * - `NOT_FOUND` - There is no component interface with the given name. + * - `NO_MEMORY` - Not enough memory to create the component interface. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return compIntf The created component interface if @p status is `OK`. + */ + createInterface( + string name + ) generates ( + Status status, + IComponentInterface compIntf + ); + + /** + * Component traits. + */ + struct ComponentTraits { + /** + * Name of the component. This must be unique for each component. + * + * This name is use to identify the component to create in + * createComponent() and createComponentInterface(). + */ + string name; + + enum Domain : uint32_t { + OTHER = 0, + VIDEO, + AUDIO, + IMAGE, + }; + /** + * Component domain. + */ + Domain domain; + + enum Kind : uint32_t { + OTHER = 0, + DECODER, + ENCODER, + }; + /** + * Component kind. + */ + Kind kind; + + /** + * Rank used by `MediaCodecList` to determine component ordering. Lower + * value means higher priority. + */ + uint32_t rank; + + /** + * MIME type. + */ + string mediaType; + + /** + * Aliases for component name for backward compatibility. + * + * Multiple components can have the same alias (but not the same + * component name) as long as their media types differ. + */ + vec<string> aliases; + }; + + /** + * Returns the list of components supported by this component store. + * + * @return status Status of the call, which may be + * - `OK` - The operation was successful. + * - `NO_MEMORY` - Not enough memory to complete this method. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return traits List of component traits for all components supported by + * this store (in no particular order). + */ + listComponents() generates ( + Status status, + vec<ComponentTraits> traits + ); + + /** + * Creates a persistent input surface that can be used as an input surface + * for any IComponent instance + * + * @return status Status of the call, which may be + * - `OK` - The operation was successful. + * - `NO_MEMORY` - Not enough memory to complete this method. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return surface A persistent input surface. This may be null to indicate + * an error. + */ + createInputSurface() generates ( + Status status, + IInputSurface surface + ); + + /** + * Returns a list of `StructDescriptor` objects for a set of requested + * C2Param structure indices that this store is aware of. + * + * This operation must be performed at best effort, e.g. the component + * store must simply ignore all struct indices that it is not aware of. + * + * @param indices Indices of C2Param structures to describe. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `NOT_FOUND` - Some indices were not known. + * - `NO_MEMORY` - Not enough memory to complete this method. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return structs List of `StructDescriptor` objects. + */ + getStructDescriptors( + vec<ParamIndex> indices + ) generates ( + Status status, + vec<StructDescriptor> structs + ); + + /** + * Copies the contents of @p src into @p dst without changing the format of + * @p dst. + * + * @param src Source buffer. + * @param dst Destination buffer. + * @return status Status of the call, which may be + * - `OK` - The copy is successful. + * - `CANNOT_DO` - @p src and @p dst are not compatible. + * - `REFUSED` - No permission to copy. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + copyBuffer(Buffer src, Buffer dst) generates (Status status); + + /** + * Returns the `IClientManager` object for the component's BufferPool. + * + * @return pool If the component store supports receiving buffers via + * BufferPool API, @p pool must be a valid `IClientManager` instance. + * Otherwise, @p pool must be null. + */ + getPoolClientManager() generates (IClientManager pool); + + /** + * Returns the @ref IConfigurable instance associated to this component + * store. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); +}; + diff --git a/media/c2/1.0/IConfigurable.hal b/media/c2/1.0/IConfigurable.hal new file mode 100644 index 0000000000..31dc4d3cba --- /dev/null +++ b/media/c2/1.0/IConfigurable.hal @@ -0,0 +1,241 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +/** + * Generic configuration interface presented by all configurable Codec2 objects. + * + * This interface must be supported in all states of the owning object, and must + * not change the state of the owning object. + */ +interface IConfigurable { + /** + * Returns the id of the object. This must be unique among all objects of + * the same type hosted by the same store. + * + * @return id Id of the object. + */ + getId() generates (uint32_t id); + + /** + * Returns the name of the object. + * + * This must match the name that was supplied during the creation of the + * object. + * + * @return name Name of the object. + */ + getName() generates (string name); + + /** + * Queries a set of parameters from the object. + * + * Querying is performed at best effort: the object must query all supported + * parameters and skip unsupported ones (which may include parameters that + * could not be allocated). Any errors are communicated in the return value. + * + * If @p mayBlock is false, this method must not block. All parameter + * queries that require blocking must be skipped. + * + * If @p mayBlock is true, a query may block, but the whole method call + * has to complete in a timely manner, or `status = TIMED_OUT` is returned. + * + * If @p mayBlock is false, this method must not block. Otherwise, this + * method is allowed to block for a certain period of time before completing + * the operation. If the operation is not completed in a timely manner, + * `status = TIMED_OUT` is returned. + * + * @note The order of C2Param objects in @p param does not depend on the + * order of C2Param structure indices in @p indices. + * + * \par For IComponent + * + * When the object type is @ref IComponent, this method must be supported in + * any state except released. This call must not change the state nor the + * internal configuration of the component. + * + * The blocking behavior of this method differs among states: + * - In the stopped state, this must be non-blocking. @p mayBlock is + * ignored. (The method operates as if @p mayBlock was false.) + * - In any of the running states, this method may block momentarily if + * @p mayBlock is true. However, if the call cannot be completed in a + * timely manner, `status = TIMED_OUT` is returned. + * + * @param indices List of C2Param structure indices to query. + * @param mayBlock Whether this call may block or not. + * @return status Status of the call, which may be + * - `OK` - All parameters could be queried. + * - `BAD_INDEX` - All supported parameters could be queried, but some + * parameters were not supported. + * - `NO_MEMORY` - Could not allocate memory for a supported parameter. + * - `BLOCKING` - Querying some parameters requires blocking, but + * @p mayBlock is false. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return params Flattened representation of C2Param objects. + * + * @sa Params. + */ + query( + vec<ParamIndex> indices, + bool mayBlock + ) generates ( + Status status, + Params params + ); + + /** + * Sets a set of parameters for the object. + * + * Tuning is performed at best effort: the object must update all supported + * configurations at best effort and skip unsupported parameters. Any errors + * are communicated in the return value and in @p failures. + * + * A non-strict parameter update with an unsupported value shall cause an + * update to the closest supported value. A strict parameter update with an + * unsupported value shall be skipped and a failure shall be returned. + * + * If @p mayBlock is false, this method must not block. An update that + * requires blocking shall be skipped and a failure shall be returned. + * + * If @p mayBlock is true, an update may block, but the whole method call + * has to complete in a timely manner, or `status = TIMED_OUT` is returned. + * + * The final values for all parameters set are propagated back to the caller + * in @p params. + * + * \par For IComponent + * + * When the object type is @ref IComponent, this method must be supported in + * any state except released. + * + * The blocking behavior of this method differs among states: + * - In the stopped state, this must be non-blocking. @p mayBlock is + * ignored. (The method operates as if @p mayBlock was false.) + * - In any of the running states, this method may block momentarily if + * @p mayBlock is true. However, if the call cannot be completed in a + * timely manner, `status = TIMED_OUT` is returned. + * + * @note Parameter tuning @e does depend on the order of the tuning + * parameters, e.g., some parameter update may enable some subsequent + * parameter update. + * + * @param inParams Requested parameter updates. + * @param mayBlock Whether this call may block or not. + * @return status Status of the call, which may be + * - `OK` - All parameters could be updated successfully. + * - `BAD_INDEX` - All supported parameters could be updated successfully, + * but some parameters were not supported. + * - `NO_MEMORY` - Some supported parameters could not be updated + * successfully because they contained unsupported values. + * These are returned in @p failures. + * - `BLOCKING` - Setting some parameters requires blocking, but + * @p mayBlock is false. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return failures List of update failures. + * @return outParams Flattened representation of configured parameters. The + * order of parameters in @p outParams is based on the order of + * requested updates in @p inParams. + * + * @sa SettingResult. + */ + config( + Params inParams, + bool mayBlock + ) generates ( + Status status, + vec<SettingResult> failures, + Params outParams + ); + + // REFLECTION MECHANISM + // ========================================================================= + + /** + * Returns a list of supported parameters within a selected range of C2Param + * structure indices. + * + * @param start The first index of the selected range. + * @param count The length of the selected range. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `NO_MEMORY` - Not enough memory to complete this method. + * @return params List of supported parameters in the selected range. This + * list may have fewer than @p count elements if some indices in the + * range are not supported. + * + * @sa ParamDescriptor. + */ + querySupportedParams( + uint32_t start, + uint32_t count + ) generates ( + Status status, + vec<ParamDescriptor> params + ); + + /** + * Retrieves the supported values for the queried fields. + * + * The object must process all fields queried even if some queries fail. + * + * If @p mayBlock is false, this method must not block. Otherwise, this + * method is allowed to block for a certain period of time before completing + * the operation. If the operation cannot be completed in a timely manner, + * `status = TIMED_OUT` is returned. + * + * \par For IComponent + * + * When the object type is @ref IComponent, this method must be supported in + * any state except released. + * + * The blocking behavior of this method differs among states: + * - In the stopped state, this must be non-blocking. @p mayBlock is + * ignored. (The method operates as if @p mayBlock was false.) + * - In any of the running states, this method may block momentarily if + * @p mayBlock is true. However, if the call cannot be completed in a + * timely manner, `status = TIMED_OUT` is returned. + * + * @param inFields List of field queries. + * @param mayBlock Whether this call may block or not. + * @return status Status of the call, which may be + * - `OK` - The operation completed successfully. + * - `BLOCKING` - Querying some parameters requires blocking, but + * @p mayBlock is false. + * - `NO_MEMORY` - Not enough memory to complete this method. + * - `BAD_INDEX` - At least one field was not recognized as a component + * field. + * - `BLOCKING` - Querying some fields requires blocking, but @p mayblock + * is false. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + * @return outFields List of supported values and results for the + * supplied queries. + * + * @sa FieldSupportedValuesQuery, FieldSupportedValuesQueryResult. + */ + querySupportedValues( + vec<FieldSupportedValuesQuery> inFields, + bool mayBlock + ) generates ( + Status status, + vec<FieldSupportedValuesQueryResult> outFields + ); + +}; + diff --git a/media/c2/1.0/IInputSink.hal b/media/c2/1.0/IInputSink.hal new file mode 100644 index 0000000000..809c27a7aa --- /dev/null +++ b/media/c2/1.0/IInputSink.hal @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer; + +import IConfigurable; + +/** + * An `IInputSink` is a receiver of work items. + * + * An @ref IComponent instance can present itself as an `IInputSink` via a thin + * wrapper. + * + * @sa IInputSurface, IComponent. + */ +interface IInputSink { + /** + * Feeds work to the sink. + * + * @param workBundle `WorkBundle` object containing a list of `Work` objects + * to queue to the component. + * @return status Status of the call, which may be + * - `OK` - Works in @p workBundle were successfully queued. + * - `BAD_INDEX` - Some component id in some `Worklet` is not valid. + * - `CANNOT_DO` - Tunneling has not been set up for this sink, but some + * `Work` object contains tunneling information. + * - `NO_MEMORY` - Not enough memory to queue @p workBundle. + * - `TIMED_OUT` - The operation cannot be finished in a timely manner. + * - `CORRUPTED` - Some unknown error occurred. + */ + queue(WorkBundle workBundle) generates (Status status); + + /** + * Returns the @ref IConfigurable instance associated to this sink. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); +}; + diff --git a/media/c2/1.0/IInputSurface.hal b/media/c2/1.0/IInputSurface.hal new file mode 100644 index 0000000000..d11ce15e0e --- /dev/null +++ b/media/c2/1.0/IInputSurface.hal @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer; + +import IConfigurable; +import IInputSink; +import IInputSurfaceConnection; + +/** + * Input surface for a Codec2 component. + * + * An <em>input surface</em> is an instance of `IInputSurface`, which may be + * created by calling IComponentStore::createInputSurface(). Once created, the + * client may + * 1. write data to it via the `IGraphicBufferProducer` interface; and + * 2. use it as input to a Codec2 encoder. + * + * @sa IInputSurfaceConnection, IComponentStore::createInputSurface(), + * IComponent::connectToInputSurface(). + */ +interface IInputSurface { + /** + * Returns the producer interface into the internal buffer queue. + * + * @return producer `IGraphicBufferProducer` instance. This must not be + * null. + */ + getGraphicBufferProducer() generates (IGraphicBufferProducer producer); + + /** + * Returns the @ref IConfigurable instance associated to this input surface. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); + + /** + * Connects the input surface to an input sink. + * + * This function is generally called from inside the implementation of + * IComponent::connectToInputSurface(), where @p sink is a thin wrapper of + * the component that consumes buffers from this surface. + * + * @param sink Input sink. See `IInputSink` for more information. + * @return status Status of the call, which may be + * - `OK` - Configuration successful. + * - `BAD_VALUE` - @p sink is invalid. + * - `CORRUPTED` - Some unknown error occurred. + * @return connection `IInputSurfaceConnection` object. This must not be + * null if @p status is `OK`. + */ + connect( + IInputSink sink + ) generates ( + Status status, + IInputSurfaceConnection connection + ); +}; + diff --git a/media/c2/1.0/IInputSurfaceConnection.hal b/media/c2/1.0/IInputSurfaceConnection.hal new file mode 100644 index 0000000000..035b1159b4 --- /dev/null +++ b/media/c2/1.0/IInputSurfaceConnection.hal @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +import IConfigurable; + +/** + * Connection between a component and an input surface. + * + * An instance of `IInputSurfaceConnection` contains an `IConfigurable` + * interface for querying and configuring properties of the connection. + */ +interface IInputSurfaceConnection { + /** + * Destroys the connection between an input surface and a component. + * + * @return status Status of the call, which may be + * - `OK` - The disconnection succeeded. + * - `BAD_STATE` - The component is not in running state. + * - `NOT_FOUND` - The surface is not connected to a component. + * - `CORRUPTED` - Some unknown error occurred. + */ + disconnect() generates (Status status); + + /** + * Returns the @ref IConfigurable instance associated to this connection. + * + * This can be used to customize the connection. + * + * @return configurable `IConfigurable` instance. This must not be null. + */ + getConfigurable() generates (IConfigurable configurable); +}; + diff --git a/media/c2/1.0/types.hal b/media/c2/1.0/types.hal new file mode 100644 index 0000000000..ec422b1f40 --- /dev/null +++ b/media/c2/1.0/types.hal @@ -0,0 +1,827 @@ +/* + * 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. + */ + +package android.hardware.media.c2@1.0; + +import android.hardware.media.bufferpool@2.0::BufferStatusMessage; + +/** + * Common return values for Codec2 operations. + */ +enum Status : int32_t { + /** Operation completed successfully. */ + OK = 0, + + // bad input + + /** Argument has invalid value (user error). */ + BAD_VALUE = -22, + /** Argument uses invalid index (user error). */ + BAD_INDEX = -75, + /** Argument/Index is valid but not possible. */ + CANNOT_DO = -2147483646, + + // bad sequencing of events + + /** Object already exists. */ + DUPLICATE = -17, + /** Object not found. */ + NOT_FOUND = -2, + /** Operation is not permitted in the current state. */ + BAD_STATE = -38, + /** Operation would block but blocking is not permitted. */ + BLOCKING = -9930, + + // bad environment + + /** Not enough memory to complete operation. */ + NO_MEMORY = -12, + /** Missing permission to complete operation. */ + REFUSED = -1, + + /** Operation did not complete within timeout. */ + TIMED_OUT = -110, + + // missing functionality + + /** Operation is not implemented/supported (optional only). */ + OMITTED = -74, + + // unknown fatal + + /** Some unexpected error prevented the operation. */ + CORRUPTED = -2147483648, + + // uninitialized + + /** Status has not been initialized. */ + NO_INIT = -19, +}; + +/** + * C2Param structure index. + * + * This is a number that is unique for each C2Param structure type. + * + * @sa Codec 2.0 standard. + */ +typedef uint32_t ParamIndex; + +/** + * Flattened representation of C2Param objects. + * + * The `Params` type is an array of bytes made up by concatenating a list of + * C2Param objects. The start index (offset into @ref Params) of each C2Param + * object in the list is divisible by 8. Up to 7 padding bytes may be added + * after each C2Param object to achieve this 64-bit alignment. + * + * Each C2Param object has the following layout: + * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the + * type of the C2Param object. + * - 4 bytes: size of the C2Param object (unsigned 4-byte integer). + * - (size - 8) bytes: data of the C2Param object. + * + * In order to interpret each C2Param object correctly, its structure must be + * described by IComponentStore::getStructDescriptors(). + * + * @note Please refer to the Codec 2.0 standard for the list of standard + * parameter structures. + * + * @sa Codec 2.0 standard. + */ +typedef vec<uint8_t> Params; + +/** + * Identifying information of a field relative to a known C2Param structure. + * + * Within a given C2Param structure, each field is uniquely identified by @ref + * FieldId. + */ +struct FieldId { + /** Offset of the field in bytes. */ + uint32_t offset; + /** Size of the field in bytes. */ + uint32_t size; +}; + +/** + * Reference to a field in a C2Param structure. + */ +struct ParamField { + /** Index of the C2Param structure. */ + ParamIndex index; + /** Identifier of the field inside the C2Param structure. */ + FieldId fieldId; +}; + +/** + * Usage description of a C2Param structure. + * + * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams(). + */ +struct ParamDescriptor { + /** + * Index of the C2Param structure being described. + */ + ParamIndex index; + + enum Attrib : uint32_t { + /** + * The parameter is required to be specified. + */ + REQUIRED = 1u << 0, + /** + * The parameter retains its value. + */ + PERSISTENT = 1u << 1, + /** + * The parameter is strict. + */ + STRICT = 1u << 2, + /** + * The parameter is publicly read-only. + */ + READ_ONLY = 1u << 3, + /** + * The parameter must not be visible to clients. + */ + HIDDEN = 1u << 4, + /** + * The parameter must not be used by framework (other than testing). + */ + INTERNAL = 1u << 5, + /** + * The parameter is publicly constant (hence read-only). + */ + CONST = 1u << 6, + }; + bitfield<Attrib> attrib; + + /** + * Name of the structure. This must be unique for each structure. + */ + string name; + + /** + * Indices of other C2Param structures that this C2Param structure depends + * on. + */ + vec<ParamIndex> dependencies; +}; + +// Generic way to describe supported numeric values for Codec2 interfaces. + +/** + * An untyped value that can fit in 64 bits, the type of which is communicated + * via a separate channel (@ref FieldSupportedValues.type). + */ +typedef uint64_t PrimitiveValue; + +/* + * Description of supported values for a field. + * + * This can be a continuous range or a discrete set of values. + */ +struct FieldSupportedValues { + /** + * Used if #type is `RANGE`. + * + * If the `step` member is 0, and `num` and `denom` are both 1, the `Range` + * structure represents a closed interval bounded by `min` and `max`. + * + * Otherwise, the #Range structure represents a finite sequence of numbers + * produced from the following recurrence relation: + * + * @code + * v[0] = min + * v[i] = v[i - 1] * num / denom + step ; i >= 1 + * @endcode + * + * Both the ratio `num / denom` and the value `step` must be positive. The + * last number in the sequence described by this #Range structure is the + * largest number in the sequence that is smaller than or equal to `max`. + * + * @note + * The division in the formula may truncate the result if the data type of + * these values is an integral type. + */ + struct Range { + /** + * Lower end of the range (inclusive). + */ + PrimitiveValue min; + /** + * Upper end of the range (inclusive). + */ + PrimitiveValue max; + /** + * The non-homogeneous term in the recurrence relation. + */ + PrimitiveValue step; + /** + * The numerator of the scale coefficient in the recurrence relation. + */ + PrimitiveValue num; + /** + * The denominator of the scale coefficient in the recurrence relation. + */ + PrimitiveValue denom; + }; + + enum Type : int32_t { + /** No supported values */ + EMPTY = 0, + /** Numeric range, described in a #Range structure */ + RANGE, + /** List of values */ + VALUES, + /** List of flags that can be OR-ed */ + FLAGS, + }; + /** + * Type of the supported values. + */ + Type type; + + /** + * When #type is #Type.RANGE, #range shall specify the range of possible + * values. + * + * The intended type of members of #range shall be clear in the context + * where `FieldSupportedValues` is used. + */ + Range range; + + /** + * When #type is #Type.VALUES or #Type.FLAGS, #value shall list supported + * values/flags. + * + * The intended type of components of #value shall be clear in the context + * where `FieldSupportedValues` is used. + */ + vec<PrimitiveValue> values; +}; + +/** + * Supported values for a field. + * + * This is a pair of the field specifier together with an optional supported + * values object. This structure is used when reporting parameter configuration + * failures and conflicts. + */ +struct ParamFieldValues { + /** + * Reference to a field or a C2Param structure. + */ + ParamField paramOrField; + + /** + * Optional supported values for the field if #paramOrField specifies an + * actual field that is numeric (non struct, blob or string). Supported + * values for arrays (including string and blobs) describe the supported + * values for each element (character for string, and bytes for blobs). It + * is optional for read-only strings and blobs. + */ + vec<FieldSupportedValues> values; +}; + +/** + * Description of a field inside a C2Param structure. + */ +struct FieldDescriptor { + + /** Location of the field in the C2Param structure */ + FieldId fieldId; + + /** + * Possible types of the field. + */ + enum Type : uint32_t { + NO_INIT = 0, + INT32, + UINT32, + CNTR32, + INT64, + UINT64, + CNTR64, + FLOAT, + /** + * Fixed-size string (POD). + */ + STRING = 0x100, + /** + * A blob has no sub-elements and can be thought of as an array of + * bytes. However, bytes cannot be individually addressed by clients. + */ + BLOB, + /** + * The field is a structure that may contain other fields. + */ + STRUCT = 0x20000, + }; + /** + * Type of the field. + */ + bitfield<Type> type; + + /** + * If #type is #Type.STRUCT, #structIndex is the C2Param structure index; + * otherwise, #structIndex is not used. + */ + ParamIndex structIndex; + + /** + * Extent of the field. + * - For a non-array field, #extent is 1. + * - For a fixed-length array field, #extent is the length. An array field + * of length 1 is indistinguishable from a non-array field. + * - For a variable-length array field, #extent is 0. This can only occur as + * the last member of a C2Param structure. + */ + uint32_t extent; + + /** + * Name of the field. This must be unique for each field in the same + * structure. + */ + string name; + + /** + * Named value type. This is used for defining an enum value for a numeric + * type. + */ + struct NamedValue { + /** + * Name of the enum value. This must be unique for each enum value in + * the same field. + */ + string name; + /** + * Underlying value of the enum value. Multiple enum names may have the + * same underlying value. + */ + PrimitiveValue value; + }; + /** + * List of enum values. This is not used when #type is not one of the + * numeric types. + */ + vec<NamedValue> namedValues; +}; + +/** + * Description of a C2Param structure. It consists of an index and a list of + * `FieldDescriptor`s. + */ +struct StructDescriptor { + /** + * Index of the structure. + */ + ParamIndex type; + /** + * List of fields in the structure. + * + * Fields are ordered by their offsets. A field that is a structure is + * ordered before its members. + */ + vec<FieldDescriptor> fields; +}; + +/** + * Information describing the reason the parameter settings may fail, or may be + * overridden. + */ +struct SettingResult { + /** Failure code */ + enum Failure : uint32_t { + /** Parameter is not supported. */ + BAD_TYPE, + /** Parameter is not supported on the specific port. */ + BAD_PORT, + /** Parameter is not supported on the specific stream. */ + BAD_INDEX, + /** Parameter is read-only and cannot be set. */ + READ_ONLY, + /** Parameter mismatches input data. */ + MISMATCH, + /** Strict parameter does not accept value for the field at all. */ + BAD_VALUE, + /** + * Strict parameter field value is in conflict with an/other + * setting(s). + */ + CONFLICT, + /** + * Parameter field is out of range due to other settings. (This failure + * mode can only be used for strict calculated parameters.) + */ + UNSUPPORTED, + /** + * Field does not access the requested parameter value at all. It has + * been corrected to the closest supported value. This failure mode is + * provided to give guidance as to what are the currently supported + * values for this field (which may be a subset of the at-all-potential + * values). + */ + INFO_BAD_VALUE, + /** + * Requested parameter value is in conflict with an/other setting(s) + * and has been corrected to the closest supported value. This failure + * mode is given to provide guidance as to what are the currently + * supported values as well as to optionally provide suggestion to the + * client as to how to enable the requested parameter value. + */ + INFO_CONFLICT, + }; + Failure failure; + + /** + * Failing (or corrected) field or parameter and optionally, currently + * supported values for the field. Values must only be set for field + * failures other than `BAD_VALUE`, and only if they are different from the + * globally supported values (e.g. due to restrictions by another parameter + * or input data). + */ + ParamFieldValues field; + + /** + * Conflicting parameters or fields with (optional) suggested values for any + * conflicting fields to avoid the conflict. Values must only be set for + * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code. + */ + vec<ParamFieldValues> conflicts; +}; + +/** + * Ordering information of @ref FrameData objects. Each member is used for + * comparing urgency: a smaller difference from a reference value indicates that + * the associated Work object is more urgent. The reference value for each + * member is initialized the first time it is communicated between the client + * and the codec, and it may be updated to later values that are communicated. + * + * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual + * order it represents is derived by subtracting the reference value, then + * interpreting the result as a signed number with the same storage size (using + * two's complement). + * + * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the + * Codec 2.0 standard. + */ +struct WorkOrdinal { + /** + * Timestamp in microseconds. + */ + uint64_t timestampUs; + /** + * Frame index. + */ + uint64_t frameIndex; + /** + * Component specific frame ordinal. + */ + uint64_t customOrdinal; +}; + +/** + * Storage type for `BaseBlock`. + * + * A `BaseBlock` is a representation of a codec memory block. Coded data, + * decoded data, codec-specific data, and other codec-related data are all sent + * in the form of BaseBlocks. + */ +safe_union BaseBlock { + /** + * #nativeBlock is the opaque representation of a buffer. + */ + handle nativeBlock; + /** + * #pooledBlock is a reference to a buffer handled by a BufferPool. + */ + BufferStatusMessage pooledBlock; +}; + +/** + * Reference to a @ref BaseBlock within a @ref WorkBundle. + * + * `Block` contains additional attributes that `BaseBlock` does not. These + * attributes may differ among `Block` objects that refer to the same + * `BaseBlock` in the same `WorkBundle`. + */ +struct Block { + /** + * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into + * #WorkBundle.baseBlocks. + */ + uint32_t index; + /** + * Metadata associated with this `Block`. + */ + Params meta; + /** + * Fence for synchronizing `Block` access. + */ + handle fence; +}; + +/** + * A codec buffer, which is a collection of @ref Block objects and metadata. + * + * This is a part of @ref FrameData. + */ +struct Buffer { + /** + * Metadata associated with the buffer. + */ + Params info; + /** + * Blocks contained in the buffer. + */ + vec<Block> blocks; +}; + +/** + * An extension of @ref Buffer that also contains a C2Param structure index. + * + * This is a part of @ref FrameData. + */ +struct InfoBuffer { + /** + * A C2Param structure index. + */ + ParamIndex index; + /** + * Associated @ref Buffer object. + */ + Buffer buffer; +}; + +/** + * Data for an input frame or an output frame. + * + * This structure represents a @e frame with its metadata. A @e frame consists + * of an ordered set of buffers, configuration changes, and info buffers along + * with some non-configuration metadata. + * + * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0 + * standard. + */ +struct FrameData { + enum Flags : uint32_t { + /** + * For input frames: no output frame shall be generated when processing + * this frame, but metadata must still be processed. + * + * For output frames: this frame must be discarded but metadata is still + * valid. + */ + DROP_FRAME = (1 << 0), + /** + * This frame is the last frame of the current stream. Further frames + * are part of a new stream. + */ + END_OF_STREAM = (1 << 1), + /** + * This frame must be discarded with its metadata. + * + * This flag is only set by components, e.g. as a response to the flush + * command. + */ + DISCARD_FRAME = (1 << 2), + /** + * This frame is not the last frame produced for the input. + * + * This flag is normally set by the component - e.g. when an input frame + * results in multiple output frames, this flag is set on all but the + * last output frame. + * + * Also, when components are chained, this flag should be propagated + * down the work chain. That is, if set on an earlier frame of a + * work-chain, it should be propagated to all later frames in that + * chain. Additionally, components down the chain could set this flag + * even if not set earlier, e.g. if multiple output frames are generated + * at that component for the input frame. + */ + FLAG_INCOMPLETE = (1 << 3), + /** + * This frame contains only codec-specific configuration data, and no + * actual access unit. + * + * @deprecated Pass codec configuration with the codec-specific + * configuration info together with the access unit. + */ + CODEC_CONFIG = (1u << 31), + }; + + /** + * Frame flags, as described in #Flags. + */ + bitfield<Flags> flags; + + /** + * @ref WorkOrdinal of the frame. + */ + WorkOrdinal ordinal; + + /** + * List of frame buffers. + */ + vec<Buffer> buffers; + + /** + * List of configuration updates. + */ + Params configUpdate; + + /** + * List of info buffers. + */ + vec<InfoBuffer> infoBuffers; +}; + +/** + * In/out structure containing some instructions for and results from output + * processing. + * + * This is a part of @ref Work. One `Worklet` corresponds to one output + * @ref FrameData. The client must construct an original `Worklet` object inside + * a @ref Work object for each expected output before calling + * IComponent::queue(). + */ +struct Worklet { + /** + * Component id. (Input) + * + * This is used only when tunneling is enabled. + * + * When used, this must match the return value from IConfigurable::getId(). + */ + uint32_t componentId; + + /** + * List of C2Param objects describing tunings to be applied before + * processing this `Worklet`. (Input) + */ + Params tunings; + + /** + * List of failures. (Output) + */ + vec<SettingResult> failures; + + /** + * Output frame data. (Output) + */ + FrameData output; +}; + +/** + * A collection of input data to and output data from the component. + * + * A `Work` object holds information about a single work item. It is created by + * the client and passed to the component via IComponent::queue(). The component + * has two ways of returning a `Work` object to the client: + * 1. If the queued `Work` object has been successfully processed, + * IComponentListener::onWorkDone() shall be called to notify the listener, + * and the output shall be included in the returned `Work` object. + * 2. If the client calls IComponent::flush(), a `Work` object that has not + * been processed shall be returned. + * + * `Work` is a part of @ref WorkBundle. + */ +struct Work { + /** + * Additional work chain info not part of this work. + */ + Params chainInfo; + + /** + * @ref FrameData for the input. + */ + FrameData input; + + /** + * The chain of `Worklet`s. + * + * The length of #worklets is 1 when tunneling is not enabled. + * + * If #worklets has more than a single element, the tunnels between + * successive components of the work chain must have been successfully + * pre-registered at the time that the `Work` is submitted. Allocating the + * output buffers in the `Worklet`s is the responsibility of each component + * in the chain. + * + * Upon `Work` submission, #worklets must be an appropriately sized vector + * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a + * successful processing, all but the final `Worklet` in the returned + * #worklets must have @ref Worklet.hasOutput set to `false`. + */ + vec<Worklet> worklets; + + /** + * The number of `Worklet`s successfully processed in this chain. + * + * This must be initialized to 0 by the client when the `Work` is submitted, + * and it must contain the number of `Worklet`s that were successfully + * processed when the `Work` is returned to the client. + * + * #workletsProcessed cannot exceed the length of #worklets. If + * #workletsProcessed is smaller than the length of #worklets, #result + * cannot be `OK`. + */ + uint32_t workletsProcessed; + + /** + * The final outcome of the `Work` (corresponding to #workletsProcessed). + * + * The value of @ref Status.OK implies that all `Worklet`s have been + * successfully processed. + */ + Status result; +}; + +/** + * List of `Work` objects. + * + * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and + * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of + * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work` + * objects together provides two benefits: + * 1. Batching of `Work` objects can reduce the number of IPC calls. + * 2. If multiple `Work` objects contain `Block`s that refer to the same + * `BaseBlock`, the number of `BaseBlock`s that is sent between processes + * is also reduced. + * + * @note `WorkBundle` is the HIDL counterpart of the vector of `C2Work` in the + * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the + * data transferred over an IPC. + */ +struct WorkBundle { + /** + * A list of Work items. + */ + vec<Work> works; + /** + * A list of blocks indexed by elements of #works. + */ + vec<BaseBlock> baseBlocks; +}; + +/** + * Query information for supported values of a field. This is used as input to + * IConfigurable::querySupportedValues(). + */ +struct FieldSupportedValuesQuery { + /** + * Identity of the field to query. + */ + ParamField field; + + enum Type : uint32_t { + /** Query all possible values regardless of other settings. */ + POSSIBLE, + /** Query currently possible values given dependent settings. */ + CURRENT, + }; + /** + * Type of the query. See #Type for more information. + */ + Type type; +}; + +/** + * This structure is used to hold the result from + * IConfigurable::querySupportedValues(). + */ +struct FieldSupportedValuesQueryResult { + /** + * Result of the query. Possible values are + * - `OK`: The query was successful. + * - `BAD_STATE`: The query was requested when the `IConfigurable` instance + * was in a bad state. + * - `BAD_INDEX`: The requested field was not recognized. + * - `TIMED_OUT`: The query could not be completed in a timely manner. + * - `BLOCKING`: The query must block, but the parameter `mayBlock` in the + * call to `querySupportedValues()` was `false`. + * - `CORRUPTED`: Some unknown error occurred. + */ + Status status; + + /** + * Supported values. This is meaningful only when #status is `OK`. + */ + FieldSupportedValues values; +}; + diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp index 34a96a0ce7..88a9e2612e 100644 --- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp +++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp @@ -470,7 +470,7 @@ void changeStateIdletoExecute(sp<IOmxNode> omxNode, status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet), OMX_StateExecuting); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); - status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT); + status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); ASSERT_EQ(msg.type, Message::Type::EVENT); ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete); diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h index c1863d5469..1575ba252e 100644 --- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h +++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h @@ -41,6 +41,8 @@ /* As component is switching states (loaded<->idle<->execute), dequeueMessage() * expects the events to be received within this duration */ #define DEFAULT_TIMEOUT 100000 +// b/70933963 +#define RELAXED_TIMEOUT 400000 /* Time interval between successive Input/Output enqueues */ #define DEFAULT_TIMEOUT_Q 2000 /* While the component is amidst a process call, asynchronous commands like diff --git a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp index 7750a12fac..4ddc833ef7 100644 --- a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp +++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp @@ -1149,15 +1149,13 @@ TEST_F(ComponentHidlTest, PortEnableDisable_Execute) { ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); // do not enable the port until all the buffers are supplied - status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, - &pBuffer[0], &pBuffer[1]); + status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT, &pBuffer[0], &pBuffer[1]); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); ASSERT_NO_FATAL_FAILURE(allocatePortBuffers( omxNode, &pBuffer[i - portBase], i, portMode[i - portBase])); - status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, - &pBuffer[0], &pBuffer[1]); + status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT, &pBuffer[0], &pBuffer[1]); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); ASSERT_EQ(msg.type, Message::Type::EVENT); ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable); diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal index 0880b2f0d7..89af35a376 100644 --- a/neuralnetworks/1.0/types.hal +++ b/neuralnetworks/1.0/types.hal @@ -55,10 +55,20 @@ enum OperandType : int32_t { */ TENSOR_QUANT8_ASYMM = 5, - /** OEM specific scalar value. */ + /** + * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to + * OEM operation and data types. + * + * OEM specific scalar value. + */ OEM = 10000, - /** A tensor of OEM specific values. */ + /** + * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to + * OEM operation and data types. + * + * A tensor of OEM specific values. + */ TENSOR_OEM_BYTE = 10001, }; @@ -1448,7 +1458,8 @@ enum OperationType : int32_t { TANH = 28, /** - * OEM specific operation. + * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to + * OEM operation and data types. * * This operation is OEM specific. It should only be used for OEM * applications. diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp index db10f6d5a2..2e1385497b 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "GeneratedTestHarness.h" #include "Callbacks.h" #include "ExecutionBurstController.h" #include "TestHarness.h" @@ -120,12 +121,14 @@ static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst( return ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true); } enum class Executor { ASYNC, SYNC, BURST }; +enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; const float kDefaultAtol = 1e-5f; const float kDefaultRtol = 1e-5f; template <typename T_IPreparedModel> void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored, - const std::vector<MixedTypedExample>& examples, bool hasRelaxedFloat32Model, float fpAtol, - float fpRtol, Executor executor, MeasureTiming measure, bool testDynamicOutputShape) { + const std::vector<MixedTypedExample>& examples, + bool hasRelaxedFloat32Model, float fpAtol, float fpRtol, + Executor executor, MeasureTiming measure, OutputType outputType) { const uint32_t INPUT = 0; const uint32_t OUTPUT = 1; @@ -173,8 +176,20 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo // Go through all outputs, initialize RequestArgument descriptors resize_accordingly(golden, test); - for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) { + bool sizeLargerThanOne = true; + for_all(golden, [&outputs_info, &outputSize, &outputType, &sizeLargerThanOne]( + int index, auto, auto s) { if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1); + if (index == 0) { + // On OutputType::INSUFFICIENT, set the output operand with index 0 with + // buffer size one byte less than needed. + if (outputType == OutputType::INSUFFICIENT) { + if (s > 1) + s -= 1; + else + sizeLargerThanOne = false; + } + } RequestArgument arg = { .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)}, .dimensions = {}, @@ -182,6 +197,9 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo outputs_info[index] = arg; outputSize += s; }); + // If output0 does not have size larger than one byte, + // we can not provide an insufficient buffer + if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return; // Compute offset for outputs 1 and so on { size_t offset = 0; @@ -276,15 +294,15 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo } } - if (testDynamicOutputShape && executionStatus != ErrorStatus::NONE) { + if (outputType != OutputType::FULLY_SPECIFIED && + executionStatus == ErrorStatus::GENERAL_FAILURE) { LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " "execute model that it does not support."; std::cout << "[ ] Early termination of test because vendor service cannot " "execute model that it does not support." << std::endl; - return; + GTEST_SKIP(); } - ASSERT_EQ(ErrorStatus::NONE, executionStatus); if (measure == MeasureTiming::NO) { EXPECT_EQ(UINT64_MAX, timing.timeOnDevice); EXPECT_EQ(UINT64_MAX, timing.timeInDriver); @@ -294,9 +312,28 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo } } + switch (outputType) { + case OutputType::FULLY_SPECIFIED: + // If the model output operands are fully specified, outputShapes must be either + // either empty, or have the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_TRUE(outputShapes.size() == 0 || + outputShapes.size() == test.operandDimensions.size()); + break; + case OutputType::UNSPECIFIED: + // If the model output operands are not fully specified, outputShapes must have + // the same number of elements as the number of outputs. + ASSERT_EQ(ErrorStatus::NONE, executionStatus); + ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); + break; + case OutputType::INSUFFICIENT: + ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus); + ASSERT_EQ(outputShapes.size(), test.operandDimensions.size()); + ASSERT_FALSE(outputShapes[0].isSufficient); + return; + } // Go through all outputs, overwrite output dimensions with returned output shapes - if (testDynamicOutputShape) { - ASSERT_NE(outputShapes.size(), 0); + if (outputShapes.size() > 0) { for_each<uint32_t>(test.operandDimensions, [&outputShapes](int idx, std::vector<uint32_t>& dim) { dim = outputShapes[idx].dimensions; @@ -321,10 +358,56 @@ void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bo } template <typename T_IPreparedModel> void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored, - const std::vector<MixedTypedExample>& examples, bool hasRelaxedFloat32Model, - Executor executor, MeasureTiming measure, bool testDynamicOutputShape) { + const std::vector<MixedTypedExample>& examples, + bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure, + OutputType outputType) { EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol, - kDefaultRtol, executor, measure, testDynamicOutputShape); + kDefaultRtol, executor, measure, outputType); +} + +void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel, + std::function<bool(int)> is_ignored, + const std::vector<MixedTypedExample>& examples, + bool hasRelaxedFloat32Model, bool testDynamicOutputShape) { + if (testDynamicOutputShape) { + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT); + } else { + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, + Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED); + } } static void getPreparedModel(sp<PreparedModelCallback> callback, @@ -380,8 +463,8 @@ void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> c float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f; EvaluatePreparedModel(preparedModel, is_ignored, examples, - /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Executor::ASYNC, MeasureTiming::NO, - /*testDynamicOutputShape=*/false); + /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Executor::ASYNC, + MeasureTiming::NO, OutputType::FULLY_SPECIFIED); } void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model, @@ -427,16 +510,12 @@ void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> c ASSERT_NE(nullptr, preparedModel.get()); EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Executor::ASYNC, - MeasureTiming::NO, /*testDynamicOutputShape=*/false); + model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Executor::ASYNC, + MeasureTiming::NO, OutputType::FULLY_SPECIFIED); } -// TODO: Reduce code duplication. -void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model, - std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples, - bool testDynamicOutputShape) { - V1_2::Model model = create_model(); - +void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model, + sp<V1_2::IPreparedModel>* preparedModel) { // see if service can handle model bool fullySupportsModel = false; Return<void> supportedCall = device->getSupportedOperations_1_2( @@ -459,12 +538,11 @@ void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> c // retrieve prepared model preparedModelCallback->wait(); ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - sp<V1_2::IPreparedModel> preparedModel; - getPreparedModel(preparedModelCallback, &preparedModel); + getPreparedModel(preparedModelCallback, preparedModel); // early termination if vendor service cannot fully prepare model if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel.get()); + ASSERT_EQ(nullptr, preparedModel->get()); LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " "prepare model that it does not support."; std::cout << "[ ] Early termination of test because vendor service cannot " @@ -473,26 +551,18 @@ void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> c GTEST_SKIP(); } EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel.get()); + ASSERT_NE(nullptr, preparedModel->get()); +} +// TODO: Reduce code duplication. +void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model, + std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples, + bool testDynamicOutputShape) { + V1_2::Model model = create_model(); + sp<V1_2::IPreparedModel> preparedModel = nullptr; + PrepareModel(device, model, &preparedModel); EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, Executor::ASYNC, MeasureTiming::NO, - testDynamicOutputShape); - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, Executor::SYNC, MeasureTiming::NO, - testDynamicOutputShape); - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, Executor::BURST, MeasureTiming::NO, - testDynamicOutputShape); - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, Executor::ASYNC, MeasureTiming::YES, - testDynamicOutputShape); - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, Executor::SYNC, MeasureTiming::YES, - testDynamicOutputShape); - EvaluatePreparedModel(preparedModel, is_ignored, examples, - model.relaxComputationFloat32toFloat16, Executor::BURST, MeasureTiming::YES, - testDynamicOutputShape); + model.relaxComputationFloat32toFloat16, testDynamicOutputShape); } } // namespace generated_tests diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h new file mode 100644 index 0000000000..c7d23993f4 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h @@ -0,0 +1,57 @@ +/* + * 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 VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H +#define VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H + +#include "TestHarness.h" + +#include <android/hardware/neuralnetworks/1.0/IDevice.h> +#include <android/hardware/neuralnetworks/1.1/IDevice.h> +#include <android/hardware/neuralnetworks/1.2/IDevice.h> + +namespace android { +namespace hardware { +namespace neuralnetworks { + +namespace generated_tests { +using ::test_helper::MixedTypedExample; + +void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model, + sp<V1_2::IPreparedModel>* preparedModel); + +void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel, + std::function<bool(int)> is_ignored, + const std::vector<MixedTypedExample>& examples, + bool hasRelaxedFloat32Model, bool testDynamicOutputShape); + +void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model, + std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples); + +void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model, + std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples); + +void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model, + std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples, + bool testDynamicOutputShape = false); + +} // namespace generated_tests + +} // namespace neuralnetworks +} // namespace hardware +} // namespace android + +#endif // VTS_HAL_NEURALNETWORKS_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp index 55e5861dec..d1c7de322f 100644 --- a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,13 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_0::IDevice>&, std::function<V1_0::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&); -} // namespace generated_tests - namespace V1_0 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 697252fe32..3f0c2561b0 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -21,6 +21,7 @@ cc_test { srcs: [ "GeneratedTestsV1_0.cpp", ], + test_suites: ["general-tests"], } // Tests for V1_1 models. diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp index d98ea04310..4db12769a7 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,13 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_1::IDevice>&, std::function<V1_1::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&); -} // namespace generated_tests - namespace V1_1 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp index 1df3218feb..e67ef8ed98 100644 --- a/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.1/vts/functional/GeneratedTestsV1_0.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,13 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_1::IDevice>&, std::function<V1_1::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&); -} // namespace generated_tests - namespace V1_1 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/IDevice.hal b/neuralnetworks/1.2/IDevice.hal index de249b0e08..b9fa38870e 100644 --- a/neuralnetworks/1.2/IDevice.hal +++ b/neuralnetworks/1.2/IDevice.hal @@ -76,6 +76,21 @@ interface IDevice extends @1.1::IDevice { getType() generates (ErrorStatus status, DeviceType type); /** + * Gets information about extensions supported by the driver implementation. + * + * All extension operations and operands must be fully supported for the + * extension to appear in the list of supported extensions. + * + * @return status Error status of the call, must be: + * - NONE if successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * @return extensions A list of supported extensions. + */ + getSupportedExtensions() + generates (ErrorStatus status, vec<Extension> extensions); + + /** * Gets the supported operations in a model. * * getSupportedOperations indicates which operations of a model are fully diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index 0abe56dea6..2e48ba016f 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -47,7 +47,7 @@ enum OperandType : @1.0::OperandType { * used to convert the 16 bit number to a real value in the following way: * realValue = integerValue * scale. * - * scale is a 32 bit floating point with value greater then zero. + * scale is a 32 bit floating point with value greater than zero. */ TENSOR_QUANT16_SYMM = 7, /** A tensor of IEEE 754 16 bit floating point values. */ @@ -73,10 +73,11 @@ enum OperandType : @1.0::OperandType { * These fields are located inside Operand's extraParams union, inside the * SymmPerChannelQuantParams struct. * - * An Operand of this type must use 'channelQuant' field of its extraParams - * union. + * An Operand of this type must use the 'channelQuant' variant of its + * extraParams field. * - * The channel dimension of this tensor must not be unknown (dimensions[channelDim] != 0). + * The channel dimension of this tensor must be known, i.e. + * dimensions[channelDim] must be non-zero. * * The formula for real values: * realValue[..., C, ...] = @@ -96,11 +97,21 @@ enum OperandType : @1.0::OperandType { * real_value = (integer_value - zeroPoint) * scale. */ TENSOR_QUANT16_ASYMM = 12, + /** + * A tensor of 8 bit signed integers that represent real numbers. + * + * Attached to this tensor is a number representing real value scale that is + * used to convert the 8 bit number to a real value in the following way: + * realValue = integerValue * scale. + * + * scale is a 32 bit floating point with value greater than zero. + */ + TENSOR_QUANT8_SYMM = 13, /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF - * OperandTypeRange::OPERAND_FUNDAMENTAL_MAX. + * OperandTypeRange::FUNDAMENTAL_MAX. */ /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF - * OperandTypeRange::OPERAND_OEM_MAX. + * OperandTypeRange::OEM_MAX. */ }; @@ -108,10 +119,12 @@ enum OperandType : @1.0::OperandType { * The range of operand values in the OperandType enum. */ enum OperandTypeRange : uint32_t { - OPERAND_FUNDAMENTAL_MIN = 0, - OPERAND_FUNDAMENTAL_MAX = 12, - OPERAND_OEM_MIN = 10000, - OPERAND_OEM_MAX = 10001, + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, + FUNDAMENTAL_MAX = 13, + OEM_MIN = 10000, + OEM_MAX = 10001, + BASE_MAX = 0xFFFF, }; /** @@ -178,10 +191,10 @@ enum OperationType : @1.1::OperationType { UNIDIRECTIONAL_SEQUENCE_LSTM = 92, UNIDIRECTIONAL_SEQUENCE_RNN = 93, /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF - * OperationTypeRange::OPERATION_FUNDAMENTAL_MAX. + * OperationTypeRange::FUNDAMENTAL_MAX. */ /* ADDING A NEW OEM OPERATION REQUIRES UPDATING THE VALUE OF - * OperationTypeRange::OPERATION_OEM_MAX. + * OperationTypeRange::OEM_MAX. */ }; @@ -189,10 +202,12 @@ enum OperationType : @1.1::OperationType { * The range of values in the OperationType enum. */ enum OperationTypeRange : uint32_t { - OPERATION_FUNDAMENTAL_MIN = 0, - OPERATION_FUNDAMENTAL_MAX = 93, - OPERATION_OEM_MIN = 10000, - OPERATION_OEM_MAX = 10000, + BASE_MIN = 0, + FUNDAMENTAL_MIN = 0, + FUNDAMENTAL_MAX = 93, + OEM_MIN = 10000, + OEM_MAX = 10000, + BASE_MAX = 0xFFFF, }; /** @@ -221,6 +236,10 @@ enum DeviceType : int32_t { struct Operation { /** * The operation type. + * + * Besides the values listed in {@link OperationType}, any value above + * {@link OperationTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. */ OperationType type; @@ -247,21 +266,16 @@ struct SymmPerChannelQuantParams { uint32_t channelDim; }; -// TODO(slavash): Operand Extension support -// /** -// * Parameters for an unknown (as of 1.2) operand extension. This is -// * a vendor-specific extension or a platform extension (backport of -// * functionality from newer NNAPI interface). -// */ -// struct OperandParamsUnknown { -// }; - /** * Describes one operand of the model's graph. */ struct Operand { /** - * Data type of the operand. + * The data type. + * + * Besides the values listed in {@link OperandType}, any value above + * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted + * as an extension type according to {@link Model::extensionNameToPrefix}. */ OperandType type; @@ -351,25 +365,28 @@ struct Operand { DataLocation location; /** - * Union of extra parameters, used by some types of Operands that need additional - * information for the complete definition of an Operand. + * Additional parameters specific to a particular operand type. */ safe_union ExtraParams { /** - * Placeholder for operand with no extra parameters. + * No additional parameters. */ Monostate none; /** - * Used with TENSOR_QUANT8_SYMM_PER_CHANNEL operand type. + * Symmetric per-channel quantization parameters. + * + * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL. */ SymmPerChannelQuantParams channelQuant; - // TODO(slavash): Operand Extension support - // /** - // * Used with Extension operand type. - // */ - // OperandParamsUnknown unknown; + /** + * Extension operand parameters. + * + * The framework treats this as an opaque data blob. + * The format is up to individual extensions. + */ + vec<uint8_t> extension; } extraParams; }; @@ -432,6 +449,63 @@ struct Model { * range and precision of the IEEE 754 32-bit floating-point format. */ bool relaxComputationFloat32toFloat16; + + /** + * The mapping between extension names and prefixes of operand and + * operation type values. + * + * An operand or operation whose numeric type value is above + * {@link OperandTypeRange::BASE_MAX} or + * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted + * as an extension operand. The low + * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value + * correspond to the value within the extension and the high + * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode + * the "prefix", which maps uniquely to the extension name. + * + * For example, if a model contains an operation whose value is + * 0xAAAABBBB and extensionNameToPrefix contains an entry with + * prefix=0xAAAA and name="vendor.test.test_extension", then + * the operation should be interpreted as the operation 0xBBBB + * of the extension named vendor.test.test_extension. + * + * This is a one-to-one correspondence. That is, there must be at most one + * prefix corresponding to each extension name and at most one extension + * name corresponding to each prefix. + */ + vec<ExtensionNameAndPrefix> extensionNameToPrefix; + + /** + * A correspondence between an extension name and a prefix of operand and + * operation type values. + */ + struct ExtensionNameAndPrefix { + /** + * The extension name. + * + * See {@link Extension::name}. + */ + string name; + + /** + * The unique extension identifier within the model. + * + * See {@link Model::extensionNameToPrefix}. + */ + uint16_t prefix; + }; + + /** + * Numeric values of extension operand and operation types have the + * following structure: + * - 16 high bits represent the "prefix", which corresponds uniquely to the + * extension name. + * - 16 low bits represent the type ID within the extension. + */ + enum ExtensionTypeEncoding : uint8_t { + HIGH_BITS_PREFIX = 16, + LOW_BITS_TYPE = 16, + }; }; /** @@ -685,3 +759,43 @@ safe_union FmqResultDatum { */ Timing executionTiming; }; + +/** + * Information about an extension. + */ +struct Extension { + /** + * The extension name. + * + * The name must start with the reverse domain name of the vendor. + * Example: com.google.test_extension + */ + string name; + + /** + * Information about an extension operand type. + */ + struct OperandTypeInformation { + /** + * The extension operand type. + */ + uint16_t type; + + /** + * Indicates whether the extension operand type represents a tensor or + * a scalar. + */ + bool isTensor; + + /** + * The byte size of the operand (if scalar) or of a single element (if + * tensor). + */ + uint32_t byteSize; + }; + + /** + * Information about operand types defined by the extension. + */ + vec<OperandTypeInformation> operandTypes; +}; diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 0cb9e16fcf..510a0d5b3c 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -46,6 +46,7 @@ cc_test { defaults: ["VtsHalNeuralNetworksTargetTestDefaults"], srcs: [ "BasicTests.cpp", + "CompilationCachingTests.cpp", "GeneratedTests.cpp", ], cflags: [ diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp index 8c3ad15e2a..2b88edd0f6 100644 --- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp @@ -55,6 +55,29 @@ TEST_F(NeuralnetworksHidlTest, GetDeviceTypeTest) { }); EXPECT_TRUE(ret.isOk()); } + +// device supported extensions test +TEST_F(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { + Return<void> ret = device->getSupportedExtensions( + [](ErrorStatus status, const hidl_vec<Extension>& extensions) { + EXPECT_EQ(ErrorStatus::NONE, status); + for (auto& extension : extensions) { + std::string extensionName = extension.name; + EXPECT_FALSE(extensionName.empty()); + EXPECT_NE(extensionName.find("."), std::string::npos) + << "Extension name must start with the reverse domain name of the " + "vendor"; + } + }); + EXPECT_TRUE(ret.isOk()); +} + +// isCachingSupported test +TEST_F(NeuralnetworksHidlTest, IsCachingSupported) { + Return<void> ret = device->isCachingSupported( + [](ErrorStatus status, bool) { EXPECT_EQ(ErrorStatus::NONE, status); }); + EXPECT_TRUE(ret.isOk()); +} } // namespace functional } // namespace vts } // namespace V1_2 diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp new file mode 100644 index 0000000000..454aa1f921 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp @@ -0,0 +1,652 @@ +/* + * 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. + */ + +#define LOG_TAG "neuralnetworks_hidl_hal_test" + +#include "VtsHalNeuralnetworks.h" + +#include "Callbacks.h" +#include "GeneratedTestHarness.h" +#include "TestHarness.h" +#include "Utils.h" + +#include <android-base/logging.h> +#include <android/hidl/memory/1.0/IMemory.h> +#include <hidlmemory/mapping.h> +#include <cstdio> +#include <cstdlib> +#include <random> + +#include <gtest/gtest.h> + +namespace android { +namespace hardware { +namespace neuralnetworks { +namespace V1_2 { +namespace vts { +namespace functional { + +using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; +using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; +using ::android::nn::allocateSharedMemory; +using ::test_helper::MixedTypedExample; + +namespace { + +// In frameworks/ml/nn/runtime/tests/generated/, creates a hidl model of mobilenet. +#include "examples/mobilenet_224_gender_basic_fixed.example.cpp" +#include "vts_models/mobilenet_224_gender_basic_fixed.model.cpp" + +// Prevent the compiler from complaining about an otherwise unused function. +[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape; +[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape; + +enum class AccessMode { READ_ONLY, WRITE_ONLY }; + +void createCacheHandle(const std::vector<std::string>& files, AccessMode mode, + hidl_handle* handle) { + std::vector<int> fds; + for (const auto& file : files) { + int fd; + if (mode == AccessMode::READ_ONLY) { + fd = open(file.c_str(), O_RDONLY); + } else if (mode == AccessMode::WRITE_ONLY) { + fd = open(file.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); + } else { + FAIL(); + } + ASSERT_GE(fd, 0); + fds.push_back(fd); + } + native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0); + ASSERT_NE(cacheNativeHandle, nullptr); + for (uint32_t i = 0; i < fds.size(); i++) { + cacheNativeHandle->data[i] = fds[i]; + } + handle->setTo(cacheNativeHandle, /*shouldOwn=*/true); +} + +} // namespace + +// Tag for the compilation caching tests. +class CompilationCachingTest : public NeuralnetworksHidlTest { + protected: + void SetUp() override { + NeuralnetworksHidlTest::SetUp(); + + // Create cache directory. + char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX"; + char* cacheDir = mkdtemp(cacheDirTemp); + ASSERT_NE(cacheDir, nullptr); + mCache1 = cacheDir + mCache1; + mCache2 = cacheDir + mCache2; + mCache3 = cacheDir + mCache3; + + // Check if caching is supported. + bool isCachingSupported; + Return<void> ret = device->isCachingSupported( + [&isCachingSupported](ErrorStatus status, bool supported) { + EXPECT_EQ(ErrorStatus::NONE, status); + isCachingSupported = supported; + }); + EXPECT_TRUE(ret.isOk()); + if (isCachingSupported) { + mIsCachingSupported = true; + } else { + LOG(INFO) << "NN VTS: Early termination of test because vendor service does not " + "support compilation caching."; + std::cout << "[ ] Early termination of test because vendor service does not " + "support compilation caching." + << std::endl; + mIsCachingSupported = false; + } + + // Create empty cache files. + hidl_handle handle; + createCacheHandle({mCache1, mCache2, mCache3}, AccessMode::WRITE_ONLY, &handle); + } + + void saveModelToCache(sp<IPreparedModel> preparedModel, const hidl_handle& cache1, + const hidl_handle& cache2, ErrorStatus* status) { + // Save IPreparedModel to cache. + hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken); + Return<ErrorStatus> saveToCacheStatus = + preparedModel->saveToCache(cache1, cache2, cacheToken); + ASSERT_TRUE(saveToCacheStatus.isOk()); + *status = static_cast<ErrorStatus>(saveToCacheStatus); + } + + bool checkEarlyTermination(ErrorStatus status) { + if (status == ErrorStatus::GENERAL_FAILURE) { + LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot " + "save the prepared model that it does not support."; + std::cout << "[ ] Early termination of test because vendor service cannot " + "save the prepared model that it does not support." + << std::endl; + return true; + } + return false; + } + + void prepareModelFromCache(const hidl_handle& cache1, const hidl_handle& cache2, + sp<IPreparedModel>* preparedModel, ErrorStatus* status) { + // Launch prepare model from cache. + sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken); + Return<ErrorStatus> prepareLaunchStatus = + device->prepareModelFromCache(cache1, cache2, cacheToken, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) { + *preparedModel = nullptr; + *status = static_cast<ErrorStatus>(prepareLaunchStatus); + return; + } + + // Retrieve prepared model. + preparedModelCallback->wait(); + *status = preparedModelCallback->getStatus(); + *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel()) + .withDefault(nullptr); + } + + std::string mCache1 = "/cache1"; + std::string mCache2 = "/cache2"; + std::string mCache3 = "/cache3"; + uint8_t mToken[static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {}; + bool mIsCachingSupported; +}; + +TEST_F(CompilationCachingTest, CacheSavingAndRetrieval) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (!mIsCachingSupported) { + EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } else { + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + } + + // Retrieve preparedModel from cache. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + if (!mIsCachingSupported) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + return; + } else { + ASSERT_EQ(status, ErrorStatus::NONE); + ASSERT_NE(preparedModel, nullptr); + } + } + + // Execute and verify results. + generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(), + testModel.relaxComputationFloat32toFloat16, + /*testDynamicOutputShape=*/false); +} + +TEST_F(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (!mIsCachingSupported) { + EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } else { + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + } + + // Retrieve preparedModel from cache. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + uint8_t dummyByte = 0; + // Advance offset by one byte. + ASSERT_GE(read(cache1.getNativeHandle()->data[0], &dummyByte, 1), 0); + ASSERT_GE(read(cache2.getNativeHandle()->data[0], &dummyByte, 1), 0); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + if (!mIsCachingSupported) { + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + return; + } else { + ASSERT_EQ(status, ErrorStatus::NONE); + ASSERT_NE(preparedModel, nullptr); + } + } + + // Execute and verify results. + generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(), + testModel.relaxComputationFloat32toFloat16, + /*testDynamicOutputShape=*/false); +} + +TEST_F(CompilationCachingTest, SaveToCacheInvalidNumFd) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // cache1 with invalid NumFd. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1, mCache3}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + } + + // cache2 with invalid NumFd. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2, mCache3}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + } + } +} + +TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::NONE); + } + } + + // cache1 with invalid NumFd. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1, mCache3}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + ASSERT_EQ(preparedModel, nullptr); + } + } + + // cache2 with invalid NumFd. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2, mCache3}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT); + ASSERT_EQ(preparedModel, nullptr); + } + } +} + +TEST_F(CompilationCachingTest, SaveToCacheInvalidAccessMode) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // cache1 with invalid access mode. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + + // cache2 with invalid access mode. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } +} + +TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (status != ErrorStatus::GENERAL_FAILURE) { + ASSERT_EQ(status, ErrorStatus::NONE); + } + } + + // cache1 with invalid access mode. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } + + // cache2 with invalid access mode. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_F(CompilationCachingTest, SaveToCacheInvalidOffset) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // cache1 with invalid file descriptor offset. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + uint8_t dummyByte = 0; + // Advance offset by one byte. + ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + + // cache2 with invalid file descriptor offset. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + uint8_t dummyByte = 0; + // Advance offset by one byte. + ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } +} + +TEST_F(CompilationCachingTest, SaveToCacheInvalidFileSize) { + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // cache1 with invalid file size. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + uint8_t dummyByte = 0; + // Write one byte and seek back to the beginning. + ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1); + ASSERT_EQ(lseek(cache1.getNativeHandle()->data[0], 0, SEEK_SET), 0); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } + + // cache2 with invalid file size. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + uint8_t dummyByte = 0; + // Write one byte and seek back to the beginning. + ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1); + ASSERT_EQ(lseek(cache2.getNativeHandle()->data[0], 0, SEEK_SET), 0); + saveModelToCache(preparedModel, cache1, cache2, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + } +} + +class CompilationCachingSecurityTest : public CompilationCachingTest, + public ::testing::WithParamInterface<uint32_t> { + protected: + void SetUp() { + CompilationCachingTest::SetUp(); + generator.seed(kSeed); + } + + // Get a random integer within a closed range [lower, upper]. + template <typename T> + T getRandomInt(T lower, T upper) { + std::uniform_int_distribution<T> dis(lower, upper); + return dis(generator); + } + + const uint32_t kSeed = GetParam(); + std::mt19937 generator; +}; + +TEST_P(CompilationCachingSecurityTest, CorruptedSecuritySensitiveCache) { + if (!mIsCachingSupported) return; + + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + + // Randomly flip one single bit of the cache entry. + FILE* pFile = fopen(mCache1.c_str(), "r+"); + ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0); + long int fileSize = ftell(pFile); + ASSERT_GT(fileSize, 0); + ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0); + int readByte = fgetc(pFile); + ASSERT_NE(readByte, EOF); + ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0); + ASSERT_NE(fputc(static_cast<uint8_t>(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF); + fclose(pFile); + + // Retrieve preparedModel from cache, expect failure. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongLengthSecuritySensitiveCache) { + if (!mIsCachingSupported) return; + + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + + // Randomly append bytes to the cache entry. + FILE* pFile = fopen(mCache1.c_str(), "a"); + uint32_t appendLength = getRandomInt(1, 256); + for (uint32_t i = 0; i < appendLength; i++) { + ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF); + } + fclose(pFile); + + // Retrieve preparedModel from cache, expect failure. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +TEST_P(CompilationCachingSecurityTest, WrongToken) { + if (!mIsCachingSupported) return; + + // Create test HIDL model and compile. + Model testModel = createTestModel(); + sp<IPreparedModel> preparedModel = nullptr; + generated_tests::PrepareModel(device, testModel, &preparedModel); + // Terminate early if the driver cannot prepare the model. + if (preparedModel == nullptr) return; + + // Save the compilation to cache. + { + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2); + saveModelToCache(preparedModel, cache1, cache2, &status); + if (checkEarlyTermination(status)) return; + ASSERT_EQ(status, ErrorStatus::NONE); + } + + // Randomly flip one single bit in mToken. + uint32_t ind = getRandomInt(0u, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1); + mToken[ind] ^= (1U << getRandomInt(0, 7)); + + // Retrieve the preparedModel from cache, expect failure. + { + preparedModel = nullptr; + ErrorStatus status; + hidl_handle cache1, cache2; + createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1); + createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2); + prepareModelFromCache(cache1, cache2, &preparedModel, &status); + ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE); + ASSERT_EQ(preparedModel, nullptr); + } +} + +INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, + ::testing::Range(0U, 10U)); + +} // namespace functional +} // namespace vts +} // namespace V1_2 +} // namespace neuralnetworks +} // namespace hardware +} // namespace android diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp index 4bc891f3d1..2c3287ab35 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,14 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&, - bool testDynamicOutputShape = false); -} // namespace generated_tests - namespace V1_2 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp index 956926aaff..990cab9161 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_0.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,14 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&, - bool testDynamicOutputShape = false); -} // namespace generated_tests - namespace V1_2 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp index 425690f321..fa6d54d295 100644 --- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp +++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_1.cpp @@ -19,6 +19,7 @@ #include "VtsHalNeuralnetworks.h" #include "Callbacks.h" +#include "GeneratedTestHarness.h" #include "TestHarness.h" #include "Utils.h" @@ -29,14 +30,6 @@ namespace android { namespace hardware { namespace neuralnetworks { - -namespace generated_tests { -using ::test_helper::MixedTypedExample; -extern void Execute(const sp<V1_2::IDevice>&, std::function<V1_2::Model(void)>, - std::function<bool(int)>, const std::vector<MixedTypedExample>&, - bool testDynamicOutputShape = false); -} // namespace generated_tests - namespace V1_2 { namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index bee255613f..a0f11ebbaf 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -128,10 +128,10 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const uint32_t invalidOperandTypes[] = { - static_cast<uint32_t>(OperandTypeRange::OPERAND_FUNDAMENTAL_MIN) - 1, - static_cast<uint32_t>(OperandTypeRange::OPERAND_FUNDAMENTAL_MAX) + 1, - static_cast<uint32_t>(OperandTypeRange::OPERAND_OEM_MIN) - 1, - static_cast<uint32_t>(OperandTypeRange::OPERAND_OEM_MAX) + 1, + static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MIN) - 1, + static_cast<uint32_t>(OperandTypeRange::FUNDAMENTAL_MAX) + 1, + static_cast<uint32_t>(OperandTypeRange::OEM_MIN) - 1, + static_cast<uint32_t>(OperandTypeRange::OEM_MAX) + 1, }; static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) { @@ -161,6 +161,8 @@ static uint32_t getInvalidRank(OperandType type) { case OperandType::TENSOR_FLOAT32: case OperandType::TENSOR_INT32: case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT8_SYMM: + case OperandType::TENSOR_QUANT16_ASYMM: case OperandType::TENSOR_QUANT16_SYMM: case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL: return 0; @@ -198,7 +200,9 @@ static float getInvalidScale(OperandType type) { return 1.0f; case OperandType::TENSOR_INT32: return -1.0f; + case OperandType::TENSOR_QUANT8_SYMM: case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT16_ASYMM: case OperandType::TENSOR_QUANT16_SYMM: return 0.0f; default: @@ -233,6 +237,10 @@ static std::vector<int32_t> getInvalidZeroPoints(OperandType type) { return {1}; case OperandType::TENSOR_QUANT8_ASYMM: return {-1, 256}; + case OperandType::TENSOR_QUANT8_SYMM: + return {-129, -1, 1, 128}; + case OperandType::TENSOR_QUANT16_ASYMM: + return {-1, 65536}; case OperandType::TENSOR_QUANT16_SYMM: return {-32769, -1, 1, 32768}; default: @@ -288,6 +296,8 @@ static void mutateOperand(Operand* operand, OperandType type) { newOperand.zeroPoint = 0; break; case OperandType::TENSOR_QUANT8_ASYMM: + case OperandType::TENSOR_QUANT8_SYMM: + case OperandType::TENSOR_QUANT16_ASYMM: case OperandType::TENSOR_QUANT16_SYMM: newOperand.dimensions = operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1}); @@ -387,10 +397,10 @@ static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Mode ///////////////////////// VALIDATE MODEL OPERATION TYPE ///////////////////////// static const uint32_t invalidOperationTypes[] = { - static_cast<uint32_t>(OperationTypeRange::OPERATION_FUNDAMENTAL_MIN) - 1, - static_cast<uint32_t>(OperationTypeRange::OPERATION_FUNDAMENTAL_MAX) + 1, - static_cast<uint32_t>(OperationTypeRange::OPERATION_OEM_MIN) - 1, - static_cast<uint32_t>(OperationTypeRange::OPERATION_OEM_MAX) + 1, + static_cast<uint32_t>(OperationTypeRange::FUNDAMENTAL_MIN) - 1, + static_cast<uint32_t>(OperationTypeRange::FUNDAMENTAL_MAX) + 1, + static_cast<uint32_t>(OperationTypeRange::OEM_MIN) - 1, + static_cast<uint32_t>(OperationTypeRange::OEM_MAX) + 1, }; static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) { diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp index a8e939cfd0..a1639d8bb9 100644 --- a/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp +++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp @@ -48,8 +48,8 @@ TEST_F(RadioConfigHidlTest, setModemsConfig_invalidArgument) { ALOGI("setModemsConfig, rspInfo.error = %s\n", toString(radioConfigRsp->rspInfo.error).c_str()); ASSERT_TRUE( - CheckAnyOfErrors(radioConfigRsp->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + CheckAnyOfErrors(radioConfigRsp->rspInfo.error, + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); } /* diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp index 6c1b3821d6..a8c257d8fc 100644 --- a/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp +++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp @@ -18,13 +18,13 @@ void RadioConfigHidlTest::SetUp() { radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>( - RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>( - hidl_string(RADIO_SERVICE_NAME))); + RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>( + hidl_string(RADIO_SERVICE_NAME))); if (radioConfig == NULL) { sleep(60); radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>( - RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>( - hidl_string(RADIO_SERVICE_NAME))); + RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>( + hidl_string(RADIO_SERVICE_NAME))); } ASSERT_NE(nullptr, radioConfig.get()); diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h index 592555f8d2..1747ce8f24 100644 --- a/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h +++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h @@ -56,8 +56,8 @@ class RadioConfigResponse : public IRadioConfigResponse { virtual ~RadioConfigResponse() = default; Return<void> getSimSlotsStatusResponse( - const RadioResponseInfo& info, - const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus); + const RadioResponseInfo& info, + const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus); Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info); diff --git a/radio/config/1.1/vts/functional/radio_config_response.cpp b/radio/config/1.1/vts/functional/radio_config_response.cpp index 6e41aebbc0..8c9e4d75e6 100644 --- a/radio/config/1.1/vts/functional/radio_config_response.cpp +++ b/radio/config/1.1/vts/functional/radio_config_response.cpp @@ -21,8 +21,8 @@ RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {} Return<void> RadioConfigResponse::getSimSlotsStatusResponse( - const RadioResponseInfo& /* info */, - const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) { + const RadioResponseInfo& /* info */, + const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) { return Void(); } @@ -31,12 +31,12 @@ Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponse } Return<void> RadioConfigResponse::getPhoneCapabilityResponse( - const RadioResponseInfo& /* info */, const PhoneCapability& /* phoneCapability */) { + const RadioResponseInfo& /* info */, const PhoneCapability& /* phoneCapability */) { return Void(); } Return<void> RadioConfigResponse::setPreferredDataModemResponse( - const RadioResponseInfo& /* info */) { + const RadioResponseInfo& /* info */) { return Void(); } diff --git a/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS index 6a38a1ff14..2031d848cf 100644 --- a/sensors/1.0/default/OWNERS +++ b/sensors/1.0/default/OWNERS @@ -1,2 +1,2 @@ -ashutoshj@google.com -pengxu@google.com +bduddie@google.com +bstack@google.com diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp index c58c7fc697..d4c5f321de 100644 --- a/sensors/1.0/vts/functional/Android.bp +++ b/sensors/1.0/vts/functional/Android.bp @@ -18,13 +18,14 @@ cc_test { name: "VtsHalSensorsV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "GrallocWrapper.cpp", + "SensorsHidlEnvironmentV1_0.cpp", "VtsHalSensorsV1_0TargetTest.cpp" ], static_libs: [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.mapper@2.0", "android.hardware.sensors@1.0", + "VtsHalSensorsTargetTestUtils", ], test_suites: ["general-tests"], } diff --git a/sensors/1.0/vts/functional/GrallocWrapper.cpp b/sensors/1.0/vts/functional/GrallocWrapper.cpp deleted file mode 100644 index e422d62c72..0000000000 --- a/sensors/1.0/vts/functional/GrallocWrapper.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "GrallocWrapper" - -#include "GrallocWrapper.h" - -#include <utils/Log.h> - -namespace android { - -GrallocWrapper::GrallocWrapper() { init(); } - -void GrallocWrapper::init() { - mAllocator = allocator2::IAllocator::getService(); - if (mAllocator == nullptr) { - ALOGE("Failed to get allocator service"); - } - - mMapper = mapper2::IMapper::getService(); - if (mMapper == nullptr) { - ALOGE("Failed to get mapper service"); - } - if (mMapper->isRemote()) { - ALOGE("Mapper is not in passthrough mode"); - } -} - -GrallocWrapper::~GrallocWrapper() { - for (auto bufferHandle : mClonedBuffers) { - auto buffer = const_cast<native_handle_t*>(bufferHandle); - native_handle_close(buffer); - native_handle_delete(buffer); - } - mClonedBuffers.clear(); - - for (auto bufferHandle : mImportedBuffers) { - auto buffer = const_cast<native_handle_t*>(bufferHandle); - if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) { - ALOGE("Failed to free buffer %p", buffer); - } - } - mImportedBuffers.clear(); -} - -sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const { - return mAllocator; -} - -std::string GrallocWrapper::dumpDebugInfo() { - std::string debugInfo; - mAllocator->dumpDebugInfo( - [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); - - return debugInfo; -} - -const native_handle_t* GrallocWrapper::cloneBuffer( - const hardware::hidl_handle& rawHandle) { - const native_handle_t* bufferHandle = - native_handle_clone(rawHandle.getNativeHandle()); - - if (bufferHandle) { - mClonedBuffers.insert(bufferHandle); - } - return bufferHandle; -} - -std::vector<const native_handle_t*> GrallocWrapper::allocate( - const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import, - uint32_t* outStride) { - std::vector<const native_handle_t*> bufferHandles; - bufferHandles.reserve(count); - mAllocator->allocate( - descriptor, count, - [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) { - if (mapper2::Error::NONE != tmpError) { - ALOGE("Failed to allocate buffers"); - } - if (count != tmpBuffers.size()) { - ALOGE("Invalid buffer array"); - } - - for (uint32_t i = 0; i < count; i++) { - if (import) { - bufferHandles.push_back(importBuffer(tmpBuffers[i])); - } else { - bufferHandles.push_back(cloneBuffer(tmpBuffers[i])); - } - } - - if (outStride) { - *outStride = tmpStride; - } - }); - - return bufferHandles; -} - -const native_handle_t* GrallocWrapper::allocate( - const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import, - uint32_t* outStride) { - mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo); - ALOGE("QQ"); - auto buffers = allocate(descriptor, 1, import, outStride); - return buffers[0]; -} - -sp<mapper2::IMapper> GrallocWrapper::getMapper() const { return mMapper; } - -mapper2::BufferDescriptor GrallocWrapper::createDescriptor( - const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) { - mapper2::BufferDescriptor descriptor; - mMapper->createDescriptor( - descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) { - if (tmpError != mapper2::Error::NONE) { - ALOGE("Failed to create descriptor"); - } - descriptor = tmpDescriptor; - }); - - return descriptor; -} - -const native_handle_t* GrallocWrapper::importBuffer( - const hardware::hidl_handle& rawHandle) { - const native_handle_t* bufferHandle = nullptr; - mMapper->importBuffer( - rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) { - if (tmpError != mapper2::Error::NONE) { - ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle()); - } - bufferHandle = static_cast<const native_handle_t*>(tmpBuffer); - }); - - if (bufferHandle) { - mImportedBuffers.insert(bufferHandle); - } - - return bufferHandle; -} - -void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) { - auto buffer = const_cast<native_handle_t*>(bufferHandle); - - if (mImportedBuffers.erase(bufferHandle)) { - mapper2::Error error = mMapper->freeBuffer(buffer); - if (error != mapper2::Error::NONE) { - ALOGE("Failed to free %p", buffer); - } - } else { - mClonedBuffers.erase(bufferHandle); - native_handle_close(buffer); - native_handle_delete(buffer); - } -} - -void* GrallocWrapper::lock(const native_handle_t* bufferHandle, - uint64_t cpuUsage, - const mapper2::IMapper::Rect& accessRegion, - int acquireFence) { - auto buffer = const_cast<native_handle_t*>(bufferHandle); - - NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); - hardware::hidl_handle acquireFenceHandle; - if (acquireFence >= 0) { - auto h = native_handle_init(acquireFenceStorage, 1, 0); - h->data[0] = acquireFence; - acquireFenceHandle = h; - } - - void* data = nullptr; - mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, - [&](const auto& tmpError, const auto& tmpData) { - if (tmpError != mapper2::Error::NONE) { - ALOGE("Failed to lock buffer %p", buffer); - } - data = tmpData; - }); - - if (acquireFence >= 0) { - close(acquireFence); - } - - return data; -} - -int GrallocWrapper::unlock(const native_handle_t* bufferHandle) { - auto buffer = const_cast<native_handle_t*>(bufferHandle); - - int releaseFence = -1; - mMapper->unlock(buffer, [&](const auto& tmpError, - const auto& tmpReleaseFence) { - if (tmpError != mapper2::Error::NONE) { - ALOGE("Failed to unlock buffer %p", buffer); - } - - auto fenceHandle = tmpReleaseFence.getNativeHandle(); - if (fenceHandle) { - if (fenceHandle->numInts != 0) { - ALOGE("Invalid fence handle %p", fenceHandle); - } - if (fenceHandle->numFds == 1) { - releaseFence = dup(fenceHandle->data[0]); - if (releaseFence < 0){ - ALOGE("Failed to dup fence fd"); - } - } else { - if (fenceHandle->numFds != 0) { - ALOGE("Invalid fence handle %p", fenceHandle); - } - } - } - }); - - return releaseFence; -} - -} // namespace android diff --git a/sensors/1.0/vts/functional/GrallocWrapper.h b/sensors/1.0/vts/functional/GrallocWrapper.h deleted file mode 100644 index e506fe1d86..0000000000 --- a/sensors/1.0/vts/functional/GrallocWrapper.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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 GRALLO_WRAPPER_H_ -#define GRALLO_WRAPPER_H_ - -#include <unordered_set> - -#include <android/hardware/graphics/allocator/2.0/IAllocator.h> -#include <android/hardware/graphics/mapper/2.0/IMapper.h> - -namespace allocator2 = ::android::hardware::graphics::allocator::V2_0; -namespace mapper2 = ::android::hardware::graphics::mapper::V2_0; - -namespace android { - -// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/ -class GrallocWrapper { - public: - GrallocWrapper(); - ~GrallocWrapper(); - - sp<allocator2::IAllocator> getAllocator() const; - sp<mapper2::IMapper> getMapper() const; - - std::string dumpDebugInfo(); - - // When import is false, this simply calls IAllocator::allocate. When import - // is true, the returned buffers are also imported into the mapper. - // - // Either case, the returned buffers must be freed with freeBuffer. - std::vector<const native_handle_t*> allocate( - const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import = true, - uint32_t* outStride = nullptr); - const native_handle_t* allocate( - const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import = true, - uint32_t* outStride = nullptr); - - mapper2::BufferDescriptor createDescriptor( - const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo); - - const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle); - void freeBuffer(const native_handle_t* bufferHandle); - - // We use fd instead of hardware::hidl_handle in these functions to pass fences - // in and out of the mapper. The ownership of the fd is always transferred - // with each of these functions. - void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, - const mapper2::IMapper::Rect& accessRegion, int acquireFence); - - int unlock(const native_handle_t* bufferHandle); - - private: - void init(); - const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle); - - sp<allocator2::IAllocator> mAllocator; - sp<mapper2::IMapper> mMapper; - - // Keep track of all cloned and imported handles. When a test fails with - // ASSERT_*, the destructor will free the handles for the test. - std::unordered_set<const native_handle_t*> mClonedBuffers; - std::unordered_set<const native_handle_t*> mImportedBuffers; -}; - -} // namespace android -#endif // GRALLO_WRAPPER_H_ diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS index 8715e5d787..759d87b482 100644 --- a/sensors/1.0/vts/functional/OWNERS +++ b/sensors/1.0/vts/functional/OWNERS @@ -1,6 +1,6 @@ # Sensors team -ashutoshj@google.com -pengxu@google.com +bduddie@google.com +bstack@google.com # VTS team trong@google.com diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp new file mode 100644 index 0000000000..00207b1ee9 --- /dev/null +++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp @@ -0,0 +1,121 @@ +/* + * 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 "SensorsHidlEnvironmentV1_0.h" + +#include <log/log.h> + +#include <vector> + +using ::android::hardware::hidl_vec; +using ::android::hardware::sensors::V1_0::ISensors; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SensorInfo; + +bool SensorsHidlEnvironmentV1_0::resetHal() { + // wait upto 100ms * 10 = 1s for hidl service. + constexpr auto RETRY_DELAY = std::chrono::milliseconds(100); + + std::string step; + bool succeed = false; + for (size_t retry = 10; retry > 0; --retry) { + // this do ... while is for easy error handling + do { + step = "getService()"; + sensors = ISensors::getService( + SensorsHidlEnvironmentV1_0::Instance()->getServiceName<ISensors>()); + if (sensors == nullptr) { + break; + } + + step = "poll() check"; + // Poke ISensor service. If it has lingering connection from previous generation of + // system server, it will kill itself. There is no intention to handle the poll result, + // which will be done since the size is 0. + if (!sensors->poll(0, [](auto, const auto&, const auto&) {}).isOk()) { + break; + } + + step = "getSensorList"; + std::vector<SensorInfo> sensorList; + if (!sensors + ->getSensorsList([&](const hidl_vec<SensorInfo>& list) { + sensorList.reserve(list.size()); + for (size_t i = 0; i < list.size(); ++i) { + sensorList.push_back(list[i]); + } + }) + .isOk()) { + break; + } + + // stop each sensor individually + step = "stop each sensor"; + bool ok = true; + for (const auto& i : sensorList) { + if (!sensors->activate(i.sensorHandle, false).isOk()) { + ok = false; + break; + } + } + if (!ok) { + break; + } + + // mark it done + step = "done"; + succeed = true; + } while (0); + + if (succeed) { + return true; + } + + // Delay 100ms before retry, hidl service is expected to come up in short time after crash. + ALOGI("%s unsuccessful, try again soon (remaining retry %zu).", step.c_str(), retry - 1); + std::this_thread::sleep_for(RETRY_DELAY); + } + + sensors = nullptr; + return false; +} + +void SensorsHidlEnvironmentV1_0::startPollingThread() { + mStopThread = false; + mPollThread = std::thread(pollingThread, this, std::ref(mStopThread)); + mEvents.reserve(128); +} + +void SensorsHidlEnvironmentV1_0::pollingThread(SensorsHidlEnvironmentV1_0* env, + std::atomic_bool& stop) { + ALOGD("polling thread start"); + + while (!stop) { + env->sensors->poll( + 64, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) { + if (result != Result::OK || + (events.size() == 0 && dynamicSensorsAdded.size() == 0) || stop) { + stop = true; + return; + } + + for (const auto& e : events) { + env->addEvent(e); + } + }); + } + ALOGD("polling thread end"); +}
\ No newline at end of file diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h new file mode 100644 index 0000000000..0a9e59f21a --- /dev/null +++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h @@ -0,0 +1,59 @@ +/* + * 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 ANDROID_SENSORS_HIDL_ENVIRONMENT_V1_0_H +#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V1_0_H + +#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h" + +#include <android/hardware/sensors/1.0/ISensors.h> +#include <android/hardware/sensors/1.0/types.h> +#include <utils/StrongPointer.h> + +#include <atomic> +#include <memory> + +using ::android::sp; + +class SensorsHidlTest; +class SensorsHidlEnvironmentV1_0 : public SensorsHidlEnvironmentBase { + public: + using Event = ::android::hardware::sensors::V1_0::Event; + // get the test environment singleton + static SensorsHidlEnvironmentV1_0* Instance() { + static SensorsHidlEnvironmentV1_0* instance = new SensorsHidlEnvironmentV1_0(); + return instance; + } + + virtual void registerTestServices() override { + registerTestService<android::hardware::sensors::V1_0::ISensors>(); + } + + private: + friend SensorsHidlTest; + // sensors hidl service + sp<android::hardware::sensors::V1_0::ISensors> sensors; + + SensorsHidlEnvironmentV1_0() {} + + bool resetHal() override; + void startPollingThread() override; + static void pollingThread(SensorsHidlEnvironmentV1_0* env, std::atomic_bool& stop); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV1_0); +}; + +#endif // ANDROID_SENSORS_HIDL_ENVIRONMENT_V1_0_H
\ No newline at end of file diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp index c18eedd176..47308e13b9 100644 --- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp +++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp @@ -15,583 +15,66 @@ */ #define LOG_TAG "sensors_hidl_hal_test" -#include <VtsHalHidlTargetTestBase.h> -#include <VtsHalHidlTargetTestEnvBase.h> -#include <android-base/logging.h> + +#include "SensorsHidlEnvironmentV1_0.h" +#include "sensors-vts-utils/SensorsHidlTestBase.h" + #include <android/hardware/sensors/1.0/ISensors.h> #include <android/hardware/sensors/1.0/types.h> -#include <cutils/ashmem.h> -#include <hardware/sensors.h> // for sensor type strings #include <log/log.h> #include <utils/SystemClock.h> -#include "GrallocWrapper.h" -#include <algorithm> #include <cinttypes> -#include <cmath> -#include <memory> -#include <mutex> -#include <thread> -#include <unordered_set> #include <vector> -#include <sys/mman.h> -#include <unistd.h> - -using ::android::GrallocWrapper; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::hardware::hidl_string; using ::android::sp; using namespace ::android::hardware::sensors::V1_0; -// Test environment for sensors -class SensorsHidlTest; -class SensorsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: - // get the test environment singleton - static SensorsHidlEnvironment* Instance() { - static SensorsHidlEnvironment* instance = new SensorsHidlEnvironment; - return instance; - } - - virtual void HidlSetUp() override; - virtual void HidlTearDown() override; - - virtual void registerTestServices() override { registerTestService<ISensors>(); } - - // Get and clear all events collected so far (like "cat" shell command). - // If output is nullptr, it clears all collected events. - void catEvents(std::vector<Event>* output); - - // set sensor event collection status - void setCollection(bool enable); - - private: - friend SensorsHidlTest; - // sensors hidl service - sp<ISensors> sensors; - - SensorsHidlEnvironment() {} - - void addEvent(const Event& ev); - void startPollingThread(); - void resetHal(); - static void pollingThread(SensorsHidlEnvironment* env, std::shared_ptr<bool> stop); - - bool collectionEnabled; - std::shared_ptr<bool> stopThread; - std::thread pollThread; - std::vector<Event> events; - std::mutex events_mutex; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironment); -}; - -void SensorsHidlEnvironment::HidlSetUp() { - resetHal(); - - ASSERT_NE(sensors, nullptr) << "sensors is nullptr, cannot get hidl service"; - - collectionEnabled = false; - startPollingThread(); - - // In case framework just stopped for test and there is sensor events in the pipe, - // wait some time for those events to be cleared to avoid them messing up the test. - std::this_thread::sleep_for(std::chrono::seconds(3)); -} +// The main test class for SENSORS HIDL HAL. -void SensorsHidlEnvironment::HidlTearDown() { - if (stopThread) { - *stopThread = true; +class SensorsHidlTest : public SensorsHidlTestBase { + protected: + SensorInfo defaultSensorByType(SensorType type) override; + std::vector<SensorInfo> getSensorsList(); + // implementation wrapper + Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override { + return S()->getSensorsList(_hidl_cb); } - pollThread.detach(); -} - -void SensorsHidlEnvironment::resetHal() { - // wait upto 100ms * 10 = 1s for hidl service. - constexpr auto RETRY_DELAY = std::chrono::milliseconds(100); - - std::string step; - bool succeed = false; - for (size_t retry = 10; retry > 0; --retry) { - // this do ... while is for easy error handling - do { - step = "getService()"; - sensors = ISensors::getService( - SensorsHidlEnvironment::Instance()->getServiceName<ISensors>()); - if (sensors == nullptr) { - break; - } - - step = "poll() check"; - // Poke ISensor service. If it has lingering connection from previous generation of - // system server, it will kill itself. There is no intention to handle the poll result, - // which will be done since the size is 0. - if(!sensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) { - break; - } - - step = "getSensorList"; - std::vector<SensorInfo> sensorList; - if (!sensors->getSensorsList( - [&] (const ::android::hardware::hidl_vec<SensorInfo> &list) { - sensorList.reserve(list.size()); - for (size_t i = 0; i < list.size(); ++i) { - sensorList.push_back(list[i]); - } - }).isOk()) { - break; - } - // stop each sensor individually - step = "stop each sensor"; - bool ok = true; - for (const auto &i : sensorList) { - if (!sensors->activate(i.sensorHandle, false).isOk()) { - ok = false; - break; - } - } - if (!ok) { - break; - } - - // mark it done - step = "done"; - succeed = true; - } while(0); + Return<Result> activate(int32_t sensorHandle, bool enabled) override; - if (succeed) { - return; + Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); } - // Delay 100ms before retry, hidl service is expected to come up in short time after crash. - ALOGI("%s unsuccessful, try again soon (remaining retry %zu).", step.c_str(), retry - 1); - std::this_thread::sleep_for(RETRY_DELAY); - } - - sensors = nullptr; -} + Return<Result> flush(int32_t sensorHandle) override { return S()->flush(sensorHandle); } -void SensorsHidlEnvironment::catEvents(std::vector<Event>* output) { - std::lock_guard<std::mutex> lock(events_mutex); - if (output) { - output->insert(output->end(), events.begin(), events.end()); - } - events.clear(); -} - -void SensorsHidlEnvironment::setCollection(bool enable) { - std::lock_guard<std::mutex> lock(events_mutex); - collectionEnabled = enable; -} - -void SensorsHidlEnvironment::addEvent(const Event& ev) { - std::lock_guard<std::mutex> lock(events_mutex); - if (collectionEnabled) { - events.push_back(ev); - } -} - -void SensorsHidlEnvironment::startPollingThread() { - stopThread = std::shared_ptr<bool>(new bool(false)); - pollThread = std::thread(pollingThread, this, stopThread); - events.reserve(128); -} - -void SensorsHidlEnvironment::pollingThread( - SensorsHidlEnvironment* env, std::shared_ptr<bool> stop) { - ALOGD("polling thread start"); - bool needExit = *stop; - - while(!needExit) { - env->sensors->poll(64, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) { - if (result != Result::OK - || (events.size() == 0 && dynamicSensorsAdded.size() == 0) - || *stop) { - needExit = true; - return; - } - - for (const auto& e : events) { - env->addEvent(e); - } - }); - } - ALOGD("polling thread end"); -} - -class SensorsTestSharedMemory { - public: - static SensorsTestSharedMemory* create(SharedMemType type, size_t size); - SharedMemInfo getSharedMemInfo() const; - char * getBuffer() const; - std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const; - virtual ~SensorsTestSharedMemory(); - private: - SensorsTestSharedMemory(SharedMemType type, size_t size); - - SharedMemType mType; - native_handle_t* mNativeHandle; - size_t mSize; - char* mBuffer; - std::unique_ptr<GrallocWrapper> mGrallocWrapper; - - DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory); -}; - -SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const { - SharedMemInfo mem = { - .type = mType, - .format = SharedMemFormat::SENSORS_EVENT, - .size = static_cast<uint32_t>(mSize), - .memoryHandle = mNativeHandle - }; - return mem; -} - -char * SensorsTestSharedMemory::getBuffer() const { - return mBuffer; -} - -std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const { - - constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH); - constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD); - constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN); - constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE); - constexpr size_t kOffsetAtomicCounter = - static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER); - constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP); - constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA); - - std::vector<Event> events; - std::vector<float> data(16); - - while (offset + kEventSize <= mSize) { - int64_t atomicCounter = *reinterpret_cast<uint32_t *>(mBuffer + offset + kOffsetAtomicCounter); - if (atomicCounter <= lastCounter) { - ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter, lastCounter); - break; + Return<Result> injectSensorData(const Event& event) override { + return S()->injectSensorData(event); } - int32_t size = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetSize); - if (size != kEventSize) { - // unknown error, events parsed may be wrong, remove all - events.clear(); - break; - } - - int32_t token = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetToken); - int32_t type = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetType); - int64_t timestamp = *reinterpret_cast<int64_t *>(mBuffer + offset + kOffsetTimestamp); - - ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32 ", timestamp %" PRId64, - offset, atomicCounter, token, type, timestamp); - - Event event = { - .timestamp = timestamp, - .sensorHandle = token, - .sensorType = static_cast<SensorType>(type), - }; - event.u.data = android::hardware::hidl_array<float, 16> - (reinterpret_cast<float*>(mBuffer + offset + kOffsetData)); + Return<void> registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) override; - events.push_back(event); - - lastCounter = atomicCounter; - offset += kEventSize; - } - - return events; -} - -SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size) - : mType(type), mSize(0), mBuffer(nullptr) { - native_handle_t *handle = nullptr; - char *buffer = nullptr; - switch(type) { - case SharedMemType::ASHMEM: { - int fd; - handle = ::native_handle_create(1 /*nFds*/, 0/*nInts*/); - if (handle != nullptr) { - handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size); - if (handle->data[0] > 0) { - // memory is pinned by default - buffer = static_cast<char *> - (::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); - if (buffer != reinterpret_cast<char*>(MAP_FAILED)) { - break; - } - ::native_handle_close(handle); - } - ::native_handle_delete(handle); - handle = nullptr; - } - break; + Return<Result> unregisterDirectChannel(int32_t channelHandle) override { + return S()->unregisterDirectChannel(channelHandle); } - case SharedMemType::GRALLOC: { - mGrallocWrapper = std::make_unique<GrallocWrapper>(); - if (mGrallocWrapper->getAllocator() == nullptr || mGrallocWrapper->getMapper() == nullptr) { - break; - } - using android::hardware::graphics::common::V1_0::BufferUsage; - using android::hardware::graphics::common::V1_0::PixelFormat; - mapper2::IMapper::BufferDescriptorInfo buf_desc_info = { - .width = static_cast<uint32_t>(size), - .height = 1, - .layerCount = 1, - .usage = static_cast<uint64_t> (BufferUsage::SENSOR_DIRECT_DATA | - BufferUsage::CPU_READ_OFTEN), - .format = PixelFormat::BLOB - }; - - handle = const_cast<native_handle_t *>(mGrallocWrapper->allocate(buf_desc_info)); - if (handle != nullptr) { - mapper2::IMapper::Rect region{0, 0, - static_cast<int32_t>(buf_desc_info.width), - static_cast<int32_t>(buf_desc_info.height)}; - buffer = static_cast<char *> - (mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1)); - if (buffer != nullptr) { - break; - } - mGrallocWrapper->freeBuffer(handle); - handle = nullptr; - } - break; - } - default: - break; - } - - if (buffer != nullptr) { - mNativeHandle = handle; - mSize = size; - mBuffer = buffer; - } -} - -SensorsTestSharedMemory::~SensorsTestSharedMemory() { - switch(mType) { - case SharedMemType::ASHMEM: { - if (mSize != 0) { - ::munmap(mBuffer, mSize); - mBuffer = nullptr; - - ::native_handle_close(mNativeHandle); - ::native_handle_delete(mNativeHandle); - - mNativeHandle = nullptr; - mSize = 0; - } - break; - } - case SharedMemType::GRALLOC: { - if (mSize != 0) { - mGrallocWrapper->unlock(mNativeHandle); - mGrallocWrapper->freeBuffer(mNativeHandle); - - mNativeHandle = nullptr; - mSize = 0; - } - break; - } - default: { - if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) { - ALOGE("SensorsTestSharedMemory %p not properly destructed: " - "type %d, native handle %p, size %zu, buffer %p", - this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer); - } - break; - } - } -} - -SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) { - constexpr size_t kMaxSize = 128*1024*1024; // sensor test should not need more than 128M - if (size == 0 || size >= kMaxSize) { - return nullptr; - } - - auto m = new SensorsTestSharedMemory(type, size); - if (m->mSize != size || m->mBuffer == nullptr) { - delete m; - m = nullptr; - } - return m; -} - -class SensorEventsChecker { - public: - virtual bool check(const std::vector<Event> &events, std::string *out) const = 0; - virtual ~SensorEventsChecker() {} -}; - -class NullChecker : public SensorEventsChecker { - public: - virtual bool check(const std::vector<Event> &, std::string *) const { - return true; - } -}; - -class SensorEventPerEventChecker : public SensorEventsChecker { - public: - virtual bool checkEvent(const Event &event, std::string *out) const = 0; - virtual bool check(const std::vector<Event> &events, std::string *out) const { - for (const auto &e : events) { - if (!checkEvent(e, out)) { - return false; - } - } - return true; - } -}; - -class Vec3NormChecker : public SensorEventPerEventChecker { - public: - Vec3NormChecker(float min, float max) : mRange(min, max) {} - static Vec3NormChecker byNominal(float nominal, float allowedError) { - return Vec3NormChecker(nominal - allowedError, nominal + allowedError); - } - virtual bool checkEvent(const Event &event, std::string *out) const { - Vec3 v = event.u.vec3; - float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z); - if (norm < mRange.first || norm > mRange.second) { - if (out != nullptr) { - std::ostringstream ss; - ss << "Event @ " << event.timestamp << " (" << v.x << ", " << v.y << ", " << v.z << ")" - << " has norm " << norm << ", which is beyond range" - << " [" << mRange.first << ", " << mRange.second << "]"; - *out = ss.str(); - } - return false; + Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) override { + return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); } - return true; - } - protected: - std::pair<float, float> mRange; -}; - -// The main test class for SENSORS HIDL HAL. -class SensorsHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - virtual void SetUp() override { - } - virtual void TearDown() override { - // stop all sensors - for (auto s : mSensorHandles) { - S()->activate(s, false); - } - mSensorHandles.clear(); + inline sp<ISensors>& S() { return SensorsHidlEnvironmentV1_0::Instance()->sensors; } - // stop all direct report and channels - for (auto c : mDirectChannelHandles) { - // disable all reports - S()->configDirectReport(-1, c, RateLevel::STOP, [] (auto, auto){}); - S()->unregisterDirectChannel(c); + SensorsHidlEnvironmentBase* getEnvironment() override { + return SensorsHidlEnvironmentV1_0::Instance(); } - mDirectChannelHandles.clear(); - } - - protected: - SensorInfo defaultSensorByType(SensorType type); - std::vector<SensorInfo> getSensorsList(); - std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit, - bool clearBeforeStart = true, bool changeCollection = true); - - // implementation wrapper - Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) { - return S()->getSensorsList(_hidl_cb); - } - - Return<Result> activate( - int32_t sensorHandle, bool enabled); - - Return<Result> batch( - int32_t sensorHandle, - int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) { - return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); - } - - Return<Result> flush(int32_t sensorHandle) { - return S()->flush(sensorHandle); - } - - Return<Result> injectSensorData(const Event& event) { - return S()->injectSensorData(event); - } - - Return<void> registerDirectChannel( - const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb); - - Return<Result> unregisterDirectChannel(int32_t channelHandle) { - return S()->unregisterDirectChannel(channelHandle); - } - - Return<void> configDirectReport( - int32_t sensorHandle, int32_t channelHandle, RateLevel rate, - ISensors::configDirectReport_cb _hidl_cb) { - return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); - } - - inline sp<ISensors>& S() { - return SensorsHidlEnvironment::Instance()->sensors; - } - - inline static SensorFlagBits extractReportMode(uint64_t flag) { - return (SensorFlagBits) (flag - & ((uint64_t) SensorFlagBits::CONTINUOUS_MODE - | (uint64_t) SensorFlagBits::ON_CHANGE_MODE - | (uint64_t) SensorFlagBits::ONE_SHOT_MODE - | (uint64_t) SensorFlagBits::SPECIAL_REPORTING_MODE)); - } - - inline static bool isMetaSensorType(SensorType type) { - return (type == SensorType::META_DATA - || type == SensorType::DYNAMIC_SENSOR_META - || type == SensorType::ADDITIONAL_INFO); - } - - inline static bool isValidType(SensorType type) { - return (int32_t) type > 0; - } - - void testStreamingOperation(SensorType type, - std::chrono::nanoseconds samplingPeriod, - std::chrono::seconds duration, - const SensorEventsChecker &checker); - void testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow = true); - void testBatchingOperation(SensorType type); - void testDirectReportOperation( - SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker); - - static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType); - static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode); - static void assertDelayMatchReportMode( - int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode); - static SensorFlagBits expectedReportModeForType(SensorType type); - static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate); - static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type); - - // checkers - static const Vec3NormChecker sAccelNormChecker; - static const Vec3NormChecker sGyroNormChecker; - - // all sensors and direct channnels used - std::unordered_set<int32_t> mSensorHandles; - std::unordered_set<int32_t> mDirectChannelHandles; }; -const Vec3NormChecker SensorsHidlTest::sAccelNormChecker( - Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f/*m/s^2*/)); -const Vec3NormChecker SensorsHidlTest::sGyroNormChecker( - Vec3NormChecker::byNominal(0.f, 0.1f/*rad/s*/)); - Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) { // If activating a sensor, add the handle in a set so that when test fails it can be turned off. // The handle is not removed when it is deactivating on purpose so that it is not necessary to @@ -618,195 +101,6 @@ Return<void> SensorsHidlTest::registerDirectChannel( return Void(); } -std::vector<Event> SensorsHidlTest::collectEvents(useconds_t timeLimitUs, size_t nEventLimit, - bool clearBeforeStart, bool changeCollection) { - std::vector<Event> events; - constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //granularity 100 ms - - ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", - nEventLimit, timeLimitUs, clearBeforeStart); - - if (changeCollection) { - SensorsHidlEnvironment::Instance()->setCollection(true); - } - if (clearBeforeStart) { - SensorsHidlEnvironment::Instance()->catEvents(nullptr); - } - - while (timeLimitUs > 0) { - useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs); - usleep(duration); - timeLimitUs -= duration; - - SensorsHidlEnvironment::Instance()->catEvents(&events); - if (events.size() >= nEventLimit) { - break; - } - ALOGV("time to go = %d, events to go = %d", - (int)timeLimitUs, (int)(nEventLimit - events.size())); - } - - if (changeCollection) { - SensorsHidlEnvironment::Instance()->setCollection(false); - } - return events; -} - -void SensorsHidlTest::assertTypeMatchStringType(SensorType type, const hidl_string& stringType) { - - if (type >= SensorType::DEVICE_PRIVATE_BASE) { - return; - } - - switch (type) { -#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \ - case SensorType::type: ASSERT_STREQ(SENSOR_STRING_TYPE_ ## type, stringType.c_str()); break; - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE); - CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE); - default: - FAIL() << "Type " << static_cast<int>(type) << " in android defined range is not checked, " - << "stringType = " << stringType; -#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE - } -} - -void SensorsHidlTest::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) { - if (type >= SensorType::DEVICE_PRIVATE_BASE) { - return; - } - - SensorFlagBits expected = expectedReportModeForType(type); - - ASSERT_TRUE(expected == (SensorFlagBits) -1 || expected == reportMode) - << "reportMode=" << static_cast<int>(reportMode) - << "expected=" << static_cast<int>(expected); -} - -void SensorsHidlTest::assertDelayMatchReportMode( - int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode) { - switch(reportMode) { - case SensorFlagBits::CONTINUOUS_MODE: - ASSERT_LT(0, minDelay); - ASSERT_LE(0, maxDelay); - break; - case SensorFlagBits::ON_CHANGE_MODE: - ASSERT_LE(0, minDelay); - ASSERT_LE(0, maxDelay); - break; - case SensorFlagBits::ONE_SHOT_MODE: - ASSERT_EQ(-1, minDelay); - ASSERT_EQ(0, maxDelay); - break; - case SensorFlagBits::SPECIAL_REPORTING_MODE: - // do not enforce anything for special reporting mode - break; - default: - FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked"; - } -} - -// return -1 means no expectation for this type -SensorFlagBits SensorsHidlTest::expectedReportModeForType(SensorType type) { - switch (type) { - case SensorType::ACCELEROMETER: - case SensorType::ACCELEROMETER_UNCALIBRATED: - case SensorType::GYROSCOPE: - case SensorType::MAGNETIC_FIELD: - case SensorType::ORIENTATION: - case SensorType::PRESSURE: - case SensorType::TEMPERATURE: - case SensorType::GRAVITY: - case SensorType::LINEAR_ACCELERATION: - case SensorType::ROTATION_VECTOR: - case SensorType::MAGNETIC_FIELD_UNCALIBRATED: - case SensorType::GAME_ROTATION_VECTOR: - case SensorType::GYROSCOPE_UNCALIBRATED: - case SensorType::GEOMAGNETIC_ROTATION_VECTOR: - case SensorType::POSE_6DOF: - case SensorType::HEART_BEAT: - return SensorFlagBits::CONTINUOUS_MODE; - - case SensorType::LIGHT: - case SensorType::PROXIMITY: - case SensorType::RELATIVE_HUMIDITY: - case SensorType::AMBIENT_TEMPERATURE: - case SensorType::HEART_RATE: - case SensorType::DEVICE_ORIENTATION: - case SensorType::STEP_COUNTER: - case SensorType::LOW_LATENCY_OFFBODY_DETECT: - return SensorFlagBits::ON_CHANGE_MODE; - - case SensorType::SIGNIFICANT_MOTION: - case SensorType::WAKE_GESTURE: - case SensorType::GLANCE_GESTURE: - case SensorType::PICK_UP_GESTURE: - case SensorType::MOTION_DETECT: - case SensorType::STATIONARY_DETECT: - return SensorFlagBits::ONE_SHOT_MODE; - - case SensorType::STEP_DETECTOR: - case SensorType::TILT_DETECTOR: - case SensorType::WRIST_TILT_GESTURE: - case SensorType::DYNAMIC_SENSOR_META: - return SensorFlagBits::SPECIAL_REPORTING_MODE; - - default: - ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type); - return (SensorFlagBits)-1; - } -} - -bool SensorsHidlTest::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) { - unsigned int r = - static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT) - >> static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT); - return r >= static_cast<unsigned int>(rate); -} - -bool SensorsHidlTest::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) { - switch (type) { - case SharedMemType::ASHMEM: - return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0; - case SharedMemType::GRALLOC: - return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0; - default: - return false; - } -} - SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) { SensorInfo ret; @@ -951,69 +245,6 @@ TEST_F(SensorsHidlTest, InjectSensorEventData) { ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL)); } -void SensorsHidlTest::testStreamingOperation(SensorType type, - std::chrono::nanoseconds samplingPeriod, - std::chrono::seconds duration, - const SensorEventsChecker &checker) { - std::vector<Event> events; - std::vector<Event> sensorEvents; - - const int64_t samplingPeriodInNs = samplingPeriod.count(); - const int64_t batchingPeriodInNs = 0; // no batching - const useconds_t minTimeUs = std::chrono::microseconds(duration).count(); - const size_t minNEvent = duration / samplingPeriod; - - SensorInfo sensor = defaultSensorByType(type); - - if (!isValidType(sensor.type)) { - // no default sensor of this type - return; - } - - if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) { - // rate not supported - return; - } - - int32_t handle = sensor.sensorHandle; - - ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK); - ASSERT_EQ(activate(handle, 1), Result::OK); - events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/); - ASSERT_EQ(activate(handle, 0), Result::OK); - - ALOGI("Collected %zu samples", events.size()); - - ASSERT_GT(events.size(), 0u); - - bool handleMismatchReported = false; - bool metaSensorTypeErrorReported = false; - for (auto & e : events) { - if (e.sensorType == type) { - // avoid generating hundreds of error - if (!handleMismatchReported) { - EXPECT_EQ(e.sensorHandle, handle) - << (handleMismatchReported = true, - "Event of the same type must come from the sensor registered"); - } - sensorEvents.push_back(e); - } else { - // avoid generating hundreds of error - if (!metaSensorTypeErrorReported) { - EXPECT_TRUE(isMetaSensorType(e.sensorType)) - << (metaSensorTypeErrorReported = true, - "Only meta types are allowed besides the type registered"); - } - } - } - - std::string s; - EXPECT_TRUE(checker.check(sensorEvents, &s)) << s; - - EXPECT_GE(sensorEvents.size(), - minNEvent / 2); // make sure returned events are not all meta -} - // Test if sensor hal can do UI speed accelerometer streaming properly TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) { testStreamingOperation(SensorType::ACCELEROMETER, @@ -1086,103 +317,6 @@ TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) { NullChecker()); } -void SensorsHidlTest::testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow) { - std::vector<Event> events1, events2; - - constexpr int64_t batchingPeriodInNs = 0; // no batching - constexpr int64_t collectionTimeoutUs = 60000000; // 60s - constexpr size_t minNEvent = 50; - - SensorInfo sensor = defaultSensorByType(type); - - if (!isValidType(sensor.type)) { - // no default sensor of this type - return; - } - - int32_t handle = sensor.sensorHandle; - int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; - int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll; - - if (minSamplingPeriodInNs == maxSamplingPeriodInNs) { - // only support single rate - return; - } - - int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs; - int64_t secondCollectionPeriod = !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs; - - // first collection - ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK); - ASSERT_EQ(activate(handle, 1), Result::OK); - - usleep(500000); // sleep 0.5 sec to wait for change rate to happen - events1 = collectEvents(collectionTimeoutUs, minNEvent); - - // second collection, without stop sensor - ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK); - - usleep(500000); // sleep 0.5 sec to wait for change rate to happen - events2 = collectEvents(collectionTimeoutUs, minNEvent); - - // end of collection, stop sensor - ASSERT_EQ(activate(handle, 0), Result::OK); - - ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size()); - - ASSERT_GT(events1.size(), 0u); - ASSERT_GT(events2.size(), 0u); - - int64_t minDelayAverageInterval, maxDelayAverageInterval; - std::vector<Event> &minDelayEvents(fastToSlow ? events1 : events2); - std::vector<Event> &maxDelayEvents(fastToSlow ? events2 : events1); - - size_t nEvent = 0; - int64_t prevTimestamp = -1; - int64_t timestampInterval = 0; - for (auto & e : minDelayEvents) { - if (e.sensorType == type) { - ASSERT_EQ(e.sensorHandle, handle); - if (prevTimestamp > 0) { - timestampInterval += e.timestamp - prevTimestamp; - } - prevTimestamp = e.timestamp; - ++ nEvent; - } - } - ASSERT_GT(nEvent, 2u); - minDelayAverageInterval = timestampInterval / (nEvent - 1); - - nEvent = 0; - prevTimestamp = -1; - timestampInterval = 0; - for (auto & e : maxDelayEvents) { - if (e.sensorType == type) { - ASSERT_EQ(e.sensorHandle, handle); - if (prevTimestamp > 0) { - timestampInterval += e.timestamp - prevTimestamp; - } - prevTimestamp = e.timestamp; - ++ nEvent; - } - } - ASSERT_GT(nEvent, 2u); - maxDelayAverageInterval = timestampInterval / (nEvent - 1); - - // change of rate is significant. - ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64, - minDelayAverageInterval, maxDelayAverageInterval); - EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10); - - // fastest rate sampling time is close to spec - EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs), - minSamplingPeriodInNs / 10); - - // slowest rate sampling time is close to spec - EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs), - maxSamplingPeriodInNs / 10); -} - // Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) { testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER); @@ -1201,74 +335,6 @@ TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) { testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/); } -void SensorsHidlTest::testBatchingOperation(SensorType type) { - std::vector<Event> events; - - constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000; - constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000; - - SensorInfo sensor = defaultSensorByType(type); - - if (!isValidType(sensor.type)) { - // no default sensor of this type - return; - } - - int32_t handle = sensor.sensorHandle; - int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; - uint32_t minFifoCount = sensor.fifoReservedEventCount; - int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs; - - if (batchingPeriodInNs < oneSecondInNs) { - // batching size too small to test reliably - return; - } - - batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs); - - ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000)); - - int64_t allowedBatchDeliverTimeNs = - std::max(oneSecondInNs, batchingPeriodInNs / 10); - - ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK); - ASSERT_EQ(activate(handle, 1), Result::OK); - - usleep(500000); // sleep 0.5 sec to wait for initialization - ASSERT_EQ(flush(handle), Result::OK); - - // wait for 80% of the reserved batching period - // there should not be any significant amount of events - // since collection is not enabled all events will go down the drain - usleep(batchingPeriodInNs / 1000 * 8 / 10); - - SensorsHidlEnvironment::Instance()->setCollection(true); - // clean existing collections - collectEvents(0 /*timeLimitUs*/, 0/*nEventLimit*/, - true /*clearBeforeStart*/, false /*change collection*/); - - // 0.8 + 0.2 times the batching period - usleep(batchingPeriodInNs / 1000 * 8 / 10); - ASSERT_EQ(flush(handle), Result::OK); - - // plus some time for the event to deliver - events = collectEvents(allowedBatchDeliverTimeNs / 1000, - minFifoCount, false /*clearBeforeStart*/, false /*change collection*/); - - SensorsHidlEnvironment::Instance()->setCollection(false); - ASSERT_EQ(activate(handle, 0), Result::OK); - - size_t nEvent = 0; - for (auto & e : events) { - if (e.sensorType == type && e.sensorHandle == handle) { - ++ nEvent; - } - } - - // at least reach 90% of advertised capacity - ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10)); -} - // Test if sensor hal can do accelerometer batching properly TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) { testBatchingOperation(SensorType::ACCELEROMETER); @@ -1284,124 +350,6 @@ TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) { testBatchingOperation(SensorType::MAGNETIC_FIELD); } -void SensorsHidlTest::testDirectReportOperation( - SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker) { - constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH); - constexpr size_t kNEvent = 4096; - constexpr size_t kMemSize = kEventSize * kNEvent; - - constexpr float kNormalNominal = 50; - constexpr float kFastNominal = 200; - constexpr float kVeryFastNominal = 800; - - constexpr float kNominalTestTimeSec = 1.f; - constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization - - SensorInfo sensor = defaultSensorByType(type); - - if (!isValidType(sensor.type)) { - // no default sensor of this type - return; - } - - if (!isDirectReportRateSupported(sensor, rate)) { - return; - } - - if (!isDirectChannelTypeSupported(sensor, memType)) { - return; - } - - std::unique_ptr<SensorsTestSharedMemory> - mem(SensorsTestSharedMemory::create(memType, kMemSize)); - ASSERT_NE(mem, nullptr); - - char* buffer = mem->getBuffer(); - // fill memory with data - for (size_t i = 0; i < kMemSize; ++i) { - buffer[i] = '\xcc'; - } - - int32_t channelHandle; - registerDirectChannel(mem->getSharedMemInfo(), - [&channelHandle] (auto result, auto channelHandle_) { - ASSERT_EQ(result, Result::OK); - channelHandle = channelHandle_; - }); - - // check memory is zeroed - for (size_t i = 0; i < kMemSize; ++i) { - ASSERT_EQ(buffer[i], '\0'); - } - - int32_t eventToken; - configDirectReport(sensor.sensorHandle, channelHandle, rate, - [&eventToken] (auto result, auto token) { - ASSERT_EQ(result, Result::OK); - eventToken = token; - }); - - usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f)); - auto events = mem->parseEvents(); - - // find norminal rate - float nominalFreq = 0.f; - switch (rate) { - case RateLevel::NORMAL: - nominalFreq = kNormalNominal; - break; - case RateLevel::FAST: - nominalFreq = kFastNominal; - break; - case RateLevel::VERY_FAST: - nominalFreq = kVeryFastNominal; - break; - case RateLevel::STOP: - FAIL(); - } - - // allowed to be between 55% and 220% of nominal freq - ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec)); - ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec)); - - int64_t lastTimestamp = 0; - bool typeErrorReported = false; - bool tokenErrorReported = false; - bool timestampErrorReported = false; - std::vector<Event> sensorEvents; - for (auto &e : events) { - if (!tokenErrorReported) { - EXPECT_EQ(eventToken, e.sensorHandle) - << (tokenErrorReported = true, - "Event token does not match that retured from configDirectReport"); - } - - if (isMetaSensorType(e.sensorType)) { - continue; - } - sensorEvents.push_back(e); - - if (!typeErrorReported) { - EXPECT_EQ(type, e.sensorType) - << (typeErrorReported = true, - "Type in event does not match type of sensor registered."); - } - if (!timestampErrorReported) { - EXPECT_GT(e.timestamp, lastTimestamp) - << (timestampErrorReported = true, "Timestamp not monotonically increasing"); - } - lastTimestamp = e.timestamp; - } - - std::string s; - EXPECT_TRUE(checker.check(sensorEvents, &s)) << s; - - // stop sensor and unregister channel - configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP, - [](auto result, auto) { EXPECT_EQ(result, Result::OK); }); - EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK); -} - // Test sensor event direct report with ashmem for accel sensor at normal rate TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) { testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL, @@ -1511,11 +459,11 @@ TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) { } int main(int argc, char **argv) { - ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironment::Instance()); - ::testing::InitGoogleTest(&argc, argv); - SensorsHidlEnvironment::Instance()->init(&argc, argv); - int status = RUN_ALL_TESTS(); - ALOGI("Test result = %d", status); - return status; + ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV1_0::Instance()); + ::testing::InitGoogleTest(&argc, argv); + SensorsHidlEnvironmentV1_0::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; } // vim: set ts=2 sw=2 diff --git a/sensors/2.0/Android.bp b/sensors/2.0/Android.bp new file mode 100644 index 0000000000..3b948a9cee --- /dev/null +++ b/sensors/2.0/Android.bp @@ -0,0 +1,24 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.sensors@2.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ISensors.hal", + "ISensorsCallback.hal", + ], + interfaces: [ + "android.hardware.sensors@1.0", + "android.hidl.base@1.0", + ], + types: [ + "EventQueueFlagBits", + "SensorTimeout", + ], + gen_java: false, +} + diff --git a/sensors/2.0/ISensors.hal b/sensors/2.0/ISensors.hal new file mode 100644 index 0000000000..3a9af46bf5 --- /dev/null +++ b/sensors/2.0/ISensors.hal @@ -0,0 +1,272 @@ +/* + * 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. + */ + +package android.hardware.sensors@2.0; + +import @1.0::Event; +import @1.0::OperationMode; +import @1.0::RateLevel; +import @1.0::Result; +import @1.0::SensorInfo; +import @1.0::SharedMemInfo; +import @2.0::ISensorsCallback; + +interface ISensors { + /** + * Enumerate all available (static) sensors. + * + * The SensorInfo for each sensor returned by getSensorsList must be stable + * from the initial call to getSensorsList after a device boot until the + * entire system restarts. The SensorInfo for each sensor must not change + * between subsequent calls to getSensorsList, even across restarts of the + * HAL and its dependencies (for example, the sensor handle for a given + * sensor must not change across HAL restarts). + */ + getSensorsList() generates (vec<SensorInfo> list); + + /** + * Place the module in a specific mode. The following modes are defined + * + * SENSOR_HAL_NORMAL_MODE - Normal operation. Default state of the module. + * + * SENSOR_HAL_DATA_INJECTION_MODE - Loopback mode. + * Data is injected for the supported sensors by the sensor service in + * this mode. + * + * @return OK on success + * BAD_VALUE if requested mode is not supported + * PERMISSION_DENIED if operation is not allowed + */ + setOperationMode(OperationMode mode) generates (Result result); + + /** + * Activate/de-activate one sensor. + * + * After sensor de-activation, existing sensor events that have not + * been written to the event queue must be abandoned immediately so that + * subsequent activations do not get stale sensor events (events + * that are generated prior to the latter activation). + * + * @param sensorHandle is the handle of the sensor to change. + * @param enabled set to true to enable, or false to disable the sensor. + * @return result OK on success, BAD_VALUE if sensorHandle is invalid. + */ + activate(int32_t sensorHandle, bool enabled) generates (Result result); + + /** + * Initialize the Sensors HAL's Fast Message Queues (FMQ) and callback. + * + * The Fast Message Queues (FMQ) that are used to send data between the + * framework and the HAL. The callback is used by the HAL to notify the + * framework of asynchronous events, such as a dynamic sensor connection. + * + * The Event FMQ is used to transport sensor events from the HAL to the + * framework. The Event FMQ is created using the eventQueueDescriptor. + * Data may only be written to the Event FMQ. Data must not be read from + * the Event FMQ since the framework is the only reader. Upon receiving + * sensor events, the HAL writes the sensor events to the Event FMQ. + * + * Once the HAL is finished writing sensor events to the Event FMQ, the HAL + * must notify the framework that sensor events are available to be read and + * processed. This is accomplished by either: + * 1) Calling the Event FMQ’s EventFlag::wake() function with + EventQueueFlagBits::READ_AND_PROCESS + * 2) Setting the write notification in the Event FMQ’s writeBlocking() + * function to EventQueueFlagBits::READ_AND_PROCESS. + * + * If the Event FMQ’s writeBlocking() function is used, the read + * notification must be set to EventQueueFlagBits::EVENTS_READ in order to + * be notified and unblocked when the framework has successfully read events + * from the Event FMQ. + * + * The Wake Lock FMQ is used by the framework to notify the HAL when it is + * safe to release its wake_lock. When the framework receives WAKE_UP events + * from the Event FMQ and the framework has acquired a wake_lock, the + * framework must write the number of WAKE_UP events processed to the Wake + * Lock FMQ. When the HAL reads the data from the Wake Lock FMQ, the HAL + * decrements its current count of unprocessed WAKE_UP events and releases + * its wake_lock if the current count of unprocessed WAKE_UP events is + * zero. + * + * The framework must use the WakeLockQueueFlagBits::DATA_WRITTEN value to + * notify the HAL that data has been written to the Wake Lock FMQ and must + * be read by HAL. + * + * The ISensorsCallback is used by the HAL to notify the framework of + * asynchronous events, such as a dynamic sensor connection. + * + * The name of any wake_lock acquired by the Sensors HAL for WAKE_UP events + * must begin with "SensorsHAL_WAKEUP". + * + * If WAKE_LOCK_TIMEOUT_SECONDS has elapsed since the most recent WAKE_UP + * event was written to the Event FMQ without receiving a message on the + * Wake Lock FMQ, then any held wake_lock for WAKE_UP events must be + * released. + * + * If either the Event FMQ or the Wake Lock FMQ is already initialized when + * initialize is invoked, then both existing FMQs must be discarded and the + * new descriptors must be used to create new FMQs within the HAL. The + * number of outstanding WAKE_UP events should also be reset to zero, and + * any outstanding wake_locks held as a result of WAKE_UP events should be + * released. + * + * All active sensor requests and direct channels must be closed and + * properly cleaned up when initialize is called in order to ensure that the + * HAL and framework's state is consistent (e.g. after a runtime restart). + * + * initialize must be thread safe and prevent concurrent calls + * to initialize from simultaneously modifying state. + * + * @param eventQueueDescriptor Fast Message Queue descriptor that is used to + * create the Event FMQ which is where sensor events are written. The + * descriptor is obtained from the framework's FMQ that is used to read + * sensor events. + * @param wakeLockDescriptor Fast Message Queue descriptor that is used to + * create the Wake Lock FMQ which is where wake_lock events are read + * from. The descriptor is obtained from the framework's FMQ that is + * used to write wake_lock events. + * @param sensorsCallback sensors callback that receives asynchronous data + * from the Sensors HAL. + * @return result OK on success; BAD_VALUE if descriptor is invalid (such + * as null) + */ + @entry + @callflow(next = {"getSensorsList"}) + initialize(fmq_sync<Event> eventQueueDescriptor, + fmq_sync<uint32_t> wakeLockDescriptor, + ISensorsCallback sensorsCallback) + generates + (Result result); + + /** + * Sets a sensor’s parameters, including sampling frequency and maximum + * report latency. This function can be called while the sensor is + * activated, in which case it must not cause any sensor measurements to + * be lost: transitioning from one sampling rate to the other cannot cause + * lost events, nor can transitioning from a high maximum report latency to + * a low maximum report latency. + * + * @param sensorHandle handle of sensor to be changed. + * @param samplingPeriodNs specifies sensor sample period in nanoseconds. + * @param maxReportLatencyNs allowed delay time before an event is sampled + * to time of report. + * @return result OK on success, BAD_VALUE if any parameters are invalid. + */ + batch(int32_t sensorHandle, + int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) + generates ( + Result result); + + /** + * Trigger a flush of internal FIFO. + * + * Flush adds a FLUSH_COMPLETE metadata event to the end of the "batch mode" + * FIFO for the specified sensor and flushes the FIFO. If the FIFO is empty + * or if the sensor doesn't support batching (FIFO size zero), return + * SUCCESS and add a trivial FLUSH_COMPLETE event added to the event stream. + * This applies to all sensors other than one-shot sensors. If the sensor + * is a one-shot sensor, flush must return BAD_VALUE and not generate any + * flush complete metadata. If the sensor is not active at the time flush() + * is called, flush() return BAD_VALUE. + * + * @param sensorHandle handle of sensor to be flushed. + * @return result OK on success and BAD_VALUE if sensorHandle is invalid. + */ + flush(int32_t sensorHandle) generates (Result result); + + /** + * Inject a single sensor event or push operation environment parameters to + * device. + * + * When device is in NORMAL mode, this function is called to push operation + * environment data to device. In this operation, Event is always of + * SensorType::AdditionalInfo type. See operation evironment parameters + * section in AdditionalInfoType. + * + * When device is in DATA_INJECTION mode, this function is also used for + * injecting sensor events. + * + * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO + * type events should not be routed back to the sensor event queue. + * + * @see AdditionalInfoType + * @see OperationMode + * @param event sensor event to be injected + * @return result OK on success; PERMISSION_DENIED if operation is not + * allowed; INVALID_OPERATION, if this functionality is unsupported; + * BAD_VALUE if sensor event cannot be injected. + */ + injectSensorData(Event event) generates (Result result); + + /** + * Register direct report channel. + * + * Register a direct channel with supplied shared memory information. Upon + * return, the sensor hardware is responsible for resetting the memory + * content to initial value (depending on memory format settings). + * + * @param mem shared memory info data structure. + * @return result OK on success; BAD_VALUE if shared memory information is + * not consistent; NO_MEMORY if shared memory cannot be used by sensor + * system; INVALID_OPERATION if functionality is not supported. + * @return channelHandle a positive integer used for referencing registered + * direct channel (>0) in configureDirectReport and + * unregisterDirectChannel if result is OK, -1 otherwise. + */ + registerDirectChannel(SharedMemInfo mem) + generates (Result result, + int32_t channelHandle); + + /** + * Unregister direct report channel. + * + * Unregister a direct channel previously registered using + * registerDirectChannel, and remove all active sensor report configured in + * still active sensor report configured in the direct channel. + * + * @param channelHandle handle of direct channel to be unregistered. + * @return result OK if direct report is supported; INVALID_OPERATION + * otherwise. + */ + unregisterDirectChannel(int32_t channelHandle) generates (Result result); + + /** + * Configure direct sensor event report in direct channel. + * + * This function start, modify rate or stop direct report of a sensor in a + * certain direct channel. + * + * @param sensorHandle handle of sensor to be configured. When combined + * with STOP rate, sensorHandle can be -1 to denote all active sensors + * in the direct channel specified by channel Handle. + * @param channelHandle handle of direct channel to be configured. + * @param rate rate level, see RateLevel enum. + * @return result OK on success; BAD_VALUE if parameter is invalid (such as + * rate level is not supported by sensor, channelHandle does not exist, + * etc); INVALID_OPERATION if functionality is not supported. + * @return reportToken positive integer to identify multiple sensors of + * the same type in a single direct channel. Ignored if rate is STOP. + * See SharedMemFormat. + */ + configDirectReport( + int32_t sensorHandle, + int32_t channelHandle, + RateLevel rate + ) generates ( + Result result, + int32_t reportToken); +}; diff --git a/sensors/2.0/ISensorsCallback.hal b/sensors/2.0/ISensorsCallback.hal new file mode 100644 index 0000000000..e0bd98f506 --- /dev/null +++ b/sensors/2.0/ISensorsCallback.hal @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package android.hardware.sensors@2.0; + +import @1.0::SensorInfo; + +interface ISensorsCallback { + /** + * Notify the framework that new dynamic sensors have been connected. + * + * If a dynamic sensor was previously connected and has not been + * disconnected, then that sensor must not be included in sensorInfos. + * + * @param sensorInfos vector of SensorInfo for each dynamic sensor that + * was connected. + */ + oneway onDynamicSensorsConnected(vec<SensorInfo> sensorInfos); + + /** + * Notify the framework that previously connected dynamic sensors have been + * disconnected. + * + * If a dynamic sensor was previously disconnected and has not been + * reconnected, then that sensor must not be included in sensorHandles. + * + * The HAL must ensure that all sensor events from departing dynamic + * sensors have been written to the Event FMQ before calling + * onDynamicSensorsDisconnected. + * + * @param sensorHandles vector of sensor handles for each dynamic sensors + * that was disconnected. + */ + oneway onDynamicSensorsDisconnected(vec<int32_t> sensorHandles); +}; diff --git a/audio/common/2.0/default/Android.bp b/sensors/2.0/default/Android.bp index ac66479c93..d83a9c36fe 100644 --- a/audio/common/2.0/default/Android.bp +++ b/sensors/2.0/default/Android.bp @@ -1,5 +1,5 @@ // -// Copyright (C) 2016 The Android Open Source Project +// 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. @@ -13,35 +13,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_library_shared { - name: "android.hardware.audio.common@2.0-util", +cc_binary { + name: "android.hardware.sensors@2.0-service", defaults: ["hidl_defaults"], - vendor_available: true, - vndk: { - enabled: true, - }, + vendor: true, + relative_install_path: "hw", srcs: [ - "HidlUtils.cpp", + "service.cpp", + "Sensor.cpp", + "Sensors.cpp", ], - - export_include_dirs: ["."], - - static_libs: [ - ], - + init_rc: ["android.hardware.sensors@2.0-service.rc"], shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "libcutils", + "libfmq", + "libhidlbase", + "libhidltransport", "liblog", + "libpower", "libutils", - "libhidlbase", - "android.hardware.audio.common-util", - "android.hardware.audio.common@2.0", - ], - export_shared_lib_headers: [ - "android.hardware.audio.common-util" - ], - - header_libs: [ - "libaudio_system_headers", - "libhardware_headers", ], + vintf_fragments: ["android.hardware.sensors@2.0.xml"], } diff --git a/sensors/2.0/default/OWNERS b/sensors/2.0/default/OWNERS new file mode 100644 index 0000000000..2031d848cf --- /dev/null +++ b/sensors/2.0/default/OWNERS @@ -0,0 +1,2 @@ +bduddie@google.com +bstack@google.com diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/2.0/default/Sensor.cpp new file mode 100644 index 0000000000..c09173f7ce --- /dev/null +++ b/sensors/2.0/default/Sensor.cpp @@ -0,0 +1,373 @@ +/* + * 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 "Sensor.h" + +#include <utils/SystemClock.h> + +#include <cmath> + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::sensors::V1_0::MetaDataEventType; +using ::android::hardware::sensors::V1_0::SensorFlagBits; +using ::android::hardware::sensors::V1_0::SensorStatus; + +static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000; + +Sensor::Sensor(ISensorsEventCallback* callback) + : mIsEnabled(false), + mSamplingPeriodNs(0), + mLastSampleTimeNs(0), + mCallback(callback), + mMode(OperationMode::NORMAL) { + mRunThread = std::thread(startThread, this); +} + +Sensor::~Sensor() { + std::unique_lock<std::mutex> lock(mRunMutex); + mStopThread = true; + mIsEnabled = false; + mWaitCV.notify_all(); + lock.release(); + mRunThread.join(); +} + +const SensorInfo& Sensor::getSensorInfo() const { + return mSensorInfo; +} + +void Sensor::batch(int32_t samplingPeriodNs) { + if (samplingPeriodNs < mSensorInfo.minDelay * 1000) { + samplingPeriodNs = mSensorInfo.minDelay * 1000; + } else if (samplingPeriodNs > mSensorInfo.maxDelay * 1000) { + samplingPeriodNs = mSensorInfo.maxDelay * 1000; + } + + if (mSamplingPeriodNs != samplingPeriodNs) { + mSamplingPeriodNs = samplingPeriodNs; + // Wake up the 'run' thread to check if a new event should be generated now + mWaitCV.notify_all(); + } +} + +void Sensor::activate(bool enable) { + if (mIsEnabled != enable) { + std::unique_lock<std::mutex> lock(mRunMutex); + mIsEnabled = enable; + mWaitCV.notify_all(); + } +} + +Result Sensor::flush() { + // Only generate a flush complete event if the sensor is enabled and if the sensor is not a + // one-shot sensor. + if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) { + return Result::BAD_VALUE; + } + + // Note: If a sensor supports batching, write all of the currently batched events for the sensor + // to the Event FMQ prior to writing the flush complete event. + Event ev; + ev.sensorHandle = mSensorInfo.sensorHandle; + ev.sensorType = SensorType::META_DATA; + ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE; + std::vector<Event> evs{ev}; + mCallback->postEvents(evs, isWakeUpSensor()); + + return Result::OK; +} + +void Sensor::startThread(Sensor* sensor) { + sensor->run(); +} + +void Sensor::run() { + std::unique_lock<std::mutex> runLock(mRunMutex); + constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000; + + while (!mStopThread) { + if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) { + mWaitCV.wait(runLock, [&] { + return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread); + }); + } else { + timespec curTime; + clock_gettime(CLOCK_REALTIME, &curTime); + int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec; + int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs; + + if (now >= nextSampleTime) { + mLastSampleTimeNs = now; + nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs; + mCallback->postEvents(readEvents(), isWakeUpSensor()); + } + + mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now)); + } + } +} + +bool Sensor::isWakeUpSensor() { + return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP); +} + +std::vector<Event> Sensor::readEvents() { + std::vector<Event> events; + Event event; + event.sensorHandle = mSensorInfo.sensorHandle; + event.sensorType = mSensorInfo.type; + event.timestamp = ::android::elapsedRealtimeNano(); + event.u.vec3.x = 0; + event.u.vec3.y = 0; + event.u.vec3.z = 0; + event.u.vec3.status = SensorStatus::ACCURACY_HIGH; + events.push_back(event); + return events; +} + +void Sensor::setOperationMode(OperationMode mode) { + if (mMode != mode) { + std::unique_lock<std::mutex> lock(mRunMutex); + mMode = mode; + mWaitCV.notify_all(); + } +} + +bool Sensor::supportsDataInjection() const { + return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION); +} + +Result Sensor::injectEvent(const Event& event) { + Result result = Result::OK; + if (event.sensorType == SensorType::ADDITIONAL_INFO) { + // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation + // environment data into the device. + } else if (!supportsDataInjection()) { + result = Result::INVALID_OPERATION; + } else if (mMode == OperationMode::DATA_INJECTION) { + mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor()); + } else { + result = Result::BAD_VALUE; + } + return result; +} + +OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback) + : Sensor(callback), mPreviousEventSet(false) {} + +void OnChangeSensor::activate(bool enable) { + Sensor::activate(enable); + if (!enable) { + mPreviousEventSet = false; + } +} + +std::vector<Event> OnChangeSensor::readEvents() { + std::vector<Event> events = Sensor::readEvents(); + std::vector<Event> outputEvents; + + for (auto iter = events.begin(); iter != events.end(); ++iter) { + Event ev = *iter; + if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) { + outputEvents.push_back(ev); + mPreviousEvent = ev; + mPreviousEventSet = true; + } + } + return outputEvents; +} + +AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Accel Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::ACCELEROMETER; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 78.4f; // +/- 8g + mSensorInfo.resolution = 1.52e-5; + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 20 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION); +}; + +PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Pressure Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::PRESSURE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 1100.0f; // hPa + mSensorInfo.resolution = 0.005f; // hPa + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 100 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = 0; +}; + +MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Magnetic Field Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::MAGNETIC_FIELD; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 1300.0f; + mSensorInfo.resolution = 0.01f; + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 20 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = 0; +}; + +LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Light Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::LIGHT; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 43000.0f; + mSensorInfo.resolution = 10.0f; + mSensorInfo.power = 0.001f; // mA + mSensorInfo.minDelay = 200 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE); +}; + +ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Proximity Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::PROXIMITY; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 5.0f; + mSensorInfo.resolution = 1.0f; + mSensorInfo.power = 0.012f; // mA + mSensorInfo.minDelay = 200 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = + static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP); +}; + +GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Gyro Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::GYROSCOPE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f; + mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f); + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 2.5f * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = 0; +}; + +AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Ambient Temp Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 80.0f; + mSensorInfo.resolution = 0.01f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE); +}; + +DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Device Temp Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::TEMPERATURE; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 80.0f; + mSensorInfo.resolution = 0.01f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE); +} + +RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle, + ISensorsEventCallback* callback) + : OnChangeSensor(callback) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.name = "Relative Humidity Sensor"; + mSensorInfo.vendor = "Vendor String"; + mSensorInfo.version = 1; + mSensorInfo.type = SensorType::RELATIVE_HUMIDITY; + mSensorInfo.typeAsString = ""; + mSensorInfo.maxRange = 100.0f; + mSensorInfo.resolution = 0.1f; + mSensorInfo.power = 0.001f; + mSensorInfo.minDelay = 40 * 1000; // microseconds + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/2.0/default/Sensor.h b/sensors/2.0/default/Sensor.h new file mode 100644 index 0000000000..61900fa436 --- /dev/null +++ b/sensors/2.0/default/Sensor.h @@ -0,0 +1,147 @@ +/* + * 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 ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H +#define ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H + +#include <android/hardware/sensors/1.0/types.h> + +#include <condition_variable> +#include <memory> +#include <mutex> +#include <thread> +#include <vector> + +using ::android::hardware::sensors::V1_0::Event; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SensorInfo; +using ::android::hardware::sensors::V1_0::SensorType; + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +class ISensorsEventCallback { + public: + virtual ~ISensorsEventCallback(){}; + virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0; +}; + +class Sensor { + public: + Sensor(ISensorsEventCallback* callback); + virtual ~Sensor(); + + const SensorInfo& getSensorInfo() const; + void batch(int32_t samplingPeriodNs); + virtual void activate(bool enable); + Result flush(); + + void setOperationMode(OperationMode mode); + bool supportsDataInjection() const; + Result injectEvent(const Event& event); + + protected: + void run(); + virtual std::vector<Event> readEvents(); + static void startThread(Sensor* sensor); + + bool isWakeUpSensor(); + + bool mIsEnabled; + int64_t mSamplingPeriodNs; + int64_t mLastSampleTimeNs; + SensorInfo mSensorInfo; + + std::atomic_bool mStopThread; + std::condition_variable mWaitCV; + std::mutex mRunMutex; + std::thread mRunThread; + + ISensorsEventCallback* mCallback; + + OperationMode mMode; +}; + +class OnChangeSensor : public Sensor { + public: + OnChangeSensor(ISensorsEventCallback* callback); + + virtual void activate(bool enable) override; + + protected: + virtual std::vector<Event> readEvents() override; + + protected: + Event mPreviousEvent; + bool mPreviousEventSet; +}; + +class AccelSensor : public Sensor { + public: + AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class GyroSensor : public Sensor { + public: + GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class AmbientTempSensor : public OnChangeSensor { + public: + AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class DeviceTempSensor : public OnChangeSensor { + public: + DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class PressureSensor : public Sensor { + public: + PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class MagnetometerSensor : public Sensor { + public: + MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class LightSensor : public OnChangeSensor { + public: + LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class ProximitySensor : public OnChangeSensor { + public: + ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +class RelativeHumiditySensor : public OnChangeSensor { + public: + RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H diff --git a/sensors/2.0/default/Sensors.cpp b/sensors/2.0/default/Sensors.cpp new file mode 100644 index 0000000000..23dd26bccb --- /dev/null +++ b/sensors/2.0/default/Sensors.cpp @@ -0,0 +1,259 @@ +/* + * 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 "Sensors.h" + +#include <android/hardware/sensors/2.0/types.h> +#include <log/log.h> + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::sensors::V1_0::Event; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::RateLevel; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SharedMemInfo; +using ::android::hardware::sensors::V2_0::SensorTimeout; +using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits; + +constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP"; + +Sensors::Sensors() + : mEventQueueFlag(nullptr), + mNextHandle(1), + mOutstandingWakeUpEvents(0), + mReadWakeLockQueueRun(false), + mAutoReleaseWakeLockTime(0), + mHasWakeLock(false) { + AddSensor<AccelSensor>(); + AddSensor<GyroSensor>(); + AddSensor<AmbientTempSensor>(); + AddSensor<DeviceTempSensor>(); + AddSensor<PressureSensor>(); + AddSensor<MagnetometerSensor>(); + AddSensor<LightSensor>(); + AddSensor<ProximitySensor>(); + AddSensor<RelativeHumiditySensor>(); +} + +Sensors::~Sensors() { + deleteEventFlag(); + mReadWakeLockQueueRun = false; + mWakeLockThread.join(); +} + +// Methods from ::android::hardware::sensors::V2_0::ISensors follow. +Return<void> Sensors::getSensorsList(getSensorsList_cb _hidl_cb) { + std::vector<SensorInfo> sensors; + for (const auto& sensor : mSensors) { + sensors.push_back(sensor.second->getSensorInfo()); + } + + // Call the HIDL callback with the SensorInfo + _hidl_cb(sensors); + + return Void(); +} + +Return<Result> Sensors::setOperationMode(OperationMode mode) { + for (auto sensor : mSensors) { + sensor.second->setOperationMode(mode); + } + return Result::OK; +} + +Return<Result> Sensors::activate(int32_t sensorHandle, bool enabled) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + sensor->second->activate(enabled); + return Result::OK; + } + return Result::BAD_VALUE; +} + +Return<Result> Sensors::initialize( + const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor, + const sp<ISensorsCallback>& sensorsCallback) { + Result result = Result::OK; + + // Ensure that all sensors are disabled + for (auto sensor : mSensors) { + sensor.second->activate(false /* enable */); + } + + // Stop the Wake Lock thread if it is currently running + if (mReadWakeLockQueueRun.load()) { + mReadWakeLockQueueRun = false; + mWakeLockThread.join(); + } + + // Save a reference to the callback + mCallback = sensorsCallback; + + // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions. + mEventQueue = + std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */); + + // Ensure that any existing EventFlag is properly deleted + deleteEventFlag(); + + // Create the EventFlag that is used to signal to the framework that sensor events have been + // written to the Event FMQ + if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) { + result = Result::BAD_VALUE; + } + + // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP + // events have been successfully read and handled by the framework. + mWakeLockQueue = + std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */); + + if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) { + result = Result::BAD_VALUE; + } + + // Start the thread to read events from the Wake Lock FMQ + mReadWakeLockQueueRun = true; + mWakeLockThread = std::thread(startReadWakeLockThread, this); + + return result; +} + +Return<Result> Sensors::batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t /* maxReportLatencyNs */) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + sensor->second->batch(samplingPeriodNs); + return Result::OK; + } + return Result::BAD_VALUE; +} + +Return<Result> Sensors::flush(int32_t sensorHandle) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + return sensor->second->flush(); + } + return Result::BAD_VALUE; +} + +Return<Result> Sensors::injectSensorData(const Event& event) { + auto sensor = mSensors.find(event.sensorHandle); + if (sensor != mSensors.end()) { + return sensor->second->injectEvent(event); + } + + return Result::BAD_VALUE; +} + +Return<void> Sensors::registerDirectChannel(const SharedMemInfo& /* mem */, + registerDirectChannel_cb _hidl_cb) { + _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); + return Return<void>(); +} + +Return<Result> Sensors::unregisterDirectChannel(int32_t /* channelHandle */) { + return Result::INVALID_OPERATION; +} + +Return<void> Sensors::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */, + RateLevel /* rate */, configDirectReport_cb _hidl_cb) { + _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); + return Return<void>(); +} + +void Sensors::postEvents(const std::vector<Event>& events, bool wakeup) { + std::lock_guard<std::mutex> lock(mWriteLock); + if (mEventQueue->write(events.data(), events.size())) { + mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS)); + + if (wakeup) { + // Keep track of the number of outstanding WAKE_UP events in order to properly hold + // a wake lock until the framework has secured a wake lock + updateWakeLock(events.size(), 0 /* eventsHandled */); + } + } +} + +void Sensors::updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) { + std::lock_guard<std::mutex> lock(mWakeLockLock); + int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled; + if (newVal < 0) { + mOutstandingWakeUpEvents = 0; + } else { + mOutstandingWakeUpEvents = newVal; + } + + if (eventsWritten > 0) { + // Update the time at which the last WAKE_UP event was sent + mAutoReleaseWakeLockTime = ::android::uptimeMillis() + + static_cast<uint32_t>(SensorTimeout::WAKE_LOCK_SECONDS) * 1000; + } + + if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 && + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) { + mHasWakeLock = true; + } else if (mHasWakeLock) { + // Check if the wake lock should be released automatically if + // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written to + // the Wake Lock FMQ. + if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) { + ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock", + SensorTimeout::WAKE_LOCK_SECONDS); + mOutstandingWakeUpEvents = 0; + } + + if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) { + mHasWakeLock = false; + } + } +} + +void Sensors::readWakeLockFMQ() { + while (mReadWakeLockQueueRun.load()) { + constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000; // 500 ms + uint32_t eventsHandled = 0; + + // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to ensure + // that any held wake lock is able to be released if it is held for too long. + mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, 0 /* readNotification */, + static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), + kReadTimeoutNs); + updateWakeLock(0 /* eventsWritten */, eventsHandled); + } +} + +void Sensors::startReadWakeLockThread(Sensors* sensors) { + sensors->readWakeLockFMQ(); +} + +void Sensors::deleteEventFlag() { + status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag); + if (status != OK) { + ALOGI("Failed to delete event flag: %d", status); + } +} + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/2.0/default/Sensors.h b/sensors/2.0/default/Sensors.h new file mode 100644 index 0000000000..d06dd78dad --- /dev/null +++ b/sensors/2.0/default/Sensors.h @@ -0,0 +1,191 @@ +/* + * 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 ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H +#define ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H + +#include "Sensor.h" + +#include <android/hardware/sensors/2.0/ISensors.h> +#include <fmq/MessageQueue.h> +#include <hardware_legacy/power.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +#include <atomic> +#include <memory> +#include <thread> + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::EventFlag; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptor; +using ::android::hardware::Return; +using ::android::hardware::Void; + +struct Sensors : public ISensors, public ISensorsEventCallback { + using Event = ::android::hardware::sensors::V1_0::Event; + using OperationMode = ::android::hardware::sensors::V1_0::OperationMode; + using RateLevel = ::android::hardware::sensors::V1_0::RateLevel; + using Result = ::android::hardware::sensors::V1_0::Result; + using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; + + Sensors(); + virtual ~Sensors(); + + // Methods from ::android::hardware::sensors::V2_0::ISensors follow. + Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override; + + Return<Result> setOperationMode(OperationMode mode) override; + + Return<Result> activate(int32_t sensorHandle, bool enabled) override; + + Return<Result> initialize( + const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor, + const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor, + const sp<ISensorsCallback>& sensorsCallback) override; + + Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override; + + Return<Result> flush(int32_t sensorHandle) override; + + Return<Result> injectSensorData(const Event& event) override; + + Return<void> registerDirectChannel(const SharedMemInfo& mem, + registerDirectChannel_cb _hidl_cb) override; + + Return<Result> unregisterDirectChannel(int32_t channelHandle) override; + + Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + configDirectReport_cb _hidl_cb) override; + + void postEvents(const std::vector<Event>& events, bool wakeup) override; + + private: + /** + * Add a new sensor + */ + template <class SensorType> + void AddSensor() { + std::shared_ptr<SensorType> sensor = + std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */); + mSensors[sensor->getSensorInfo().sensorHandle] = sensor; + } + + /** + * Utility function to delete the Event Flag + */ + void deleteEventFlag(); + + /** + * Function to read the Wake Lock FMQ and release the wake lock when appropriate + */ + void readWakeLockFMQ(); + + static void startReadWakeLockThread(Sensors* sensors); + + /** + * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events + */ + void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled); + + using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>; + using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>; + + /** + * The Event FMQ where sensor events are written + */ + std::unique_ptr<EventMessageQueue> mEventQueue; + + /** + * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events + */ + std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue; + + /** + * Event Flag to signal to the framework when sensor events are available to be read + */ + EventFlag* mEventQueueFlag; + + /** + * Callback for asynchronous events, such as dynamic sensor connections. + */ + sp<ISensorsCallback> mCallback; + + /** + * A map of the available sensors + */ + std::map<int32_t, std::shared_ptr<Sensor>> mSensors; + + /** + * The next available sensor handle + */ + int32_t mNextHandle; + + /** + * Lock to protect writes to the FMQs + */ + std::mutex mWriteLock; + + /** + * Lock to protect acquiring and releasing the wake lock + */ + std::mutex mWakeLockLock; + + /** + * Track the number of WAKE_UP events that have not been handled by the framework + */ + uint32_t mOutstandingWakeUpEvents; + + /** + * A thread to read the Wake Lock FMQ + */ + std::thread mWakeLockThread; + + /** + * Flag to indicate that the Wake Lock Thread should continue to run + */ + std::atomic_bool mReadWakeLockQueueRun; + + /** + * Track the time when the wake lock should automatically be released + */ + int64_t mAutoReleaseWakeLockTime; + + /** + * Flag to indicate if a wake lock has been acquired + */ + bool mHasWakeLock; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H diff --git a/sensors/2.0/default/android.hardware.sensors@2.0-service.rc b/sensors/2.0/default/android.hardware.sensors@2.0-service.rc new file mode 100644 index 0000000000..321d760b0d --- /dev/null +++ b/sensors/2.0/default/android.hardware.sensors@2.0-service.rc @@ -0,0 +1,5 @@ +service vendor.sensors-hal-2-0 /vendor/bin/hw/android.hardware.sensors@2.0-service + class hal + user system + group system + rlimit rtprio 10 10 diff --git a/sensors/2.0/default/android.hardware.sensors@2.0.xml b/sensors/2.0/default/android.hardware.sensors@2.0.xml new file mode 100644 index 0000000000..1acc8e6113 --- /dev/null +++ b/sensors/2.0/default/android.hardware.sensors@2.0.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.sensors</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>ISensors</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/sensors/2.0/default/service.cpp b/sensors/2.0/default/service.cpp new file mode 100644 index 0000000000..5c13e331d0 --- /dev/null +++ b/sensors/2.0/default/service.cpp @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.sensors@2.0-service" + +#include <android/hardware/sensors/2.0/ISensors.h> +#include <hidl/HidlTransportSupport.h> +#include <log/log.h> +#include <utils/StrongPointer.h> +#include "Sensors.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::sensors::V2_0::ISensors; +using android::hardware::sensors::V2_0::implementation::Sensors; + +int main(int /* argc */, char** /* argv */) { + configureRpcThreadpool(1, true); + + android::sp<ISensors> sensors = new Sensors(); + if (sensors->registerAsService() != ::android::OK) { + ALOGE("Failed to register Sensors HAL instance"); + return -1; + } + + joinRpcThreadpool(); + return 1; // joinRpcThreadpool shouldn't exit +} diff --git a/sensors/2.0/types.hal b/sensors/2.0/types.hal new file mode 100644 index 0000000000..4457544875 --- /dev/null +++ b/sensors/2.0/types.hal @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package android.hardware.sensors@2.0; + +enum SensorTimeout : int32_t { + /** + * The maximum number of seconds to wait for a message on the Wake Lock FMQ + * before automatically releasing any wake_lock held for a WAKE_UP event. + */ + WAKE_LOCK_SECONDS = 1, +}; + +enum EventQueueFlagBits : uint32_t { + /** + * Used to notify the Event FMQ that events should be read and processed. + */ + READ_AND_PROCESS = 1 << 0, + + /** + * Used by the framework to signal to the HAL when events have been + * successfully read from the Event FMQ. + * + * If the MessageQueue::writeBlocking function is being used to write sensor + * events to the Event FMQ, then the readNotification parameter must be set + * to EVENTS_READ. + */ + EVENTS_READ = 1 << 1, +}; + +enum WakeLockQueueFlagBits : uint32_t { + /** + * Used to notify the HAL that the framework has written data to the Wake + * Lock FMQ. + */ + DATA_WRITTEN = 1 << 0, +}; diff --git a/audio/core/4.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp index 7ebb688772..8e8413c6a2 100644 --- a/audio/core/4.0/vts/functional/Android.bp +++ b/sensors/2.0/vts/functional/Android.bp @@ -1,5 +1,5 @@ // -// Copyright (C) 2017 The Android Open Source Project +// 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. @@ -15,26 +15,19 @@ // cc_test { - name: "VtsHalAudioV4_0TargetTest", + name: "VtsHalSensorsV2_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "AudioPrimaryHidlHalTest.cpp", - "ValidateAudioConfiguration.cpp" + "SensorsHidlEnvironmentV2_0.cpp", + "VtsHalSensorsV2_0TargetTest.cpp" ], static_libs: [ - "android.hardware.audio.common.test.utility", - "android.hardware.audio@4.0", - "android.hardware.audio.common@4.0", - "libicuuc", - "libicuuc_stubdata", - "libandroidicu", - "libxml2", - ], - shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.mapper@2.0", + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", "libfmq", + "VtsHalSensorsTargetTestUtils", ], - header_libs: [ - "android.hardware.audio.common.util@all-versions", - ], - test_suites: ["general-tests"], } + diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS new file mode 100644 index 0000000000..759d87b482 --- /dev/null +++ b/sensors/2.0/vts/functional/OWNERS @@ -0,0 +1,7 @@ +# Sensors team +bduddie@google.com +bstack@google.com + +# VTS team +trong@google.com +yim@google.com diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp new file mode 100644 index 0000000000..be7415bb7c --- /dev/null +++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp @@ -0,0 +1,153 @@ +/* + * 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 "SensorsHidlEnvironmentV2_0.h" + +#include <android/hardware/sensors/2.0/types.h> +#include <log/log.h> + +#include <algorithm> +#include <vector> + +using ::android::hardware::EventFlag; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SensorInfo; +using ::android::hardware::sensors::V2_0::EventQueueFlagBits; +using ::android::hardware::sensors::V2_0::ISensors; +using ::android::hardware::sensors::V2_0::ISensorsCallback; + +template <typename EnumType> +constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) { + return static_cast<typename std::underlying_type<EnumType>::type>(value); +} + +constexpr size_t SensorsHidlEnvironmentV2_0::MAX_RECEIVE_BUFFER_EVENT_COUNT; + +struct SensorsCallback : ISensorsCallback { + Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& /* sensorInfos */) { + return Return<void>(); + } + + Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& /* sensorHandles */) { + return Return<void>(); + } +}; + +bool SensorsHidlEnvironmentV2_0::resetHal() { + bool succeed = false; + do { + mSensors = ISensors::getService( + SensorsHidlEnvironmentV2_0::Instance()->getServiceName<ISensors>()); + if (mSensors == nullptr) { + break; + } + + // Initialize FMQs + mEventQueue = std::make_unique<EventMessageQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT, + true /* configureEventFlagWord */); + + mWakeLockQueue = std::make_unique<WakeLockQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT, + true /* configureEventFlagWord */); + + if (mEventQueue == nullptr || mWakeLockQueue == nullptr) { + break; + } + + EventFlag::deleteEventFlag(&mEventQueueFlag); + EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag); + if (mEventQueueFlag == nullptr) { + break; + } + + mSensors->initialize(*mEventQueue->getDesc(), *mWakeLockQueue->getDesc(), + new SensorsCallback()); + + std::vector<SensorInfo> sensorList; + if (!mSensors->getSensorsList([&](const hidl_vec<SensorInfo>& list) { sensorList = list; }) + .isOk()) { + break; + } + + // stop each sensor individually + bool ok = true; + for (const auto& i : sensorList) { + if (!mSensors->activate(i.sensorHandle, false).isOk()) { + ok = false; + break; + } + } + if (!ok) { + break; + } + + // mark it done + succeed = true; + } while (0); + + if (!succeed) { + mSensors = nullptr; + } + + return succeed; +} + +void SensorsHidlEnvironmentV2_0::HidlTearDown() { + mStopThread = true; + + // Wake up the event queue so the poll thread can exit + mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::READ_AND_PROCESS)); + mPollThread.join(); + + EventFlag::deleteEventFlag(&mEventQueueFlag); +} + +void SensorsHidlEnvironmentV2_0::startPollingThread() { + mStopThread = false; + mPollThread = std::thread(pollingThread, this); + mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT); +} + +void SensorsHidlEnvironmentV2_0::readEvents() { + size_t availableEvents = mEventQueue->availableToRead(); + + if (availableEvents == 0) { + uint32_t eventFlagState = 0; + + mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS), &eventFlagState); + availableEvents = mEventQueue->availableToRead(); + } + + size_t eventsToRead = std::min(availableEvents, mEventBuffer.size()); + if (eventsToRead > 0) { + if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) { + for (size_t i = 0; i < eventsToRead; i++) { + addEvent(mEventBuffer[i]); + } + } + } +} + +void SensorsHidlEnvironmentV2_0::pollingThread(SensorsHidlEnvironmentV2_0* env) { + ALOGD("polling thread start"); + + while (!env->mStopThread.load()) { + env->readEvents(); + } + + ALOGD("polling thread end"); +} diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h new file mode 100644 index 0000000000..5e54530917 --- /dev/null +++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h @@ -0,0 +1,125 @@ +/* + * 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 ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H +#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H + +#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h" + +#include <android/hardware/sensors/1.0/types.h> +#include <android/hardware/sensors/2.0/ISensors.h> +#include <fmq/MessageQueue.h> +#include <utils/StrongPointer.h> + +#include <array> +#include <atomic> +#include <memory> + +using ::android::sp; +using ::android::hardware::MessageQueue; + +class SensorsHidlTest; +class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase { + public: + using Event = ::android::hardware::sensors::V1_0::Event; + // get the test environment singleton + static SensorsHidlEnvironmentV2_0* Instance() { + static SensorsHidlEnvironmentV2_0* instance = new SensorsHidlEnvironmentV2_0(); + return instance; + } + + virtual void registerTestServices() override { + registerTestService<android::hardware::sensors::V2_0::ISensors>(); + } + + virtual void HidlTearDown() override; + + protected: + friend SensorsHidlTest; + + SensorsHidlEnvironmentV2_0() : mEventQueueFlag(nullptr) {} + + /** + * Resets the HAL with new FMQs and a new Event Flag + * + * @return bool true if successful, false otherwise + */ + bool resetHal() override; + + /** + * Starts the polling thread that reads sensor events from the Event FMQ + */ + void startPollingThread() override; + + /** + * Thread responsible for calling functions to read Event FMQ + * + * @param env SensorEnvironment to being polling for events on + */ + static void pollingThread(SensorsHidlEnvironmentV2_0* env); + + /** + * Reads and saves sensor events from the Event FMQ + */ + void readEvents(); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_0); + + /** + * Pointer to the Sensors HAL Interface that allows the test to call HAL functions. + */ + sp<android::hardware::sensors::V2_0::ISensors> mSensors; + + /** + * Type used to simplify the creation of the Event FMQ + */ + typedef MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite> EventMessageQueue; + + /** + * Type used to simplify the creation of the Wake Lock FMQ + */ + typedef MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite> WakeLockQueue; + + /** + * The Event FMQ where the test framework is able to read sensor events that the Sensors HAL + * has written. + */ + std::unique_ptr<EventMessageQueue> mEventQueue; + + /** + * The Wake Lock FMQ is used by the test to notify the Sensors HAL whenever it has processed + * WAKE_UP sensor events. + */ + std::unique_ptr<WakeLockQueue> mWakeLockQueue; + + /** + * The Event Queue Flag notifies the test framework when sensor events have been written to the + * Event FMQ by the Sensors HAL. + */ + ::android::hardware::EventFlag* mEventQueueFlag; + + /** + * The maximum number of sensor events that can be read from the Event FMQ at one time. + */ + static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 128; + + /** + * An array that is used to store sensor events read from the Event FMQ + */ + std::array<Event, MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer; +}; + +#endif // ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp new file mode 100644 index 0000000000..39053fe75f --- /dev/null +++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp @@ -0,0 +1,1048 @@ +/* + * 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. + */ + +#define LOG_TAG "sensors_hidl_hal_test" + +#include "SensorsHidlEnvironmentV2_0.h" +#include "sensors-vts-utils/SensorsHidlTestBase.h" +#include "sensors-vts-utils/SensorsTestSharedMemory.h" + +#include <android/hardware/sensors/2.0/ISensors.h> +#include <android/hardware/sensors/2.0/types.h> +#include <log/log.h> +#include <utils/SystemClock.h> + +#include <cinttypes> +#include <condition_variable> +#include <cstring> +#include <map> +#include <vector> + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::sensors::V1_0::MetaDataEventType; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset; +using ::android::hardware::sensors::V1_0::SensorStatus; +using ::android::hardware::sensors::V1_0::SharedMemType; +using ::android::hardware::sensors::V1_0::Vec3; + +constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH); + +class EventCallback : public IEventCallback { + public: + void reset() { + mFlushMap.clear(); + mEventMap.clear(); + } + + void onEvent(const ::android::hardware::sensors::V1_0::Event& event) override { + if (event.sensorType == SensorType::META_DATA && + event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) { + std::unique_lock<std::recursive_mutex> lock(mFlushMutex); + mFlushMap[event.sensorHandle]++; + mFlushCV.notify_all(); + } else if (event.sensorType != SensorType::ADDITIONAL_INFO) { + std::unique_lock<std::recursive_mutex> lock(mEventMutex); + mEventMap[event.sensorHandle].push_back(event); + mEventCV.notify_all(); + } + } + + int32_t getFlushCount(int32_t sensorHandle) { + std::unique_lock<std::recursive_mutex> lock(mFlushMutex); + return mFlushMap[sensorHandle]; + } + + void waitForFlushEvents(const std::vector<SensorInfo>& sensorsToWaitFor, + int32_t numCallsToFlush, int64_t timeoutMs) { + std::unique_lock<std::recursive_mutex> lock(mFlushMutex); + mFlushCV.wait_for(lock, std::chrono::milliseconds(timeoutMs), + [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); }); + } + + const std::vector<Event> getEvents(int32_t sensorHandle) { + std::unique_lock<std::recursive_mutex> lock(mEventMutex); + return mEventMap[sensorHandle]; + } + + void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t timeoutMs) { + std::unique_lock<std::recursive_mutex> lock(mEventMutex); + mEventCV.wait_for(lock, std::chrono::milliseconds(timeoutMs), + [&] { return eventsReceived(sensorsToWaitFor); }); + } + + protected: + bool flushesReceived(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t numCallsToFlush) { + for (const SensorInfo& sensor : sensorsToWaitFor) { + if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) { + return false; + } + } + return true; + } + + bool eventsReceived(const std::vector<SensorInfo>& sensorsToWaitFor) { + for (const SensorInfo& sensor : sensorsToWaitFor) { + if (getEvents(sensor.sensorHandle).size() == 0) { + return false; + } + } + return true; + } + + std::map<int32_t, int32_t> mFlushMap; + std::recursive_mutex mFlushMutex; + std::condition_variable_any mFlushCV; + + std::map<int32_t, std::vector<Event>> mEventMap; + std::recursive_mutex mEventMutex; + std::condition_variable_any mEventCV; +}; + +// The main test class for SENSORS HIDL HAL. + +class SensorsHidlTest : public SensorsHidlTestBase { + protected: + SensorInfo defaultSensorByType(SensorType type) override; + std::vector<SensorInfo> getSensorsList(); + // implementation wrapper + Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override { + return getSensors()->getSensorsList(_hidl_cb); + } + + Return<Result> activate(int32_t sensorHandle, bool enabled) override; + + Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) override { + return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return<Result> flush(int32_t sensorHandle) override { + return getSensors()->flush(sensorHandle); + } + + Return<Result> injectSensorData(const Event& event) override { + return getSensors()->injectSensorData(event); + } + + Return<void> registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) override; + + Return<Result> unregisterDirectChannel(int32_t channelHandle) override { + return getSensors()->unregisterDirectChannel(channelHandle); + } + + Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) override { + return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + inline sp<::android::hardware::sensors::V2_0::ISensors>& getSensors() { + return SensorsHidlEnvironmentV2_0::Instance()->mSensors; + } + + SensorsHidlEnvironmentBase* getEnvironment() override { + return SensorsHidlEnvironmentV2_0::Instance(); + } + + // Test helpers + void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor, + int32_t expectedFlushCount, Result expectedResponse); + void runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor, + int32_t flushCalls, int32_t expectedFlushCount, Result expectedResponse); + + // Helper functions + void activateAllSensors(bool enable); + std::vector<SensorInfo> getNonOneShotSensors(); + std::vector<SensorInfo> getOneShotSensors(); + std::vector<SensorInfo> getInjectEventSensors(); + int32_t getInvalidSensorHandle(); + bool getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, RateLevel* rate); + void verifyDirectChannel(SharedMemType memType); + void verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType, + std::shared_ptr<SensorsTestSharedMemory> mem, + int32_t* directChannelHandle); + void verifyConfigure(const SensorInfo& sensor, SharedMemType memType, + int32_t directChannelHandle); + void verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType, + int32_t directChannelHandle); + void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel); +}; + +Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) { + // If activating a sensor, add the handle in a set so that when test fails it can be turned off. + // The handle is not removed when it is deactivating on purpose so that it is not necessary to + // check the return value of deactivation. Deactivating a sensor more than once does not have + // negative effect. + if (enabled) { + mSensorHandles.insert(sensorHandle); + } + return getSensors()->activate(sensorHandle, enabled); +} + +Return<void> SensorsHidlTest::registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb cb) { + // If registeration of a channel succeeds, add the handle of channel to a set so that it can be + // unregistered when test fails. Unregister a channel does not remove the handle on purpose. + // Unregistering a channel more than once should not have negative effect. + getSensors()->registerDirectChannel(mem, [&](auto result, auto channelHandle) { + if (result == Result::OK) { + mDirectChannelHandles.insert(channelHandle); + } + cb(result, channelHandle); + }); + return Void(); +} + +SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) { + SensorInfo ret; + + ret.type = (SensorType)-1; + getSensors()->getSensorsList([&](const auto& list) { + const size_t count = list.size(); + for (size_t i = 0; i < count; ++i) { + if (list[i].type == type) { + ret = list[i]; + return; + } + } + }); + + return ret; +} + +std::vector<SensorInfo> SensorsHidlTest::getSensorsList() { + std::vector<SensorInfo> ret; + + getSensors()->getSensorsList([&](const auto& list) { + const size_t count = list.size(); + ret.reserve(list.size()); + for (size_t i = 0; i < count; ++i) { + ret.push_back(list[i]); + } + }); + + return ret; +} + +std::vector<SensorInfo> SensorsHidlTest::getNonOneShotSensors() { + std::vector<SensorInfo> sensors; + for (const SensorInfo& info : getSensorsList()) { + if (extractReportMode(info.flags) != SensorFlagBits::ONE_SHOT_MODE) { + sensors.push_back(info); + } + } + return sensors; +} + +std::vector<SensorInfo> SensorsHidlTest::getOneShotSensors() { + std::vector<SensorInfo> sensors; + for (const SensorInfo& info : getSensorsList()) { + if (extractReportMode(info.flags) == SensorFlagBits::ONE_SHOT_MODE) { + sensors.push_back(info); + } + } + return sensors; +} + +std::vector<SensorInfo> SensorsHidlTest::getInjectEventSensors() { + std::vector<SensorInfo> sensors; + for (const SensorInfo& info : getSensorsList()) { + if (info.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION)) { + sensors.push_back(info); + } + } + return sensors; +} + +int32_t SensorsHidlTest::getInvalidSensorHandle() { + // Find a sensor handle that does not exist in the sensor list + int32_t maxHandle = 0; + for (const SensorInfo& sensor : getSensorsList()) { + maxHandle = max(maxHandle, sensor.sensorHandle); + } + return maxHandle + 1; +} + +// Test if sensor list returned is valid +TEST_F(SensorsHidlTest, SensorListValid) { + getSensors()->getSensorsList([&](const auto& list) { + const size_t count = list.size(); + for (size_t i = 0; i < count; ++i) { + const auto& s = list[i]; + SCOPED_TRACE(::testing::Message() + << i << "/" << count << ": " + << " handle=0x" << std::hex << std::setw(8) << std::setfill('0') + << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type) + << " name=" << s.name); + + // Test non-empty type string + EXPECT_FALSE(s.typeAsString.empty()); + + // Test defined type matches defined string type + EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString)); + + // Test if all sensor has name and vendor + EXPECT_FALSE(s.name.empty()); + EXPECT_FALSE(s.vendor.empty()); + + // Test power > 0, maxRange > 0 + EXPECT_LE(0, s.power); + EXPECT_LT(0, s.maxRange); + + // Info type, should have no sensor + EXPECT_FALSE(s.type == SensorType::ADDITIONAL_INFO || s.type == SensorType::META_DATA); + + // Test fifoMax >= fifoReserved + EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount) + << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount; + + // Test Reporting mode valid + EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags))); + + // Test min max are in the right order + EXPECT_LE(s.minDelay, s.maxDelay); + // Test min/max delay matches reporting mode + EXPECT_NO_FATAL_FAILURE( + assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags))); + } + }); +} + +// Test that SetOperationMode returns the expected value +TEST_F(SensorsHidlTest, SetOperationMode) { + std::vector<SensorInfo> sensors = getInjectEventSensors(); + if (getInjectEventSensors().size() > 0) { + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); + } else { + ASSERT_EQ(Result::BAD_VALUE, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); + } +} + +// Test that an injected event is written back to the Event FMQ +TEST_F(SensorsHidlTest, InjectSensorEventData) { + std::vector<SensorInfo> sensors = getInjectEventSensors(); + if (sensors.size() == 0) { + return; + } + + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION)); + + EventCallback callback; + getEnvironment()->registerCallback(&callback); + + // AdditionalInfo event should not be sent to Event FMQ + Event additionalInfoEvent; + additionalInfoEvent.sensorType = SensorType::ADDITIONAL_INFO; + additionalInfoEvent.timestamp = android::elapsedRealtimeNano(); + + Event injectedEvent; + injectedEvent.timestamp = android::elapsedRealtimeNano(); + Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH}; + injectedEvent.u.vec3 = data; + + for (const auto& s : sensors) { + additionalInfoEvent.sensorHandle = s.sensorHandle; + EXPECT_EQ(Result::OK, getSensors()->injectSensorData(additionalInfoEvent)); + + injectedEvent.sensorType = s.type; + injectedEvent.sensorHandle = s.sensorHandle; + EXPECT_EQ(Result::OK, getSensors()->injectSensorData(injectedEvent)); + } + + // Wait for events to be written back to the Event FMQ + callback.waitForEvents(sensors, 1000 /* timeoutMs */); + + for (const auto& s : sensors) { + auto events = callback.getEvents(s.sensorHandle); + auto lastEvent = events.back(); + + // Verify that only a single event has been received + ASSERT_EQ(events.size(), 1); + + // Verify that the event received matches the event injected and is not the additional + // info event + ASSERT_EQ(lastEvent.sensorType, s.type); + ASSERT_EQ(lastEvent.sensorType, s.type); + ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp); + ASSERT_EQ(lastEvent.u.vec3.x, injectedEvent.u.vec3.x); + ASSERT_EQ(lastEvent.u.vec3.y, injectedEvent.u.vec3.y); + ASSERT_EQ(lastEvent.u.vec3.z, injectedEvent.u.vec3.z); + ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status); + } + + getEnvironment()->unregisterCallback(); + ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL)); +} + +// Test if sensor hal can do UI speed accelerometer streaming properly +TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) { + testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200), + std::chrono::seconds(5), sAccelNormChecker); +} + +// Test if sensor hal can do normal speed accelerometer streaming properly +TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) { + testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20), + std::chrono::seconds(5), sAccelNormChecker); +} + +// Test if sensor hal can do game speed accelerometer streaming properly +TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) { + testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5), + std::chrono::seconds(5), sAccelNormChecker); +} + +// Test if sensor hal can do UI speed gyroscope streaming properly +TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) { + testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200), + std::chrono::seconds(5), sGyroNormChecker); +} + +// Test if sensor hal can do normal speed gyroscope streaming properly +TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) { + testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20), + std::chrono::seconds(5), sGyroNormChecker); +} + +// Test if sensor hal can do game speed gyroscope streaming properly +TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) { + testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5), + std::chrono::seconds(5), sGyroNormChecker); +} + +// Test if sensor hal can do UI speed magnetometer streaming properly +TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) { + testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do normal speed magnetometer streaming properly +TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) { + testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do game speed magnetometer streaming properly +TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) { + testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5), + std::chrono::seconds(5), NullChecker()); +} + +// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active +TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER); + testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/); +} + +// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active +TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE); + testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/); +} + +// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active +TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) { + testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD); + testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/); +} + +// Test if sensor hal can do accelerometer batching properly +TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) { + testBatchingOperation(SensorType::ACCELEROMETER); +} + +// Test if sensor hal can do gyroscope batching properly +TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) { + testBatchingOperation(SensorType::GYROSCOPE); +} + +// Test if sensor hal can do magnetometer batching properly +TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) { + testBatchingOperation(SensorType::MAGNETIC_FIELD); +} + +// Test sensor event direct report with ashmem for accel sensor at normal rate +TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL, + sAccelNormChecker); +} + +// Test sensor event direct report with ashmem for accel sensor at fast rate +TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST, + sAccelNormChecker); +} + +// Test sensor event direct report with ashmem for accel sensor at very fast rate +TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, + RateLevel::VERY_FAST, sAccelNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at normal rate +TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL, + sGyroNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at fast rate +TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST, + sGyroNormChecker); +} + +// Test sensor event direct report with ashmem for gyro sensor at very fast rate +TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST, + sGyroNormChecker); +} + +// Test sensor event direct report with ashmem for mag sensor at normal rate +TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) { + testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL, + NullChecker()); +} + +// Test sensor event direct report with ashmem for mag sensor at fast rate +TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) { + testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST, + NullChecker()); +} + +// Test sensor event direct report with ashmem for mag sensor at very fast rate +TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) { + testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, + RateLevel::VERY_FAST, NullChecker()); +} + +// Test sensor event direct report with gralloc for accel sensor at normal rate +TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL, + sAccelNormChecker); +} + +// Test sensor event direct report with gralloc for accel sensor at fast rate +TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST, + sAccelNormChecker); +} + +// Test sensor event direct report with gralloc for accel sensor at very fast rate +TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, + RateLevel::VERY_FAST, sAccelNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at normal rate +TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL, + sGyroNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at fast rate +TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST, + sGyroNormChecker); +} + +// Test sensor event direct report with gralloc for gyro sensor at very fast rate +TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST, + sGyroNormChecker); +} + +// Test sensor event direct report with gralloc for mag sensor at normal rate +TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) { + testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL, + NullChecker()); +} + +// Test sensor event direct report with gralloc for mag sensor at fast rate +TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) { + testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST, + NullChecker()); +} + +// Test sensor event direct report with gralloc for mag sensor at very fast rate +TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) { + testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, + RateLevel::VERY_FAST, NullChecker()); +} + +void SensorsHidlTest::activateAllSensors(bool enable) { + for (const SensorInfo& sensorInfo : getSensorsList()) { + if (isValidType(sensorInfo.type)) { + batch(sensorInfo.sensorHandle, sensorInfo.minDelay, 0 /* maxReportLatencyNs */); + activate(sensorInfo.sensorHandle, enable); + } + } +} + +// Test that if initialize is called twice, then the HAL writes events to the FMQs from the second +// call to the function. +TEST_F(SensorsHidlTest, CallInitializeTwice) { + // Create a helper class so that a second environment is able to be instantiated + class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_0 {}; + + if (getSensorsList().size() == 0) { + // No sensors + return; + } + + constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s + constexpr int32_t kNumEvents = 1; + + // Create a new environment that calls initialize() + std::unique_ptr<SensorsHidlEnvironmentTest> newEnv = + std::make_unique<SensorsHidlEnvironmentTest>(); + newEnv->HidlSetUp(); + + activateAllSensors(true); + // Verify that the old environment does not receive any events + ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0); + // Verify that the new event queue receives sensor events + ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, newEnv.get()).size(), kNumEvents); + activateAllSensors(false); + + // Cleanup the test environment + newEnv->HidlTearDown(); + + // Restore the test environment for future tests + SensorsHidlEnvironmentV2_0::Instance()->HidlTearDown(); + SensorsHidlEnvironmentV2_0::Instance()->HidlSetUp(); + + // Ensure that the original environment is receiving events + activateAllSensors(true); + ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents); + activateAllSensors(false); +} + +TEST_F(SensorsHidlTest, CleanupConnectionsOnInitialize) { + activateAllSensors(true); + + // Verify that events are received + constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s + constexpr int32_t kNumEvents = 1; + ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents); + + // Clear the active sensor handles so they are not disabled during TearDown + auto handles = mSensorHandles; + mSensorHandles.clear(); + getEnvironment()->TearDown(); + getEnvironment()->SetUp(); + + // Verify no events are received until sensors are re-activated + ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0); + activateAllSensors(true); + ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents); + + // Disable sensors + activateAllSensors(false); + + // Restore active sensors prior to clearing the environment + mSensorHandles = handles; +} + +void SensorsHidlTest::runSingleFlushTest(const std::vector<SensorInfo>& sensors, + bool activateSensor, int32_t expectedFlushCount, + Result expectedResponse) { + runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResponse); +} + +void SensorsHidlTest::runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor, + int32_t flushCalls, int32_t expectedFlushCount, + Result expectedResponse) { + EventCallback callback; + getEnvironment()->registerCallback(&callback); + + for (const SensorInfo& sensor : sensors) { + // Configure and activate the sensor + batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */); + activate(sensor.sensorHandle, activateSensor); + + // Flush the sensor + for (int32_t i = 0; i < flushCalls; i++) { + Result flushResult = flush(sensor.sensorHandle); + ASSERT_EQ(flushResult, expectedResponse); + } + activate(sensor.sensorHandle, false); + } + + // Wait up to one second for the flush events + callback.waitForFlushEvents(sensors, flushCalls, 1000 /* timeoutMs */); + getEnvironment()->unregisterCallback(); + + // Check that the correct number of flushes are present for each sensor + for (const SensorInfo& sensor : sensors) { + ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount); + } +} + +TEST_F(SensorsHidlTest, FlushSensor) { + // Find a sensor that is not a one-shot sensor + std::vector<SensorInfo> sensors = getNonOneShotSensors(); + if (sensors.size() == 0) { + return; + } + + constexpr int32_t kFlushes = 5; + runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */, Result::OK); + runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK); +} + +TEST_F(SensorsHidlTest, FlushOneShotSensor) { + // Find a sensor that is a one-shot sensor + std::vector<SensorInfo> sensors = getOneShotSensors(); + if (sensors.size() == 0) { + return; + } + + runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */, + Result::BAD_VALUE); +} + +TEST_F(SensorsHidlTest, FlushInactiveSensor) { + // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary + std::vector<SensorInfo> sensors = getNonOneShotSensors(); + if (sensors.size() == 0) { + sensors = getOneShotSensors(); + if (sensors.size() == 0) { + return; + } + } + + runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */, + Result::BAD_VALUE); +} + +TEST_F(SensorsHidlTest, FlushNonexistentSensor) { + SensorInfo sensor; + std::vector<SensorInfo> sensors = getNonOneShotSensors(); + if (sensors.size() == 0) { + sensors = getOneShotSensors(); + if (sensors.size() == 0) { + return; + } + } + sensor = sensors.front(); + sensor.sensorHandle = getInvalidSensorHandle(); + runSingleFlushTest(std::vector<SensorInfo>{sensor}, false /* activateSensor */, + 0 /* expectedFlushCount */, Result::BAD_VALUE); +} + +TEST_F(SensorsHidlTest, Batch) { + if (getSensorsList().size() == 0) { + return; + } + + activateAllSensors(false /* enable */); + for (const SensorInfo& sensor : getSensorsList()) { + // Call batch on inactive sensor + ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */), + Result::OK); + + // Activate the sensor + activate(sensor.sensorHandle, true /* enabled */); + + // Call batch on an active sensor + ASSERT_EQ(batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */), + Result::OK); + } + activateAllSensors(false /* enable */); + + // Call batch on an invalid sensor + SensorInfo sensor = getSensorsList().front(); + sensor.sensorHandle = getInvalidSensorHandle(); + ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */), + Result::BAD_VALUE); +} + +TEST_F(SensorsHidlTest, Activate) { + if (getSensorsList().size() == 0) { + return; + } + + // Verify that sensor events are generated when activate is called + for (const SensorInfo& sensor : getSensorsList()) { + batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */); + ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK); + + // Call activate on a sensor that is already activated + ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK); + + // Deactivate the sensor + ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK); + + // Call deactivate on a sensor that is already deactivated + ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK); + } + + // Attempt to activate an invalid sensor + int32_t invalidHandle = getInvalidSensorHandle(); + ASSERT_EQ(activate(invalidHandle, true), Result::BAD_VALUE); + ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE); +} + +TEST_F(SensorsHidlTest, NoStaleEvents) { + constexpr int64_t kFiveHundredMilliseconds = 500 * 1000; + constexpr int64_t kOneSecond = 1000 * 1000; + + // Register the callback to receive sensor events + EventCallback callback; + getEnvironment()->registerCallback(&callback); + + const std::vector<SensorInfo> sensors = getSensorsList(); + int32_t maxMinDelay = 0; + for (const SensorInfo& sensor : getSensorsList()) { + maxMinDelay = std::max(maxMinDelay, sensor.minDelay); + } + + // Activate the sensors so that they start generating events + activateAllSensors(true); + + // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time + // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount + // of time to guarantee that a sample has arrived. + callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay)); + activateAllSensors(false); + + // Save the last received event for each sensor + std::map<int32_t, int64_t> lastEventTimestampMap; + for (const SensorInfo& sensor : sensors) { + ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1); + lastEventTimestampMap[sensor.sensorHandle] = + callback.getEvents(sensor.sensorHandle).back().timestamp; + } + + // Allow some time to pass, reset the callback, then reactivate the sensors + usleep(kOneSecond + (5 * maxMinDelay)); + callback.reset(); + activateAllSensors(true); + callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay)); + activateAllSensors(false); + + for (const SensorInfo& sensor : sensors) { + // Ensure that the first event received is not stale by ensuring that its timestamp is + // sufficiently different from the previous event + const Event newEvent = callback.getEvents(sensor.sensorHandle).front(); + int64_t delta = newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]; + ASSERT_GE(delta, kFiveHundredMilliseconds + (3 * sensor.minDelay)); + } + + getEnvironment()->unregisterCallback(); +} + +void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, + RateLevel rateLevel) { + configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel, + [&](Result result, int32_t reportToken) { + if (isDirectReportRateSupported(sensor, rateLevel)) { + ASSERT_EQ(result, Result::OK); + ASSERT_GT(reportToken, 0); + } else { + ASSERT_EQ(result, Result::BAD_VALUE); + } + }); +} + +void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType, + std::shared_ptr<SensorsTestSharedMemory> mem, + int32_t* directChannelHandle) { + char* buffer = mem->getBuffer(); + memset(buffer, 0xff, mem->getSize()); + + registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) { + if (isDirectChannelTypeSupported(sensor, memType)) { + ASSERT_EQ(result, Result::OK); + ASSERT_GT(channelHandle, 0); + + // Verify that the memory has been zeroed + for (size_t i = 0; i < mem->getSize(); i++) { + ASSERT_EQ(buffer[i], 0x00); + } + } else { + ASSERT_EQ(result, Result::INVALID_OPERATION); + ASSERT_EQ(channelHandle, -1); + } + *directChannelHandle = channelHandle; + }); +} + +void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType, + int32_t directChannelHandle) { + if (isDirectChannelTypeSupported(sensor, memType)) { + // Verify that each rate level is properly supported + checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL); + checkRateLevel(sensor, directChannelHandle, RateLevel::FAST); + checkRateLevel(sensor, directChannelHandle, RateLevel::VERY_FAST); + checkRateLevel(sensor, directChannelHandle, RateLevel::STOP); + + // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP + configDirectReport( + -1 /* sensorHandle */, directChannelHandle, RateLevel::NORMAL, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); }); + configDirectReport( + -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); }); + } else { + // Direct channel is not supported for this SharedMemType + configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL, + [](Result result, int32_t /* reportToken */) { + ASSERT_EQ(result, Result::INVALID_OPERATION); + }); + } +} + +void SensorsHidlTest::verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType, + int32_t directChannelHandle) { + Result result = unregisterDirectChannel(directChannelHandle); + if (isDirectChannelTypeSupported(sensor, memType)) { + ASSERT_EQ(result, Result::OK); + } else { + ASSERT_EQ(result, Result::INVALID_OPERATION); + } +} + +void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) { + constexpr size_t kNumEvents = 1; + constexpr size_t kMemSize = kNumEvents * kEventSize; + + std::shared_ptr<SensorsTestSharedMemory> mem( + SensorsTestSharedMemory::create(memType, kMemSize)); + ASSERT_NE(mem, nullptr); + + for (const SensorInfo& sensor : getSensorsList()) { + int32_t directChannelHandle = 0; + verifyRegisterDirectChannel(sensor, memType, mem, &directChannelHandle); + verifyConfigure(sensor, memType, directChannelHandle); + verifyUnregisterDirectChannel(sensor, memType, directChannelHandle); + } +} + +TEST_F(SensorsHidlTest, DirectChannelAshmem) { + verifyDirectChannel(SharedMemType::ASHMEM); +} + +TEST_F(SensorsHidlTest, DirectChannelGralloc) { + verifyDirectChannel(SharedMemType::GRALLOC); +} + +bool SensorsHidlTest::getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, + RateLevel* rate) { + bool found = false; + for (const SensorInfo& curSensor : getSensorsList()) { + if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM)) { + *memType = SharedMemType::ASHMEM; + *sensor = curSensor; + found = true; + break; + } else if (isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) { + *memType = SharedMemType::GRALLOC; + *sensor = curSensor; + found = true; + break; + } + } + + if (found) { + // Find a supported rate level + constexpr int kNumRateLevels = 3; + RateLevel rates[kNumRateLevels] = {RateLevel::NORMAL, RateLevel::FAST, + RateLevel::VERY_FAST}; + *rate = RateLevel::STOP; + for (int i = 0; i < kNumRateLevels; i++) { + if (isDirectReportRateSupported(*sensor, rates[i])) { + *rate = rates[i]; + } + } + + // At least one rate level must be supported + EXPECT_NE(*rate, RateLevel::STOP); + } + return found; +} + +TEST_F(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) { + SensorInfo sensor; + SharedMemType memType; + RateLevel rate; + if (!getDirectChannelSensor(&sensor, &memType, &rate)) { + return; + } + + // Verify that an invalid channel handle produces a BAD_VALUE result + configDirectReport(sensor.sensorHandle, -1, rate, [](Result result, int32_t /* reportToken */) { + ASSERT_EQ(result, Result::BAD_VALUE); + }); +} + +TEST_F(SensorsHidlTest, CleanupDirectConnectionOnInitialize) { + constexpr size_t kNumEvents = 1; + constexpr size_t kMemSize = kNumEvents * kEventSize; + + SensorInfo sensor; + SharedMemType memType; + RateLevel rate; + + if (!getDirectChannelSensor(&sensor, &memType, &rate)) { + return; + } + + std::shared_ptr<SensorsTestSharedMemory> mem( + SensorsTestSharedMemory::create(memType, kMemSize)); + ASSERT_NE(mem, nullptr); + + int32_t directChannelHandle = 0; + registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) { + ASSERT_EQ(result, Result::OK); + directChannelHandle = channelHandle; + }); + + // Configure the channel and expect success + configDirectReport( + sensor.sensorHandle, directChannelHandle, rate, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); }); + + // Call initialize() via the environment setup to cause the HAL to re-initialize + // Clear the active direct connections so they are not stopped during TearDown + auto handles = mDirectChannelHandles; + mDirectChannelHandles.clear(); + getEnvironment()->TearDown(); + getEnvironment()->SetUp(); + + // Attempt to configure the direct channel and expect it to fail + configDirectReport( + sensor.sensorHandle, directChannelHandle, rate, + [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); }); + + // Restore original handles, though they should already be deactivated + mDirectChannelHandles = handles; +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV2_0::Instance()); + ::testing::InitGoogleTest(&argc, argv); + SensorsHidlEnvironmentV2_0::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} +// vim: set ts=2 sw=2 diff --git a/sensors/common/vts/OWNERS b/sensors/common/vts/OWNERS new file mode 100644 index 0000000000..759d87b482 --- /dev/null +++ b/sensors/common/vts/OWNERS @@ -0,0 +1,7 @@ +# Sensors team +bduddie@google.com +bstack@google.com + +# VTS team +trong@google.com +yim@google.com diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp new file mode 100644 index 0000000000..95df4259e7 --- /dev/null +++ b/sensors/common/vts/utils/Android.bp @@ -0,0 +1,37 @@ +// +// 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. +// + +cc_library_static { + name: "VtsHalSensorsTargetTestUtils", + srcs: [ + "GrallocWrapper.cpp", + "SensorsHidlEnvironmentBase.cpp", + "SensorsHidlTestBase.cpp", + "SensorsTestSharedMemory.cpp", + ], + export_include_dirs: [ + "include", + ], + local_include_dirs: [ + "include/sensors-vts-utils", + ], + static_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.mapper@2.0", + "android.hardware.sensors@1.0", + "VtsHalHidlTargetTestBase", + ], +} diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp new file mode 100644 index 0000000000..7bed16d6c4 --- /dev/null +++ b/sensors/common/vts/utils/GrallocWrapper.cpp @@ -0,0 +1,224 @@ +/* + * 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. + */ + +#define LOG_TAG "GrallocWrapper" + +#include "GrallocWrapper.h" + +#include <utils/Log.h> + +namespace android { + +GrallocWrapper::GrallocWrapper() { + init(); +} + +void GrallocWrapper::init() { + mAllocator = allocator2::IAllocator::getService(); + if (mAllocator == nullptr) { + ALOGE("Failed to get allocator service"); + } + + mMapper = mapper2::IMapper::getService(); + if (mMapper == nullptr) { + ALOGE("Failed to get mapper service"); + } + if (mMapper->isRemote()) { + ALOGE("Mapper is not in passthrough mode"); + } +} + +GrallocWrapper::~GrallocWrapper() { + for (auto bufferHandle : mClonedBuffers) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + native_handle_close(buffer); + native_handle_delete(buffer); + } + mClonedBuffers.clear(); + + for (auto bufferHandle : mImportedBuffers) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) { + ALOGE("Failed to free buffer %p", buffer); + } + } + mImportedBuffers.clear(); +} + +sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const { + return mAllocator; +} + +std::string GrallocWrapper::dumpDebugInfo() { + std::string debugInfo; + mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); + + return debugInfo; +} + +const native_handle_t* GrallocWrapper::cloneBuffer(const hardware::hidl_handle& rawHandle) { + const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle()); + + if (bufferHandle) { + mClonedBuffers.insert(bufferHandle); + } + return bufferHandle; +} + +std::vector<const native_handle_t*> GrallocWrapper::allocate( + const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import, uint32_t* outStride) { + std::vector<const native_handle_t*> bufferHandles; + bufferHandles.reserve(count); + mAllocator->allocate(descriptor, count, + [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) { + if (mapper2::Error::NONE != tmpError) { + ALOGE("Failed to allocate buffers"); + } + if (count != tmpBuffers.size()) { + ALOGE("Invalid buffer array"); + } + + for (uint32_t i = 0; i < count; i++) { + if (import) { + bufferHandles.push_back(importBuffer(tmpBuffers[i])); + } else { + bufferHandles.push_back(cloneBuffer(tmpBuffers[i])); + } + } + + if (outStride) { + *outStride = tmpStride; + } + }); + + return bufferHandles; +} + +const native_handle_t* GrallocWrapper::allocate( + const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import, + uint32_t* outStride) { + mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo); + auto buffers = allocate(descriptor, 1, import, outStride); + return buffers[0]; +} + +sp<mapper2::IMapper> GrallocWrapper::getMapper() const { + return mMapper; +} + +mapper2::BufferDescriptor GrallocWrapper::createDescriptor( + const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) { + mapper2::BufferDescriptor descriptor; + mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) { + if (tmpError != mapper2::Error::NONE) { + ALOGE("Failed to create descriptor"); + } + descriptor = tmpDescriptor; + }); + + return descriptor; +} + +const native_handle_t* GrallocWrapper::importBuffer(const hardware::hidl_handle& rawHandle) { + const native_handle_t* bufferHandle = nullptr; + mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) { + if (tmpError != mapper2::Error::NONE) { + ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle()); + } + bufferHandle = static_cast<const native_handle_t*>(tmpBuffer); + }); + + if (bufferHandle) { + mImportedBuffers.insert(bufferHandle); + } + + return bufferHandle; +} + +void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + if (mImportedBuffers.erase(bufferHandle)) { + mapper2::Error error = mMapper->freeBuffer(buffer); + if (error != mapper2::Error::NONE) { + ALOGE("Failed to free %p", buffer); + } + } else { + mClonedBuffers.erase(bufferHandle); + native_handle_close(buffer); + native_handle_delete(buffer); + } +} + +void* GrallocWrapper::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const mapper2::IMapper::Rect& accessRegion, int acquireFence) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); + hardware::hidl_handle acquireFenceHandle; + if (acquireFence >= 0) { + auto h = native_handle_init(acquireFenceStorage, 1, 0); + h->data[0] = acquireFence; + acquireFenceHandle = h; + } + + void* data = nullptr; + mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpData) { + if (tmpError != mapper2::Error::NONE) { + ALOGE("Failed to lock buffer %p", buffer); + } + data = tmpData; + }); + + if (acquireFence >= 0) { + close(acquireFence); + } + + return data; +} + +int GrallocWrapper::unlock(const native_handle_t* bufferHandle) { + auto buffer = const_cast<native_handle_t*>(bufferHandle); + + int releaseFence = -1; + mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) { + if (tmpError != mapper2::Error::NONE) { + ALOGE("Failed to unlock buffer %p", buffer); + } + + auto fenceHandle = tmpReleaseFence.getNativeHandle(); + if (fenceHandle) { + if (fenceHandle->numInts != 0) { + ALOGE("Invalid fence handle %p", fenceHandle); + } + if (fenceHandle->numFds == 1) { + releaseFence = dup(fenceHandle->data[0]); + if (releaseFence < 0) { + ALOGE("Failed to dup fence fd"); + } + } else { + if (fenceHandle->numFds != 0) { + ALOGE("Invalid fence handle %p", fenceHandle); + } + } + } + }); + + return releaseFence; +} + +} // namespace android diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS new file mode 100644 index 0000000000..759d87b482 --- /dev/null +++ b/sensors/common/vts/utils/OWNERS @@ -0,0 +1,7 @@ +# Sensors team +bduddie@google.com +bstack@google.com + +# VTS team +trong@google.com +yim@google.com diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp new file mode 100644 index 0000000000..affdf8b6b3 --- /dev/null +++ b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp @@ -0,0 +1,67 @@ +/* + * 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 "SensorsHidlEnvironmentBase.h" + +void SensorsHidlEnvironmentBase::HidlSetUp() { + ASSERT_TRUE(resetHal()) << "could not get hidl service"; + + mCollectionEnabled = false; + startPollingThread(); + + // In case framework just stopped for test and there is sensor events in the pipe, + // wait some time for those events to be cleared to avoid them messing up the test. + std::this_thread::sleep_for(std::chrono::seconds(3)); +} + +void SensorsHidlEnvironmentBase::HidlTearDown() { + mStopThread = true; + mPollThread.detach(); +} + +void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) { + std::lock_guard<std::mutex> lock(mEventsMutex); + if (output) { + output->insert(output->end(), mEvents.begin(), mEvents.end()); + } + mEvents.clear(); +} + +void SensorsHidlEnvironmentBase::setCollection(bool enable) { + std::lock_guard<std::mutex> lock(mEventsMutex); + mCollectionEnabled = enable; +} + +void SensorsHidlEnvironmentBase::addEvent(const Event& ev) { + std::lock_guard<std::mutex> lock(mEventsMutex); + if (mCollectionEnabled) { + mEvents.push_back(ev); + } + + if (mCallback != nullptr) { + mCallback->onEvent(ev); + } +} + +void SensorsHidlEnvironmentBase::registerCallback(IEventCallback* callback) { + std::lock_guard<std::mutex> lock(mEventsMutex); + mCallback = callback; +} + +void SensorsHidlEnvironmentBase::unregisterCallback() { + std::lock_guard<std::mutex> lock(mEventsMutex); + mCallback = nullptr; +}
\ No newline at end of file diff --git a/sensors/common/vts/utils/SensorsHidlTestBase.cpp b/sensors/common/vts/utils/SensorsHidlTestBase.cpp new file mode 100644 index 0000000000..18549dfb17 --- /dev/null +++ b/sensors/common/vts/utils/SensorsHidlTestBase.cpp @@ -0,0 +1,584 @@ +/* + * 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 "SensorsHidlTestBase.h" + +#include "sensors-vts-utils/GrallocWrapper.h" +#include "sensors-vts-utils/SensorsTestSharedMemory.h" + +#include <hardware/sensors.h> // for sensor type strings +#include <log/log.h> +#include <utils/SystemClock.h> + +#include <cinttypes> + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::sensors::V1_0::SensorFlagShift; +using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset; + +const Vec3NormChecker SensorsHidlTestBase::sAccelNormChecker( + Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f /*m/s^2*/)); +const Vec3NormChecker SensorsHidlTestBase::sGyroNormChecker( + Vec3NormChecker::byNominal(0.f, 0.1f /*rad/s*/)); + +std::vector<Event> SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit, + bool clearBeforeStart, + bool changeCollection) { + return collectEvents(timeLimitUs, nEventLimit, getEnvironment(), clearBeforeStart, + changeCollection); +} + +std::vector<Event> SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit, + SensorsHidlEnvironmentBase* environment, + bool clearBeforeStart, + bool changeCollection) { + std::vector<Event> events; + constexpr useconds_t SLEEP_GRANULARITY = 100 * 1000; // granularity 100 ms + + ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", nEventLimit, timeLimitUs, + clearBeforeStart); + + if (changeCollection) { + environment->setCollection(true); + } + if (clearBeforeStart) { + environment->catEvents(nullptr); + } + + while (timeLimitUs > 0) { + useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs); + usleep(duration); + timeLimitUs -= duration; + + environment->catEvents(&events); + if (events.size() >= nEventLimit) { + break; + } + ALOGV("time to go = %d, events to go = %d", (int)timeLimitUs, + (int)(nEventLimit - events.size())); + } + + if (changeCollection) { + environment->setCollection(false); + } + return events; +} + +void SensorsHidlTestBase::assertTypeMatchStringType(SensorType type, + const hidl_string& stringType) { + if (type >= SensorType::DEVICE_PRIVATE_BASE) { + return; + } + + switch (type) { +#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \ + case SensorType::type: \ + ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \ + break; + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE); + default: + FAIL() << "Type " << static_cast<int>(type) + << " in android defined range is not checked, " + << "stringType = " << stringType; +#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE + } +} + +void SensorsHidlTestBase::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) { + if (type >= SensorType::DEVICE_PRIVATE_BASE) { + return; + } + + SensorFlagBits expected = expectedReportModeForType(type); + + ASSERT_TRUE(expected == (SensorFlagBits)-1 || expected == reportMode) + << "reportMode=" << static_cast<int>(reportMode) + << "expected=" << static_cast<int>(expected); +} + +void SensorsHidlTestBase::assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay, + SensorFlagBits reportMode) { + switch (reportMode) { + case SensorFlagBits::CONTINUOUS_MODE: + ASSERT_LT(0, minDelay); + ASSERT_LE(0, maxDelay); + break; + case SensorFlagBits::ON_CHANGE_MODE: + ASSERT_LE(0, minDelay); + ASSERT_LE(0, maxDelay); + break; + case SensorFlagBits::ONE_SHOT_MODE: + ASSERT_EQ(-1, minDelay); + ASSERT_EQ(0, maxDelay); + break; + case SensorFlagBits::SPECIAL_REPORTING_MODE: + // do not enforce anything for special reporting mode + break; + default: + FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked"; + } +} + +// return -1 means no expectation for this type +SensorFlagBits SensorsHidlTestBase::expectedReportModeForType(SensorType type) { + switch (type) { + case SensorType::ACCELEROMETER: + case SensorType::ACCELEROMETER_UNCALIBRATED: + case SensorType::GYROSCOPE: + case SensorType::MAGNETIC_FIELD: + case SensorType::ORIENTATION: + case SensorType::PRESSURE: + case SensorType::TEMPERATURE: + case SensorType::GRAVITY: + case SensorType::LINEAR_ACCELERATION: + case SensorType::ROTATION_VECTOR: + case SensorType::MAGNETIC_FIELD_UNCALIBRATED: + case SensorType::GAME_ROTATION_VECTOR: + case SensorType::GYROSCOPE_UNCALIBRATED: + case SensorType::GEOMAGNETIC_ROTATION_VECTOR: + case SensorType::POSE_6DOF: + case SensorType::HEART_BEAT: + return SensorFlagBits::CONTINUOUS_MODE; + + case SensorType::LIGHT: + case SensorType::PROXIMITY: + case SensorType::RELATIVE_HUMIDITY: + case SensorType::AMBIENT_TEMPERATURE: + case SensorType::HEART_RATE: + case SensorType::DEVICE_ORIENTATION: + case SensorType::STEP_COUNTER: + case SensorType::LOW_LATENCY_OFFBODY_DETECT: + return SensorFlagBits::ON_CHANGE_MODE; + + case SensorType::SIGNIFICANT_MOTION: + case SensorType::WAKE_GESTURE: + case SensorType::GLANCE_GESTURE: + case SensorType::PICK_UP_GESTURE: + case SensorType::MOTION_DETECT: + case SensorType::STATIONARY_DETECT: + return SensorFlagBits::ONE_SHOT_MODE; + + case SensorType::STEP_DETECTOR: + case SensorType::TILT_DETECTOR: + case SensorType::WRIST_TILT_GESTURE: + case SensorType::DYNAMIC_SENSOR_META: + return SensorFlagBits::SPECIAL_REPORTING_MODE; + + default: + ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type); + return (SensorFlagBits)-1; + } +} + +bool SensorsHidlTestBase::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) { + unsigned int r = static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT) >> + static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT); + return r >= static_cast<unsigned int>(rate); +} + +bool SensorsHidlTestBase::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) { + switch (type) { + case SharedMemType::ASHMEM: + return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0; + case SharedMemType::GRALLOC: + return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0; + default: + return false; + } +} + +void SensorsHidlTestBase::testDirectReportOperation(SensorType type, SharedMemType memType, + RateLevel rate, + const SensorEventsChecker& checker) { + constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH); + constexpr size_t kNEvent = 4096; + constexpr size_t kMemSize = kEventSize * kNEvent; + + constexpr float kNormalNominal = 50; + constexpr float kFastNominal = 200; + constexpr float kVeryFastNominal = 800; + + constexpr float kNominalTestTimeSec = 1.f; + constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization + + SensorInfo sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + if (!isDirectReportRateSupported(sensor, rate)) { + return; + } + + if (!isDirectChannelTypeSupported(sensor, memType)) { + return; + } + + std::unique_ptr<SensorsTestSharedMemory> mem( + SensorsTestSharedMemory::create(memType, kMemSize)); + ASSERT_NE(mem, nullptr); + + char* buffer = mem->getBuffer(); + // fill memory with data + for (size_t i = 0; i < kMemSize; ++i) { + buffer[i] = '\xcc'; + } + + int32_t channelHandle; + registerDirectChannel(mem->getSharedMemInfo(), + [&channelHandle](auto result, auto channelHandle_) { + ASSERT_EQ(result, Result::OK); + channelHandle = channelHandle_; + }); + + // check memory is zeroed + for (size_t i = 0; i < kMemSize; ++i) { + ASSERT_EQ(buffer[i], '\0'); + } + + int32_t eventToken; + configDirectReport(sensor.sensorHandle, channelHandle, rate, + [&eventToken](auto result, auto token) { + ASSERT_EQ(result, Result::OK); + eventToken = token; + }); + + usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f)); + auto events = mem->parseEvents(); + + // find norminal rate + float nominalFreq = 0.f; + switch (rate) { + case RateLevel::NORMAL: + nominalFreq = kNormalNominal; + break; + case RateLevel::FAST: + nominalFreq = kFastNominal; + break; + case RateLevel::VERY_FAST: + nominalFreq = kVeryFastNominal; + break; + case RateLevel::STOP: + FAIL(); + } + + // allowed to be between 55% and 220% of nominal freq + ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec)); + ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec)); + + int64_t lastTimestamp = 0; + bool typeErrorReported = false; + bool tokenErrorReported = false; + bool timestampErrorReported = false; + std::vector<Event> sensorEvents; + for (auto& e : events) { + if (!tokenErrorReported) { + EXPECT_EQ(eventToken, e.sensorHandle) + << (tokenErrorReported = true, + "Event token does not match that retured from configDirectReport"); + } + + if (isMetaSensorType(e.sensorType)) { + continue; + } + sensorEvents.push_back(e); + + if (!typeErrorReported) { + EXPECT_EQ(type, e.sensorType) + << (typeErrorReported = true, + "Type in event does not match type of sensor registered."); + } + if (!timestampErrorReported) { + EXPECT_GT(e.timestamp, lastTimestamp) + << (timestampErrorReported = true, "Timestamp not monotonically increasing"); + } + lastTimestamp = e.timestamp; + } + + std::string s; + EXPECT_TRUE(checker.check(sensorEvents, &s)) << s; + + // stop sensor and unregister channel + configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP, + [](auto result, auto) { EXPECT_EQ(result, Result::OK); }); + EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK); +} + +void SensorsHidlTestBase::testStreamingOperation(SensorType type, + std::chrono::nanoseconds samplingPeriod, + std::chrono::seconds duration, + const SensorEventsChecker& checker) { + std::vector<Event> events; + std::vector<Event> sensorEvents; + + const int64_t samplingPeriodInNs = samplingPeriod.count(); + const int64_t batchingPeriodInNs = 0; // no batching + const useconds_t minTimeUs = std::chrono::microseconds(duration).count(); + const size_t minNEvent = duration / samplingPeriod; + + SensorInfo sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) { + // rate not supported + return; + } + + int32_t handle = sensor.sensorHandle; + + ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/); + ASSERT_EQ(activate(handle, 0), Result::OK); + + ALOGI("Collected %zu samples", events.size()); + + ASSERT_GT(events.size(), 0u); + + bool handleMismatchReported = false; + bool metaSensorTypeErrorReported = false; + for (auto& e : events) { + if (e.sensorType == type) { + // avoid generating hundreds of error + if (!handleMismatchReported) { + EXPECT_EQ(e.sensorHandle, handle) + << (handleMismatchReported = true, + "Event of the same type must come from the sensor registered"); + } + sensorEvents.push_back(e); + } else { + // avoid generating hundreds of error + if (!metaSensorTypeErrorReported) { + EXPECT_TRUE(isMetaSensorType(e.sensorType)) + << (metaSensorTypeErrorReported = true, + "Only meta types are allowed besides the type registered"); + } + } + } + + std::string s; + EXPECT_TRUE(checker.check(sensorEvents, &s)) << s; + + EXPECT_GE(sensorEvents.size(), + minNEvent / 2); // make sure returned events are not all meta +} + +void SensorsHidlTestBase::testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow) { + std::vector<Event> events1, events2; + + constexpr int64_t batchingPeriodInNs = 0; // no batching + constexpr int64_t collectionTimeoutUs = 60000000; // 60s + constexpr size_t minNEvent = 50; + + SensorInfo sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + int32_t handle = sensor.sensorHandle; + int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; + int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll; + + if (minSamplingPeriodInNs == maxSamplingPeriodInNs) { + // only support single rate + return; + } + + int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs; + int64_t secondCollectionPeriod = !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs; + + // first collection + ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for change rate to happen + events1 = collectEvents(collectionTimeoutUs, minNEvent); + + // second collection, without stop sensor + ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for change rate to happen + events2 = collectEvents(collectionTimeoutUs, minNEvent); + + // end of collection, stop sensor + ASSERT_EQ(activate(handle, 0), Result::OK); + + ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size()); + + ASSERT_GT(events1.size(), 0u); + ASSERT_GT(events2.size(), 0u); + + int64_t minDelayAverageInterval, maxDelayAverageInterval; + std::vector<Event>& minDelayEvents(fastToSlow ? events1 : events2); + std::vector<Event>& maxDelayEvents(fastToSlow ? events2 : events1); + + size_t nEvent = 0; + int64_t prevTimestamp = -1; + int64_t timestampInterval = 0; + for (auto& e : minDelayEvents) { + if (e.sensorType == type) { + ASSERT_EQ(e.sensorHandle, handle); + if (prevTimestamp > 0) { + timestampInterval += e.timestamp - prevTimestamp; + } + prevTimestamp = e.timestamp; + ++nEvent; + } + } + ASSERT_GT(nEvent, 2u); + minDelayAverageInterval = timestampInterval / (nEvent - 1); + + nEvent = 0; + prevTimestamp = -1; + timestampInterval = 0; + for (auto& e : maxDelayEvents) { + if (e.sensorType == type) { + ASSERT_EQ(e.sensorHandle, handle); + if (prevTimestamp > 0) { + timestampInterval += e.timestamp - prevTimestamp; + } + prevTimestamp = e.timestamp; + ++nEvent; + } + } + ASSERT_GT(nEvent, 2u); + maxDelayAverageInterval = timestampInterval / (nEvent - 1); + + // change of rate is significant. + ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64, minDelayAverageInterval, + maxDelayAverageInterval); + EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10); + + // fastest rate sampling time is close to spec + EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs), + minSamplingPeriodInNs / 10); + + // slowest rate sampling time is close to spec + EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs), + maxSamplingPeriodInNs / 10); +} + +void SensorsHidlTestBase::testBatchingOperation(SensorType type) { + std::vector<Event> events; + + constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000; + constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000; + + SensorInfo sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + int32_t handle = sensor.sensorHandle; + int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; + uint32_t minFifoCount = sensor.fifoReservedEventCount; + int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs; + + if (batchingPeriodInNs < oneSecondInNs) { + // batching size too small to test reliably + return; + } + + batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs); + + ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000)); + + int64_t allowedBatchDeliverTimeNs = std::max(oneSecondInNs, batchingPeriodInNs / 10); + + ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for initialization + ASSERT_EQ(flush(handle), Result::OK); + + // wait for 80% of the reserved batching period + // there should not be any significant amount of events + // since collection is not enabled all events will go down the drain + usleep(batchingPeriodInNs / 1000 * 8 / 10); + + getEnvironment()->setCollection(true); + // clean existing collections + collectEvents(0 /*timeLimitUs*/, 0 /*nEventLimit*/, true /*clearBeforeStart*/, + false /*change collection*/); + + // 0.8 + 0.2 times the batching period + usleep(batchingPeriodInNs / 1000 * 8 / 10); + ASSERT_EQ(flush(handle), Result::OK); + + // plus some time for the event to deliver + events = collectEvents(allowedBatchDeliverTimeNs / 1000, minFifoCount, + false /*clearBeforeStart*/, false /*change collection*/); + + getEnvironment()->setCollection(false); + ASSERT_EQ(activate(handle, 0), Result::OK); + + size_t nEvent = 0; + for (auto& e : events) { + if (e.sensorType == type && e.sensorHandle == handle) { + ++nEvent; + } + } + + // at least reach 90% of advertised capacity + ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10)); +} diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp new file mode 100644 index 0000000000..819e2974f7 --- /dev/null +++ b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp @@ -0,0 +1,210 @@ +/* + * 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 "SensorsTestSharedMemory.h" + +#include <log/log.h> + +#include <sys/mman.h> +#include <cinttypes> + +using namespace ::android::hardware::sensors::V1_0; + +SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const { + SharedMemInfo mem = {.type = mType, + .format = SharedMemFormat::SENSORS_EVENT, + .size = static_cast<uint32_t>(mSize), + .memoryHandle = mNativeHandle}; + return mem; +} + +char* SensorsTestSharedMemory::getBuffer() const { + return mBuffer; +} + +size_t SensorsTestSharedMemory::getSize() const { + return mSize; +} + +std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const { + constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH); + constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD); + constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN); + constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE); + constexpr size_t kOffsetAtomicCounter = + static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER); + constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP); + constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA); + + std::vector<Event> events; + std::vector<float> data(16); + + while (offset + kEventSize <= mSize) { + int64_t atomicCounter = + *reinterpret_cast<uint32_t*>(mBuffer + offset + kOffsetAtomicCounter); + if (atomicCounter <= lastCounter) { + ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter, + lastCounter); + break; + } + + int32_t size = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetSize); + if (size != kEventSize) { + // unknown error, events parsed may be wrong, remove all + events.clear(); + break; + } + + int32_t token = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetToken); + int32_t type = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetType); + int64_t timestamp = *reinterpret_cast<int64_t*>(mBuffer + offset + kOffsetTimestamp); + + ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32 + ", timestamp %" PRId64, + offset, atomicCounter, token, type, timestamp); + + Event event = { + .timestamp = timestamp, + .sensorHandle = token, + .sensorType = static_cast<SensorType>(type), + }; + event.u.data = android::hardware::hidl_array<float, 16>( + reinterpret_cast<float*>(mBuffer + offset + kOffsetData)); + + events.push_back(event); + + lastCounter = atomicCounter; + offset += kEventSize; + } + + return events; +} + +SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size) + : mType(type), mSize(0), mBuffer(nullptr) { + native_handle_t* handle = nullptr; + char* buffer = nullptr; + switch (type) { + case SharedMemType::ASHMEM: { + int fd; + handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/); + if (handle != nullptr) { + handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size); + if (handle->data[0] > 0) { + // memory is pinned by default + buffer = static_cast<char*>( + ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + if (buffer != reinterpret_cast<char*>(MAP_FAILED)) { + break; + } + ::native_handle_close(handle); + } + ::native_handle_delete(handle); + handle = nullptr; + } + break; + } + case SharedMemType::GRALLOC: { + mGrallocWrapper = std::make_unique<::android::GrallocWrapper>(); + if (mGrallocWrapper->getAllocator() == nullptr || + mGrallocWrapper->getMapper() == nullptr) { + break; + } + using android::hardware::graphics::common::V1_0::BufferUsage; + using android::hardware::graphics::common::V1_0::PixelFormat; + mapper2::IMapper::BufferDescriptorInfo buf_desc_info = { + .width = static_cast<uint32_t>(size), + .height = 1, + .layerCount = 1, + .usage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | + BufferUsage::CPU_READ_OFTEN), + .format = PixelFormat::BLOB}; + + handle = const_cast<native_handle_t*>(mGrallocWrapper->allocate(buf_desc_info)); + if (handle != nullptr) { + mapper2::IMapper::Rect region{0, 0, static_cast<int32_t>(buf_desc_info.width), + static_cast<int32_t>(buf_desc_info.height)}; + buffer = static_cast<char*>( + mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1)); + if (buffer != nullptr) { + break; + } + mGrallocWrapper->freeBuffer(handle); + handle = nullptr; + } + break; + } + default: + break; + } + + if (buffer != nullptr) { + mNativeHandle = handle; + mSize = size; + mBuffer = buffer; + } +} + +SensorsTestSharedMemory::~SensorsTestSharedMemory() { + switch (mType) { + case SharedMemType::ASHMEM: { + if (mSize != 0) { + ::munmap(mBuffer, mSize); + mBuffer = nullptr; + + ::native_handle_close(mNativeHandle); + ::native_handle_delete(mNativeHandle); + + mNativeHandle = nullptr; + mSize = 0; + } + break; + } + case SharedMemType::GRALLOC: { + if (mSize != 0) { + mGrallocWrapper->unlock(mNativeHandle); + mGrallocWrapper->freeBuffer(mNativeHandle); + + mNativeHandle = nullptr; + mSize = 0; + } + break; + } + default: { + if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) { + ALOGE( + "SensorsTestSharedMemory %p not properly destructed: " + "type %d, native handle %p, size %zu, buffer %p", + this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer); + } + break; + } + } +} + +SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) { + constexpr size_t kMaxSize = 128 * 1024 * 1024; // sensor test should not need more than 128M + if (size == 0 || size >= kMaxSize) { + return nullptr; + } + + auto m = new SensorsTestSharedMemory(type, size); + if (m->mSize != size || m->mBuffer == nullptr) { + delete m; + m = nullptr; + } + return m; +} diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h new file mode 100644 index 0000000000..3bd73c36e0 --- /dev/null +++ b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h @@ -0,0 +1,79 @@ +/* + * 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 GRALLO_WRAPPER_H_ +#define GRALLO_WRAPPER_H_ + +#include <unordered_set> + +#include <android/hardware/graphics/allocator/2.0/IAllocator.h> +#include <android/hardware/graphics/mapper/2.0/IMapper.h> + +namespace allocator2 = ::android::hardware::graphics::allocator::V2_0; +namespace mapper2 = ::android::hardware::graphics::mapper::V2_0; + +namespace android { + +// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/ +class GrallocWrapper { + public: + GrallocWrapper(); + ~GrallocWrapper(); + + sp<allocator2::IAllocator> getAllocator() const; + sp<mapper2::IMapper> getMapper() const; + + std::string dumpDebugInfo(); + + // When import is false, this simply calls IAllocator::allocate. When import + // is true, the returned buffers are also imported into the mapper. + // + // Either case, the returned buffers must be freed with freeBuffer. + std::vector<const native_handle_t*> allocate(const mapper2::BufferDescriptor& descriptor, + uint32_t count, bool import = true, + uint32_t* outStride = nullptr); + const native_handle_t* allocate(const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, + bool import = true, uint32_t* outStride = nullptr); + + mapper2::BufferDescriptor createDescriptor( + const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo); + + const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle); + void freeBuffer(const native_handle_t* bufferHandle); + + // We use fd instead of hardware::hidl_handle in these functions to pass fences + // in and out of the mapper. The ownership of the fd is always transferred + // with each of these functions. + void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const mapper2::IMapper::Rect& accessRegion, int acquireFence); + + int unlock(const native_handle_t* bufferHandle); + + private: + void init(); + const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle); + + sp<allocator2::IAllocator> mAllocator; + sp<mapper2::IMapper> mMapper; + + // Keep track of all cloned and imported handles. When a test fails with + // ASSERT_*, the destructor will free the handles for the test. + std::unordered_set<const native_handle_t*> mClonedBuffers; + std::unordered_set<const native_handle_t*> mImportedBuffers; +}; + +} // namespace android +#endif // GRALLO_WRAPPER_H_ diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h new file mode 100644 index 0000000000..b5daccc987 --- /dev/null +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h @@ -0,0 +1,78 @@ +/* + * 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 ANDROID_SENSOR_EVENTS_CHECKER_H +#define ANDROID_SENSOR_EVENTS_CHECKER_H + +#include <android/hardware/sensors/1.0/types.h> + +#include <cmath> + +class SensorEventsChecker { + public: + using Event = ::android::hardware::sensors::V1_0::Event; + virtual bool check(const std::vector<Event>& events, std::string* out) const = 0; + virtual ~SensorEventsChecker() {} +}; + +class NullChecker : public SensorEventsChecker { + public: + virtual bool check(const std::vector<Event>&, std::string*) const { return true; } +}; + +class SensorEventPerEventChecker : public SensorEventsChecker { + public: + virtual bool checkEvent(const Event& event, std::string* out) const = 0; + virtual bool check(const std::vector<Event>& events, std::string* out) const { + for (const auto& e : events) { + if (!checkEvent(e, out)) { + return false; + } + } + return true; + } +}; + +class Vec3NormChecker : public SensorEventPerEventChecker { + public: + Vec3NormChecker(float min, float max) : mLowerLimit(min), mUpperLimit(max) {} + static Vec3NormChecker byNominal(float nominal, float allowedError) { + return Vec3NormChecker(nominal - allowedError, nominal + allowedError); + } + + virtual bool checkEvent(const Event& event, std::string* out) const { + android::hardware::sensors::V1_0::Vec3 v = event.u.vec3; + float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z); + if (norm < mLowerLimit || norm > mUpperLimit) { + if (out != nullptr) { + std::ostringstream ss; + ss << "Event @ " << event.timestamp << " (" << v.x << ", " << v.y << ", " << v.z + << ")" + << " has norm " << norm << ", which is beyond range" + << " [" << mLowerLimit << ", " << mUpperLimit << "]"; + *out = ss.str(); + } + return false; + } + return true; + } + + protected: + float mLowerLimit; + float mUpperLimit; +}; + +#endif // ANDROID_SENSOR_EVENTS_CHECKER_H
\ No newline at end of file diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h new file mode 100644 index 0000000000..6499fba54e --- /dev/null +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h @@ -0,0 +1,71 @@ +/* + * 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 ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H +#define ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H + +#include <VtsHalHidlTargetTestEnvBase.h> + +#include <android/hardware/sensors/1.0/types.h> + +#include <atomic> +#include <memory> +#include <mutex> +#include <thread> +#include <vector> + +class IEventCallback { + public: + virtual ~IEventCallback() = default; + virtual void onEvent(const ::android::hardware::sensors::V1_0::Event& event) = 0; +}; + +class SensorsHidlEnvironmentBase : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + using Event = ::android::hardware::sensors::V1_0::Event; + virtual void HidlSetUp() override; + virtual void HidlTearDown() override; + + // Get and clear all events collected so far (like "cat" shell command). + // If output is nullptr, it clears all collected events. + void catEvents(std::vector<Event>* output); + + // set sensor event collection status + void setCollection(bool enable); + + void registerCallback(IEventCallback* callback); + void unregisterCallback(); + + protected: + SensorsHidlEnvironmentBase() : mCollectionEnabled(false), mCallback(nullptr) {} + + void addEvent(const Event& ev); + + virtual void startPollingThread() = 0; + virtual bool resetHal() = 0; + + bool mCollectionEnabled; + std::atomic_bool mStopThread; + std::thread mPollThread; + std::vector<Event> mEvents; + std::mutex mEventsMutex; + + IEventCallback* mCallback; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase); +}; + +#endif // ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
\ No newline at end of file diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h new file mode 100644 index 0000000000..6fd9a2b5de --- /dev/null +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h @@ -0,0 +1,132 @@ +/* + * 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 ANDROID_SENSORS_HIDL_TEST_BASE_H +#define ANDROID_SENSORS_HIDL_TEST_BASE_H + +#include "sensors-vts-utils/SensorEventsChecker.h" +#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h" + +#include <VtsHalHidlTargetTestBase.h> +#include <android/hardware/sensors/1.0/ISensors.h> +#include <android/hardware/sensors/1.0/types.h> + +#include <unordered_set> +#include <vector> + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::android::hardware::Void; + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::sensors::V1_0::Event; +using ::android::hardware::sensors::V1_0::ISensors; +using ::android::hardware::sensors::V1_0::RateLevel; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SensorFlagBits; +using ::android::hardware::sensors::V1_0::SensorInfo; +using ::android::hardware::sensors::V1_0::SensorType; +using ::android::hardware::sensors::V1_0::SharedMemInfo; +using ::android::hardware::sensors::V1_0::SharedMemType; + +class SensorsHidlTestBase : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual SensorsHidlEnvironmentBase* getEnvironment() = 0; + virtual void SetUp() override {} + + virtual void TearDown() override { + // stop all sensors + for (auto s : mSensorHandles) { + activate(s, false); + } + mSensorHandles.clear(); + + // stop all direct report and channels + for (auto c : mDirectChannelHandles) { + // disable all reports + configDirectReport(-1, c, RateLevel::STOP, [](auto, auto) {}); + unregisterDirectChannel(c); + } + mDirectChannelHandles.clear(); + } + + // implementation wrapper + virtual SensorInfo defaultSensorByType(SensorType type) = 0; + virtual Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) = 0; + + virtual Return<Result> activate(int32_t sensorHandle, bool enabled) = 0; + + virtual Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) = 0; + + virtual Return<Result> flush(int32_t sensorHandle) = 0; + virtual Return<Result> injectSensorData(const Event& event) = 0; + virtual Return<void> registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb) = 0; + virtual Return<Result> unregisterDirectChannel(int32_t channelHandle) = 0; + virtual Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, + RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) = 0; + + std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit, + bool clearBeforeStart = true, bool changeCollection = true); + static std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit, + SensorsHidlEnvironmentBase* environment, + bool clearBeforeStart = true, + bool changeCollection = true); + + inline static SensorFlagBits extractReportMode(uint64_t flag) { + return (SensorFlagBits)(flag & ((uint64_t)SensorFlagBits::CONTINUOUS_MODE | + (uint64_t)SensorFlagBits::ON_CHANGE_MODE | + (uint64_t)SensorFlagBits::ONE_SHOT_MODE | + (uint64_t)SensorFlagBits::SPECIAL_REPORTING_MODE)); + } + + inline static bool isMetaSensorType(SensorType type) { + return (type == SensorType::META_DATA || type == SensorType::DYNAMIC_SENSOR_META || + type == SensorType::ADDITIONAL_INFO); + } + + inline static bool isValidType(SensorType type) { return (int32_t)type > 0; } + + void testStreamingOperation(SensorType type, std::chrono::nanoseconds samplingPeriod, + std::chrono::seconds duration, const SensorEventsChecker& checker); + void testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow = true); + void testBatchingOperation(SensorType type); + void testDirectReportOperation(SensorType type, SharedMemType memType, RateLevel rate, + const SensorEventsChecker& checker); + + static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType); + static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode); + static void assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay, + SensorFlagBits reportMode); + static SensorFlagBits expectedReportModeForType(SensorType type); + static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate); + static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type); + + protected: + // checkers + static const Vec3NormChecker sAccelNormChecker; + static const Vec3NormChecker sGyroNormChecker; + + // all sensors and direct channnels used + std::unordered_set<int32_t> mSensorHandles; + std::unordered_set<int32_t> mDirectChannelHandles; +}; + +#endif // ANDROID_SENSORS_HIDL_TEST_BASE_H
\ No newline at end of file diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h new file mode 100644 index 0000000000..002f42c112 --- /dev/null +++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h @@ -0,0 +1,52 @@ +/* + * 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 ANDROID_SENSORS_TEST_SHARED_MEMORY_H +#define ANDROID_SENSORS_TEST_SHARED_MEMORY_H + +#include "GrallocWrapper.h" + +#include <android-base/macros.h> +#include <android/hardware/sensors/1.0/types.h> + +#include <cutils/ashmem.h> + +class SensorsTestSharedMemory { + using SharedMemType = ::android::hardware::sensors::V1_0::SharedMemType; + using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; + using Event = ::android::hardware::sensors::V1_0::Event; + + public: + static SensorsTestSharedMemory* create(SharedMemType type, size_t size); + SharedMemInfo getSharedMemInfo() const; + char* getBuffer() const; + size_t getSize() const; + std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const; + virtual ~SensorsTestSharedMemory(); + + private: + SensorsTestSharedMemory(SharedMemType type, size_t size); + + SharedMemType mType; + native_handle_t* mNativeHandle; + size_t mSize; + char* mBuffer; + std::unique_ptr<::android::GrallocWrapper> mGrallocWrapper; + + DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory); +}; + +#endif // ANDROID_SENSORS_TEST_SHARED_MEMORY_H diff --git a/soundtrigger/2.2/Android.bp b/soundtrigger/2.2/Android.bp new file mode 100644 index 0000000000..0a7c2d80ba --- /dev/null +++ b/soundtrigger/2.2/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.soundtrigger@2.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "ISoundTriggerHw.hal", + ], + interfaces: [ + "android.hardware.audio.common@2.0", + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.1", + "android.hidl.base@1.0", + ], + gen_java: false, +} + diff --git a/soundtrigger/2.2/ISoundTriggerHw.hal b/soundtrigger/2.2/ISoundTriggerHw.hal new file mode 100644 index 0000000000..a26896a0f4 --- /dev/null +++ b/soundtrigger/2.2/ISoundTriggerHw.hal @@ -0,0 +1,42 @@ +/* + * Copyright 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. + */ + +package android.hardware.soundtrigger@2.2; + +import @2.0::SoundModelHandle; +import @2.1::ISoundTriggerHw; + +/** + * SoundTrigger HAL interface. Used for hardware recognition of hotwords + * and other sounds. + */ +interface ISoundTriggerHw extends @2.1::ISoundTriggerHw { + + /** + * Get the state of a given model. + * The model state is returned asynchronously as a RecognitionEvent via + * the callback that was registered in StartRecognition(). + * @param modelHandle The handle of the sound model whose state is being + * queried. + * @return retval Operation completion status: 0 in case of success, + * -ENOSYS in case of invalid model handle, + * -ENOMEM in case of memory allocation failure, + * -ENODEV in case of initialization error, + * -EINVAL in case where a recognition event is already + * being processed. + */ + getModelState(SoundModelHandle modelHandle) generates (int32_t retval); +}; diff --git a/soundtrigger/2.2/default/Android.bp b/soundtrigger/2.2/default/Android.bp new file mode 100644 index 0000000000..78bb69f33e --- /dev/null +++ b/soundtrigger/2.2/default/Android.bp @@ -0,0 +1,37 @@ +// +// 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. + +cc_library_shared { + name: "android.hardware.soundtrigger@2.2-impl", + relative_install_path: "hw", + vendor: true, + srcs: [ + "SoundTriggerHw.cpp", + ], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "liblog", + "libhidlmemory", + "libutils", + "libhardware", + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.0-core", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + ], +} diff --git a/soundtrigger/2.2/default/SoundTriggerHw.cpp b/soundtrigger/2.2/default/SoundTriggerHw.cpp new file mode 100644 index 0000000000..4586544406 --- /dev/null +++ b/soundtrigger/2.2/default/SoundTriggerHw.cpp @@ -0,0 +1,730 @@ +/* + * 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. + */ + +#define LOG_TAG "SoundTriggerHw" + +#include "SoundTriggerHw.h" + +#include <android/hidl/allocator/1.0/IAllocator.h> +#include <android/log.h> +#include <hidlmemory/mapping.h> +#include <utility> + +using android::hardware::hidl_memory; +using android::hidl::allocator::V1_0::IAllocator; +using android::hidl::memory::V1_0::IMemory; + +namespace android { +namespace hardware { +namespace soundtrigger { +namespace V2_2 { +namespace implementation { + +/** + * According to the HIDL C++ Users Guide: client and server implementations + * should never directly refer to anything other than the interface header + * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so + * this V2_2 implementation copies the V2_0 and V2_1 implementations and + * then adds the new V2_2 implementation. + */ + +// Begin V2_0 implementation, copied from +// hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp + +// static +void soundModelCallback_(struct sound_trigger_model_event* halEvent, void* cookie) { + if (halEvent == NULL) { + ALOGW("soundModelCallback called with NULL event"); + return; + } + sp<SoundTriggerHw::SoundModelClient> client = + wp<SoundTriggerHw::SoundModelClient>(static_cast<SoundTriggerHw::SoundModelClient*>(cookie)) + .promote(); + if (client == 0) { + ALOGW("soundModelCallback called on stale client"); + return; + } + if (halEvent->model != client->getHalHandle()) { + ALOGW("soundModelCallback call with wrong handle %d on client with handle %d", + (int)halEvent->model, (int)client->getHalHandle()); + return; + } + + client->soundModelCallback(halEvent); +} + +// static +void recognitionCallback_(struct sound_trigger_recognition_event* halEvent, void* cookie) { + if (halEvent == NULL) { + ALOGW("recognitionCallback call NULL event"); + return; + } + sp<SoundTriggerHw::SoundModelClient> client = + wp<SoundTriggerHw::SoundModelClient>(static_cast<SoundTriggerHw::SoundModelClient*>(cookie)) + .promote(); + if (client == 0) { + ALOGW("recognitionCallback called on stale client"); + return; + } + + client->recognitionCallback(halEvent); +} + +Return<void> SoundTriggerHw::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) { + ALOGV("getProperties() mHwDevice %p", mHwDevice); + int ret; + struct sound_trigger_properties halProperties; + ISoundTriggerHw::Properties properties; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + ret = mHwDevice->get_properties(mHwDevice, &halProperties); + + convertPropertiesFromHal(&properties, &halProperties); + + ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(), + properties.recognitionModes); + +exit: + _hidl_cb(ret, properties); + return Void(); +} + +int SoundTriggerHw::doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + sp<SoundTriggerHw::SoundModelClient> client) { + int32_t ret = 0; + struct sound_trigger_sound_model* halSoundModel; + + ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size()); + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + halSoundModel = convertSoundModelToHal(&soundModel); + if (halSoundModel == NULL) { + ret = -EINVAL; + goto exit; + } + + sound_model_handle_t halHandle; + ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback_, client.get(), + &halHandle); + + free(halSoundModel); + + if (ret != 0) { + goto exit; + } + + client->setHalHandle(halHandle); + { + AutoMutex lock(mLock); + mClients.add(client->getId(), client); + } + +exit: + return ret; +} + +Return<void> SoundTriggerHw::loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + const sp<V2_0::ISoundTriggerHwCallback>& callback, + V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + ISoundTriggerHw::loadSoundModel_cb _hidl_cb) { + sp<SoundTriggerHw::SoundModelClient> client = + new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel(soundModel, client), client->getId()); + return Void(); +} + +Return<void> SoundTriggerHw::loadPhraseSoundModel( + const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<V2_0::ISoundTriggerHwCallback>& callback, + V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) { + sp<SoundTriggerHw::SoundModelClient> client = + new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel, client), + client->getId()); + return Void(); +} + +Return<int32_t> SoundTriggerHw::unloadSoundModel(int32_t modelHandle) { + int32_t ret; + sp<SoundTriggerHw::SoundModelClient> client; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle()); + + mClients.removeItem(modelHandle); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHw::startRecognition( + int32_t modelHandle, const V2_0::ISoundTriggerHw::RecognitionConfig& config, + const sp<V2_0::ISoundTriggerHwCallback>& /* callback */, int32_t /* cookie */) { + int32_t ret; + sp<SoundTriggerHw::SoundModelClient> client; + struct sound_trigger_recognition_config* halConfig; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + halConfig = + convertRecognitionConfigToHal((const V2_0::ISoundTriggerHw::RecognitionConfig*)&config); + + if (halConfig == NULL) { + ret = -EINVAL; + goto exit; + } + ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig, + recognitionCallback_, client.get()); + + free(halConfig); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHw::stopRecognition(int32_t modelHandle) { + int32_t ret; + sp<SoundTriggerHw::SoundModelClient> client; + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle()); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHw::stopAllRecognitions() { + int32_t ret; + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 && + mHwDevice->stop_all_recognitions) { + ret = mHwDevice->stop_all_recognitions(mHwDevice); + } else { + ret = -ENOSYS; + } +exit: + return ret; +} + +SoundTriggerHw::SoundTriggerHw() : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {} + +void SoundTriggerHw::onFirstRef() { + const hw_module_t* mod; + int rc; + + rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod); + if (rc != 0) { + ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID, + mModuleName, strerror(-rc)); + return; + } + rc = sound_trigger_hw_device_open(mod, &mHwDevice); + if (rc != 0) { + ALOGE("couldn't open sound trigger hw device in %s.%s (%s)", + SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc)); + mHwDevice = NULL; + return; + } + if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 || + mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) { + ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version); + sound_trigger_hw_device_close(mHwDevice); + mHwDevice = NULL; + return; + } + + ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice); +} + +SoundTriggerHw::~SoundTriggerHw() { + if (mHwDevice != NULL) { + sound_trigger_hw_device_close(mHwDevice); + } +} + +uint32_t SoundTriggerHw::nextUniqueModelId() { + uint32_t modelId = 0; + { + AutoMutex lock(mLock); + do { + modelId = + atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1, memory_order_acq_rel); + } while (mClients.valueFor(modelId) != 0 && modelId != 0); + } + LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu", + mClients.size()); + return modelId; +} + +void SoundTriggerHw::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) { + uuid->timeLow = halUuid->timeLow; + uuid->timeMid = halUuid->timeMid; + uuid->versionAndTimeHigh = halUuid->timeHiAndVersion; + uuid->variantAndClockSeqHigh = halUuid->clockSeq; + memcpy(&uuid->node[0], &halUuid->node[0], 6); +} + +void SoundTriggerHw::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) { + halUuid->timeLow = uuid->timeLow; + halUuid->timeMid = uuid->timeMid; + halUuid->timeHiAndVersion = uuid->versionAndTimeHigh; + halUuid->clockSeq = uuid->variantAndClockSeqHigh; + memcpy(&halUuid->node[0], &uuid->node[0], 6); +} + +void SoundTriggerHw::convertPropertiesFromHal( + ISoundTriggerHw::Properties* properties, const struct sound_trigger_properties* halProperties) { + properties->implementor = halProperties->implementor; + properties->description = halProperties->description; + properties->version = halProperties->version; + convertUuidFromHal(&properties->uuid, &halProperties->uuid); + properties->maxSoundModels = halProperties->max_sound_models; + properties->maxKeyPhrases = halProperties->max_key_phrases; + properties->maxUsers = halProperties->max_users; + properties->recognitionModes = halProperties->recognition_modes; + properties->captureTransition = halProperties->capture_transition; + properties->maxBufferMs = halProperties->max_buffer_ms; + properties->concurrentCapture = halProperties->concurrent_capture; + properties->triggerInEvent = halProperties->trigger_in_event; + properties->powerConsumptionMw = halProperties->power_consumption_mw; +} + +void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase, + const ISoundTriggerHw::Phrase* triggerPhrase) { + halTriggerPhrase->id = triggerPhrase->id; + halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes; + unsigned int i; + + halTriggerPhrase->num_users = + std::min((int)triggerPhrase->users.size(), SOUND_TRIGGER_MAX_USERS); + for (i = 0; i < halTriggerPhrase->num_users; i++) { + halTriggerPhrase->users[i] = triggerPhrase->users[i]; + } + + strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN); + strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN); +} + +struct sound_trigger_sound_model* SoundTriggerHw::convertSoundModelToHal( + const V2_0::ISoundTriggerHw::SoundModel* soundModel) { + struct sound_trigger_sound_model* halModel = NULL; + if (soundModel->type == V2_0::SoundModelType::KEYPHRASE) { + size_t allocSize = + sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size(); + struct sound_trigger_phrase_sound_model* halKeyPhraseModel = + static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL, + "malloc failed for size %zu in convertSoundModelToHal PHRASE", + allocSize); + + const V2_0::ISoundTriggerHw::PhraseSoundModel* keyPhraseModel = + reinterpret_cast<const V2_0::ISoundTriggerHw::PhraseSoundModel*>(soundModel); + + size_t i; + for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]); + } + halKeyPhraseModel->num_phrases = (unsigned int)i; + halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel); + halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model); + } else { + size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size(); + halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halModel == NULL, + "malloc failed for size %zu in convertSoundModelToHal GENERIC", + allocSize); + + halModel->data_offset = sizeof(struct sound_trigger_sound_model); + } + halModel->type = (sound_trigger_sound_model_type_t)soundModel->type; + convertUuidToHal(&halModel->uuid, &soundModel->uuid); + convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid); + halModel->data_size = soundModel->data.size(); + uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset; + const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]); + memcpy(dst, src, soundModel->data.size()); + + return halModel; +} + +void SoundTriggerHw::convertPhraseRecognitionExtraToHal( + struct sound_trigger_phrase_recognition_extra* halExtra, + const V2_0::PhraseRecognitionExtra* extra) { + halExtra->id = extra->id; + halExtra->recognition_modes = extra->recognitionModes; + halExtra->confidence_level = extra->confidenceLevel; + + unsigned int i; + for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) { + halExtra->levels[i].user_id = extra->levels[i].userId; + halExtra->levels[i].level = extra->levels[i].levelPercent; + } + halExtra->num_levels = i; +} + +struct sound_trigger_recognition_config* SoundTriggerHw::convertRecognitionConfigToHal( + const V2_0::ISoundTriggerHw::RecognitionConfig* config) { + size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size(); + struct sound_trigger_recognition_config* halConfig = + static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize)); + + LOG_ALWAYS_FATAL_IF(halConfig == NULL, + "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize); + + halConfig->capture_handle = (audio_io_handle_t)config->captureHandle; + halConfig->capture_device = (audio_devices_t)config->captureDevice; + halConfig->capture_requested = config->captureRequested; + + unsigned int i; + for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]); + } + halConfig->num_phrases = i; + + halConfig->data_offset = sizeof(struct sound_trigger_recognition_config); + halConfig->data_size = config->data.size(); + uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset; + const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]); + memcpy(dst, src, config->data.size()); + return halConfig; +} + +// static +void SoundTriggerHw::convertSoundModelEventFromHal( + V2_0::ISoundTriggerHwCallback::ModelEvent* event, + const struct sound_trigger_model_event* halEvent) { + event->status = (V2_0::ISoundTriggerHwCallback::SoundModelStatus)halEvent->status; + // event->model to be remapped by called + event->data.setToExternal( + const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset, + halEvent->data_size); +} + +// static +void SoundTriggerHw::convertPhaseRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event, + const struct sound_trigger_phrase_recognition_event* halEvent) { + event->phraseExtras.resize(halEvent->num_phrases); + for (unsigned int i = 0; i < halEvent->num_phrases; i++) { + convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]); + } + convertRecognitionEventFromHal(&event->common, &halEvent->common); +} + +// static +void SoundTriggerHw::convertRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::RecognitionEvent* event, + const struct sound_trigger_recognition_event* halEvent) { + event->status = static_cast<V2_0::ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status); + event->type = static_cast<V2_0::SoundModelType>(halEvent->type); + // event->model to be remapped by called + event->captureAvailable = halEvent->capture_available; + event->captureSession = halEvent->capture_session; + event->captureDelayMs = halEvent->capture_delay_ms; + event->capturePreambleMs = halEvent->capture_preamble_ms; + event->triggerInData = halEvent->trigger_in_data; + event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate; + event->audioConfig.channelMask = + (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask; + event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format; + event->data.setToExternal( + const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset, + halEvent->data_size); +} + +// static +void SoundTriggerHw::convertPhraseRecognitionExtraFromHal( + V2_0::PhraseRecognitionExtra* extra, + const struct sound_trigger_phrase_recognition_extra* halExtra) { + extra->id = halExtra->id; + extra->recognitionModes = halExtra->recognition_modes; + extra->confidenceLevel = halExtra->confidence_level; + + extra->levels.resize(halExtra->num_levels); + for (unsigned int i = 0; i < halExtra->num_levels; i++) { + extra->levels[i].userId = halExtra->levels[i].user_id; + extra->levels[i].levelPercent = halExtra->levels[i].level; + } +} + +void SoundTriggerHw::SoundModelClient_2_0::recognitionCallback( + struct sound_trigger_recognition_event* halEvent) { + if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event; + convertPhaseRecognitionEventFromHal( + &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent)); + event.common.model = mId; + mCallback->phraseRecognitionCallback(event, mCookie); + } else { + V2_0::ISoundTriggerHwCallback::RecognitionEvent event; + convertRecognitionEventFromHal(&event, halEvent); + event.model = mId; + mCallback->recognitionCallback(event, mCookie); + } +} + +void SoundTriggerHw::SoundModelClient_2_0::soundModelCallback( + struct sound_trigger_model_event* halEvent) { + V2_0::ISoundTriggerHwCallback::ModelEvent event; + convertSoundModelEventFromHal(&event, halEvent); + event.model = mId; + mCallback->soundModelCallback(event, mCookie); +} + +// Begin V2_1 implementation, copied from +// hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.cpp + +namespace { + +// Backs up by the vector with the contents of shared memory. +// It is assumed that the passed hidl_vector is empty, so it's +// not cleared if the memory is a null object. +// The caller needs to keep the returned sp<IMemory> as long as +// the data is needed. +std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) { + sp<IMemory> memory; + if (m.size() == 0) { + return std::make_pair(true, memory); + } + memory = mapMemory(m); + if (memory != nullptr) { + memory->read(); + vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())), + memory->getSize()); + return std::make_pair(true, memory); + } + ALOGE("%s: Could not map HIDL memory to IMemory", __func__); + return std::make_pair(false, memory); +} + +// Moves the data from the vector into allocated shared memory, +// emptying the vector. +// It is assumed that the passed hidl_memory is a null object, so it's +// not reset if the vector is empty. +// The caller needs to keep the returned sp<IMemory> as long as +// the data is needed. +std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) { + sp<IMemory> memory; + if (v->size() == 0) { + return std::make_pair(true, memory); + } + sp<IAllocator> ashmem = IAllocator::getService("ashmem"); + if (ashmem == 0) { + ALOGE("Failed to retrieve ashmem allocator service"); + return std::make_pair(false, memory); + } + bool success = false; + Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) { + success = s; + if (success) *mem = m; + }); + if (r.isOk() && success) { + memory = hardware::mapMemory(*mem); + if (memory != 0) { + memory->update(); + memcpy(memory->getPointer(), v->data(), v->size()); + memory->commit(); + v->resize(0); + return std::make_pair(true, memory); + } else { + ALOGE("Failed to map allocated ashmem"); + } + } else { + ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size()); + } + return std::make_pair(false, memory); +} + +} // namespace + +Return<void> SoundTriggerHw::loadSoundModel_2_1( + const V2_1::ISoundTriggerHw::SoundModel& soundModel, + const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie, + V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) { + // It is assumed that legacy data vector is empty, thus making copy is cheap. + V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header); + auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data); + if (result.first) { + sp<SoundModelClient> client = + new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId()); + return Void(); + } + _hidl_cb(-ENOMEM, 0); + return Void(); +} + +Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1( + const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie, + V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) { + V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0; + // It is assumed that legacy data vector is empty, thus making copy is cheap. + soundModel_2_0.common = soundModel.common.header; + // Avoid copying phrases data. + soundModel_2_0.phrases.setToExternal( + const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()), + soundModel.phrases.size()); + auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data); + if (result.first) { + sp<SoundModelClient> client = + new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client), + client->getId()); + return Void(); + } + _hidl_cb(-ENOMEM, 0); + return Void(); +} + +Return<int32_t> SoundTriggerHw::startRecognition_2_1( + int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config, + const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie) { + // It is assumed that legacy data vector is empty, thus making copy is cheap. + V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header); + auto result = memoryAsVector(config.data, &config_2_0.data); + return result.first ? startRecognition(modelHandle, config_2_0, callback, cookie) + : Return<int32_t>(-ENOMEM); +} + +void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback( + struct sound_trigger_recognition_event* halEvent) { + if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0; + convertPhaseRecognitionEventFromHal( + &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent)); + event_2_0.common.model = mId; + V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event; + event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(), + event_2_0.phraseExtras.size()); + auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data); + if (result.first) { + // The data vector is now empty, thus copying is cheap. + event.common.header = event_2_0.common; + mCallback->phraseRecognitionCallback_2_1(event, mCookie); + } + } else { + V2_1::ISoundTriggerHwCallback::RecognitionEvent event; + convertRecognitionEventFromHal(&event.header, halEvent); + event.header.model = mId; + auto result = moveVectorToMemory(&event.header.data, &event.data); + if (result.first) { + mCallback->recognitionCallback_2_1(event, mCookie); + } + } +} + +void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback( + struct sound_trigger_model_event* halEvent) { + V2_1::ISoundTriggerHwCallback::ModelEvent event; + convertSoundModelEventFromHal(&event.header, halEvent); + event.header.model = mId; + auto result = moveVectorToMemory(&event.header.data, &event.data); + if (result.first) { + mCallback->soundModelCallback_2_1(event, mCookie); + } +} + +// Begin V2_2 implementation + +Return<int32_t> SoundTriggerHw::getModelState(int32_t modelHandle) { + sp<SoundModelClient> client; + if (mHwDevice == NULL) { + return -ENODEV; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + return -ENOSYS; + } + } + + if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_2) { + ALOGE("Get model state not supported"); + return -ENODEV; + } + + if (mHwDevice->get_model_state == NULL) { + ALOGE("Failed to get model state from device, no such method"); + return -ENODEV; + } + + return mHwDevice->get_model_state(mHwDevice, client->getHalHandle()); +} + +// Methods from ::android::hidl::base::V1_0::IBase follow. + +ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) { + return new SoundTriggerHw(); +} + +} // namespace implementation +} // namespace V2_2 +} // namespace soundtrigger +} // namespace hardware +} // namespace android diff --git a/soundtrigger/2.2/default/SoundTriggerHw.h b/soundtrigger/2.2/default/SoundTriggerHw.h new file mode 100644 index 0000000000..6676318b24 --- /dev/null +++ b/soundtrigger/2.2/default/SoundTriggerHw.h @@ -0,0 +1,193 @@ +/* + * 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 ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H +#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H + +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h> +#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h> +#include <hardware/sound_trigger.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <stdatomic.h> +#include <system/sound_trigger.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> + +namespace android { +namespace hardware { +namespace soundtrigger { +namespace V2_2 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::audio::common::V2_0::Uuid; +using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback; + +/** + * According to the HIDL C++ Users Guide: client and server implementations + * should never directly refer to anything other than the interface header + * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so + * this V2_2 implementation copies the V2_0 and V2_1 implementations and + * then adds the new V2_2 implementation. + */ +struct SoundTriggerHw : public ISoundTriggerHw { + // Methods from V2_0::ISoundTriggerHw follow. + Return<void> getProperties(getProperties_cb _hidl_cb) override; + Return<void> loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + const sp<V2_0::ISoundTriggerHwCallback>& callback, int32_t cookie, + loadSoundModel_cb _hidl_cb) override; + Return<void> loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<V2_0::ISoundTriggerHwCallback>& callback, + int32_t cookie, loadPhraseSoundModel_cb _hidl_cb) override; + Return<int32_t> unloadSoundModel(int32_t modelHandle) override; + Return<int32_t> startRecognition(int32_t modelHandle, + const V2_0::ISoundTriggerHw::RecognitionConfig& config, + const sp<V2_0::ISoundTriggerHwCallback>& callback, + int32_t cookie) override; + Return<int32_t> stopRecognition(int32_t modelHandle) override; + Return<int32_t> stopAllRecognitions() override; + + // Methods from V2_1::ISoundTriggerHw follow. + Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel, + const sp<V2_1::ISoundTriggerHwCallback>& callback, + int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override; + Return<void> loadPhraseSoundModel_2_1(const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<V2_1::ISoundTriggerHwCallback>& callback, + int32_t cookie, + loadPhraseSoundModel_2_1_cb _hidl_cb) override; + Return<int32_t> startRecognition_2_1(int32_t modelHandle, + const V2_1::ISoundTriggerHw::RecognitionConfig& config, + const sp<V2_1::ISoundTriggerHwCallback>& callback, + int32_t cookie) override; + + // Methods from V2_2::ISoundTriggerHw follow. + Return<int32_t> getModelState(int32_t modelHandle) override; + + SoundTriggerHw(); + + // Copied from hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.h + class SoundModelClient : public RefBase { + public: + SoundModelClient(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie) + : mId(id), mCookie(cookie) {} + virtual ~SoundModelClient() {} + + uint32_t getId() const { return mId; } + sound_model_handle_t getHalHandle() const { return mHalHandle; } + void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; } + + virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0; + virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0; + + protected: + const uint32_t mId; + sound_model_handle_t mHalHandle; + V2_0::ISoundTriggerHwCallback::CallbackCookie mCookie; + }; + + protected: + static void convertPhaseRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event, + const struct sound_trigger_phrase_recognition_event* halEvent); + static void convertRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::RecognitionEvent* event, + const struct sound_trigger_recognition_event* halEvent); + static void convertSoundModelEventFromHal(V2_0::ISoundTriggerHwCallback::ModelEvent* event, + const struct sound_trigger_model_event* halEvent); + + virtual ~SoundTriggerHw(); + + uint32_t nextUniqueModelId(); + int doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + sp<SoundModelClient> client); + + // RefBase + void onFirstRef() override; + + private: + class SoundModelClient_2_0 : public SoundModelClient { + public: + SoundModelClient_2_0(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + sp<V2_0::ISoundTriggerHwCallback> callback) + : SoundModelClient(id, cookie), mCallback(callback) {} + + void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override; + void soundModelCallback(struct sound_trigger_model_event* halEvent) override; + + private: + sp<V2_0::ISoundTriggerHwCallback> mCallback; + }; + + void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid); + void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid); + void convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties* properties, + const struct sound_trigger_properties* halProperties); + void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase, + const V2_0::ISoundTriggerHw::Phrase* triggerPhrase); + // returned HAL sound model must be freed by caller + struct sound_trigger_sound_model* convertSoundModelToHal( + const V2_0::ISoundTriggerHw::SoundModel* soundModel); + void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra, + const V2_0::PhraseRecognitionExtra* extra); + // returned recognition config must be freed by caller + struct sound_trigger_recognition_config* convertRecognitionConfigToHal( + const V2_0::ISoundTriggerHw::RecognitionConfig* config); + + static void convertPhraseRecognitionExtraFromHal( + V2_0::PhraseRecognitionExtra* extra, + const struct sound_trigger_phrase_recognition_extra* halExtra); + + static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie); + static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie); + + const char* mModuleName; + struct sound_trigger_hw_device* mHwDevice; + volatile atomic_uint_fast32_t mNextModelId; + DefaultKeyedVector<int32_t, sp<SoundModelClient> > mClients; + Mutex mLock; + + // Copied from hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.h + class SoundModelClient_2_1 : public SoundModelClient { + public: + SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie, + sp<V2_1::ISoundTriggerHwCallback> callback) + : SoundModelClient(id, cookie), mCallback(callback) {} + + void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override; + void soundModelCallback(struct sound_trigger_model_event* halEvent) override; + + private: + sp<V2_1::ISoundTriggerHwCallback> mCallback; + }; +}; + +extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name); + +} // namespace implementation +} // namespace V2_2 +} // namespace soundtrigger +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H diff --git a/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp b/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp new file mode 100644 index 0000000000..0f37816e47 --- /dev/null +++ b/soundtrigger/2.2/vts/functional/VtsHalSoundtriggerV2_2TargetTest.cpp @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#define LOG_TAG "SoundTriggerHidlHalTest" +#include <stdlib.h> +#include <time.h> + +#include <condition_variable> +#include <mutex> + +#include <android/log.h> +#include <cutils/native_handle.h> +#include <log/log.h> + +#include <android/hardware/audio/common/2.0/types.h> +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> +#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h> + +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback; +using ::android::hardware::soundtrigger::V2_0::SoundModelHandle; +using ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw; + +// Test environment for SoundTrigger HIDL HAL. +class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static SoundTriggerHidlEnvironment* Instance() { + static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment; + return instance; + } + + void registerTestServices() override { registerTestService<ISoundTriggerHw>(); } + + private: + SoundTriggerHidlEnvironment() {} +}; + +// The main test class for Sound Trigger HIDL HAL. +class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + void SetUp() override { + mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>( + SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>()); + ASSERT_NE(nullptr, mSoundTriggerHal.get()); + } + + static void SetUpTestCase() { srand(1234); } + + void TearDown() override {} + + protected: + sp<ISoundTriggerHw> mSoundTriggerHal; +}; + +/** + * Test ISoundTriggerHw::getModelState() method + * + * Verifies that: + * - the implementation returns -ENOSYS with invalid model handle + * + */ +TEST_F(SoundTriggerHidlTest, GetModelStateInvalidModel) { + SoundModelHandle handle = 0; + Return<int32_t> hidlReturn = mSoundTriggerHal->getModelState(handle); + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(-ENOSYS, hidlReturn); +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + SoundTriggerHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} diff --git a/thermal/2.0/Android.bp b/thermal/2.0/Android.bp new file mode 100644 index 0000000000..c513739e49 --- /dev/null +++ b/thermal/2.0/Android.bp @@ -0,0 +1,28 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.thermal@2.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IThermal.hal", + "IThermalChangedCallback.hal", + ], + interfaces: [ + "android.hardware.thermal@1.0", + "android.hidl.base@1.0", + ], + types: [ + "CoolingDevice", + "CoolingType", + "Temperature", + "TemperatureThreshold", + "TemperatureType", + "ThrottlingSeverity", + ], + gen_java: true, +} + diff --git a/thermal/2.0/IThermal.hal b/thermal/2.0/IThermal.hal new file mode 100644 index 0000000000..f890694d2c --- /dev/null +++ b/thermal/2.0/IThermal.hal @@ -0,0 +1,117 @@ +/* + * 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. + */ +package android.hardware.thermal@2.0; + +import android.hardware.thermal@1.0::IThermal; +import android.hardware.thermal@1.0::ThermalStatus; +import IThermalChangedCallback; + +interface IThermal extends @1.0::IThermal { + + /** + * Retrieves temperatures in Celsius. + * + * @param filterType whether to filter the result for a given type. + * @param type the TemperatureType such as battery or skin. + * + * @return status Status of the operation. If status code is FAILURE, + * the status.debugMessage must be populated with a human-readable + * error message. + * + * @return temperatures If status code is SUCCESS, it's filled with the + * current temperatures. The order of temperatures of built-in + * devices (such as CPUs, GPUs and etc.) in the list must be kept + * the same regardless of the number of calls to this method even if + * they go offline, if these devices exist on boot. The method + * always returns and never removes such temperatures. + */ + getCurrentTemperatures(bool filterType, TemperatureType type) + generates (ThermalStatus status, vec<Temperature> temperatures); + + /** + * Retrieves static temperature thresholds in Celsius. + * + * @param filterType whether to filter the result for a given type. + * @param type the TemperatureType such as battery or skin. + * + * @return status Status of the operation. If status code is FAILURE, + * the status.debugMessage must be populated with a human-readable error message. + * @return temperatureThresholds If status code is SUCCESS, it's filled with the + * temperatures thresholds. The order of temperatures of built-in + * devices (such as CPUs, GPUs and etc.) in the list must be kept + * the same regardless of the number of calls to this method even if + * they go offline, if these devices exist on boot. The method + * always returns and never removes such temperatures. The thresholds + * are returned as static values and must not change across calls. The actual + * throttling state is determined in driver and HAL and must not be simply + * compared with these thresholds. To get accurate throttling status, use + * getCurrentTemperatures or registerThermalChangedCallback and listen. + */ + getTemperatureThresholds(bool filterType, TemperatureType type) + generates (ThermalStatus status, vec<TemperatureThreshold> temperatureThresholds); + + /** + * Register an IThermalChangedCallback, used by the Thermal HAL + * to send thermal events when thermal mitigation status changed. + * Multiple registrations with different IThermalChangedCallback must be allowed. + * Multiple registrations with same IThermalChangedCallback is not allowed, client + * should unregister the given IThermalChangedCallback first. + * + * @param callback the IThermalChangedCallback to use for sending + * thermal events (cannot be nullptr). + * @param filterType if filter for given sensor type. + * @param type the type to be filtered. + * + * @return status Status of the operation. If status code is FAILURE, + * the status.debugMessage must be populated with a human-readable error message. + */ + registerThermalChangedCallback(IThermalChangedCallback callback, + bool filterType, + TemperatureType type) + generates (ThermalStatus status); + + /** + * Register an IThermalChangedCallback, used by the Thermal HAL + * to send thermal events when thermal mitigation status changed. + * + * @param callback the IThermalChangedCallback to use for sending + * thermal events, or nullptr to set no callback. + * + * @return status Status of the operation. If status code is FAILURE, + * the status.debugMessage must be populated with a human-readable error message. + */ + unregisterThermalChangedCallback(IThermalChangedCallback callback) + generates (ThermalStatus status); + + /** + * Retrieves the cooling devices information. + * + * @param filterType whether to filter the result for a given type. + * @param type the CoolingDevice such as CPU/GPU. + * + * @return status Status of the operation. If status code is FAILURE, + * the status.debugMessage must be populated with the human-readable + * error message. + * @return devices If status code is SUCCESS, it's filled with the current + * cooling device information. The order of built-in cooling + * devices in the list must be kept the same regardless of the number + * of calls to this method even if they go offline, if these devices + * exist on boot. The method always returns and never removes from + * the list such cooling devices. + */ + getCurrentCoolingDevices(bool filterType, CoolingType type) + generates (ThermalStatus status, vec<CoolingDevice> devices); +}; diff --git a/audio/core/2.0/default/include/core/2.0/default/Util.h b/thermal/2.0/IThermalChangedCallback.hal index 1f0e284d0a..b06bfbfd9d 100644 --- a/audio/core/2.0/default/include/core/2.0/default/Util.h +++ b/thermal/2.0/IThermalChangedCallback.hal @@ -14,13 +14,20 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H -#define ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H +package android.hardware.thermal@2.0; -#include <android/hardware/audio/2.0/types.h> +import android.hardware.thermal@2.0::Temperature; -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/Util.h> -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H +/** + * IThermalChangedCallback send throttling notification to clients. + */ +interface IThermalChangedCallback { + /** + * Send a thermal throttling event to all ThermalHAL + * thermal event listeners. + * + * @param temperature The temperature associated with the + * throttling event. + */ + oneway notifyThrottling (Temperature temperature); +}; diff --git a/thermal/2.0/default/Android.bp b/thermal/2.0/default/Android.bp new file mode 100644 index 0000000000..dab0d337f2 --- /dev/null +++ b/thermal/2.0/default/Android.bp @@ -0,0 +1,35 @@ +// +// 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. + +cc_binary { + name: "android.hardware.thermal@2.0-service.mock", + defaults: ["hidl_defaults"], + relative_install_path: "hw", + vendor: true, + init_rc: ["android.hardware.thermal@2.0-service.rc"], + vintf_fragments: ["android.hardware.thermal@2.0-service.xml"], + srcs: [ + "Thermal.cpp", + "service.cpp" + ], + shared_libs: [ + "libbase", + "libhidlbase", + "libhidltransport", + "libutils", + "android.hardware.thermal@2.0", + "android.hardware.thermal@1.0", + ], +} diff --git a/thermal/2.0/default/Thermal.cpp b/thermal/2.0/default/Thermal.cpp new file mode 100644 index 0000000000..442af61fa5 --- /dev/null +++ b/thermal/2.0/default/Thermal.cpp @@ -0,0 +1,208 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.thermal@2.0-service-mock" + +#include <cmath> +#include <set> + +#include <android-base/logging.h> +#include <hidl/HidlTransportSupport.h> + +#include "Thermal.h" + +namespace android { +namespace hardware { +namespace thermal { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::interfacesEqual; +using ::android::hardware::thermal::V1_0::ThermalStatus; +using ::android::hardware::thermal::V1_0::ThermalStatusCode; + +std::set<sp<IThermalChangedCallback>> gCallbacks; + +static const Temperature_1_0 kTemp_1_0 = { + .type = static_cast<::android::hardware::thermal::V1_0::TemperatureType>(TemperatureType::CPU), + .name = "test temperature sensor", + .currentValue = 98.6, + .throttlingThreshold = 58, + .shutdownThreshold = 60.0, + .vrThrottlingThreshold = 59.0, +}; + +static const Temperature_2_0 kTemp_2_0 = { + .type = TemperatureType::SKIN, + .name = "test temperature sensor", + .value = 98.6, + .throttlingStatus = ThrottlingSeverity::CRITICAL, +}; + +static const TemperatureThreshold kTempThreshold = { + .type = TemperatureType::SKIN, + .name = "test temperature sensor", + .hotThrottlingThresholds = {{NAN, NAN, NAN, NAN, NAN, NAN, NAN}}, + .coldThrottlingThresholds = {{NAN, NAN, NAN, NAN, NAN, NAN, NAN}}, + .vrThrottlingThreshold = NAN, +}; + +static const CoolingDevice_1_0 kCooling_1_0 = { + .type = ::android::hardware::thermal::V1_0::CoolingType::FAN_RPM, + .name = "test cooling device", + .currentValue = 100.0, +}; + +static const CoolingDevice_2_0 kCooling_2_0 = { + .type = CoolingType::CPU, + .name = "test cooling device", + .value = 1, +}; + +static const CpuUsage kCpuUsage = { + .name = "cpu_name", + .active = 0, + .total = 0, + .isOnline = true, +}; + +// Methods from ::android::hardware::thermal::V1_0::IThermal follow. +Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + std::vector<Temperature_1_0> temperatures = {kTemp_1_0}; + _hidl_cb(status, temperatures); + return Void(); +} + +Return<void> Thermal::getCpuUsages(getCpuUsages_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + std::vector<CpuUsage> cpu_usages = {kCpuUsage}; + _hidl_cb(status, cpu_usages); + return Void(); +} + +Return<void> Thermal::getCoolingDevices(getCoolingDevices_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + std::vector<CoolingDevice_1_0> cooling_devices = {kCooling_1_0}; + _hidl_cb(status, cooling_devices); + return Void(); +} + +// Methods from ::android::hardware::thermal::V2_0::IThermal follow. +Return<void> Thermal::getCurrentTemperatures(bool filterType, TemperatureType type, + getCurrentTemperatures_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + std::vector<Temperature_2_0> temperatures; + if (filterType && type != kTemp_2_0.type) { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = "Failed to read data"; + } else { + temperatures = {kTemp_2_0}; + } + _hidl_cb(status, temperatures); + return Void(); +} + +Return<void> Thermal::getTemperatureThresholds(bool filterType, TemperatureType type, + getTemperatureThresholds_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + std::vector<TemperatureThreshold> temperature_thresholds; + if (filterType && type != kTempThreshold.type) { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = "Failed to read data"; + } else { + temperature_thresholds = {kTempThreshold}; + } + _hidl_cb(status, temperature_thresholds); + return Void(); +} + +Return<void> Thermal::getCurrentCoolingDevices(bool filterType, CoolingType type, + getCurrentCoolingDevices_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + std::vector<CoolingDevice_2_0> cooling_devices; + if (filterType && type != kCooling_2_0.type) { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = "Failed to read data"; + } else { + cooling_devices = {kCooling_2_0}; + } + _hidl_cb(status, cooling_devices); + return Void(); +} + +Return<void> Thermal::registerThermalChangedCallback(const sp<IThermalChangedCallback>& callback, + bool filterType, TemperatureType type, + registerThermalChangedCallback_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + std::lock_guard<std::mutex> _lock(thermal_callback_mutex_); + if (std::any_of(callbacks_.begin(), callbacks_.end(), [&](const CallbackSetting& c) { + return interfacesEqual(c.callback, callback); + })) { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = "Same callback interface registered already"; + LOG(ERROR) << status.debugMessage; + } else { + callbacks_.emplace_back(callback, filterType, type); + LOG(INFO) << "A callback has been registered to ThermalHAL, isFilter: " << filterType + << " Type: " << android::hardware::thermal::V2_0::toString(type); + } + _hidl_cb(status); + return Void(); +} + +Return<void> Thermal::unregisterThermalChangedCallback( + const sp<IThermalChangedCallback>& callback, unregisterThermalChangedCallback_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + bool removed = false; + std::lock_guard<std::mutex> _lock(thermal_callback_mutex_); + callbacks_.erase( + std::remove_if(callbacks_.begin(), callbacks_.end(), + [&](const CallbackSetting& c) { + if (interfacesEqual(c.callback, callback)) { + LOG(INFO) + << "A callback has been unregistered from ThermalHAL, isFilter: " + << c.is_filter_type << " Type: " + << android::hardware::thermal::V2_0::toString(c.type); + removed = true; + return true; + } + return false; + }), + callbacks_.end()); + if (!removed) { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = "The callback was not registered before"; + LOG(ERROR) << status.debugMessage; + } + _hidl_cb(status); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace thermal +} // namespace hardware +} // namespace android diff --git a/thermal/2.0/default/Thermal.h b/thermal/2.0/default/Thermal.h new file mode 100644 index 0000000000..5fa1abd9f5 --- /dev/null +++ b/thermal/2.0/default/Thermal.h @@ -0,0 +1,88 @@ +/* + * 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 ANDROID_HARDWARE_THERMAL_V2_0_THERMAL_H +#define ANDROID_HARDWARE_THERMAL_V2_0_THERMAL_H + +#include <android/hardware/thermal/2.0/IThermal.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace thermal { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::thermal::V1_0::CpuUsage; +using ::android::hardware::thermal::V2_0::CoolingType; +using ::android::hardware::thermal::V2_0::IThermal; +using CoolingDevice_1_0 = ::android::hardware::thermal::V1_0::CoolingDevice; +using CoolingDevice_2_0 = ::android::hardware::thermal::V2_0::CoolingDevice; +using Temperature_1_0 = ::android::hardware::thermal::V1_0::Temperature; +using Temperature_2_0 = ::android::hardware::thermal::V2_0::Temperature; +using ::android::hardware::thermal::V2_0::IThermalChangedCallback; +using ::android::hardware::thermal::V2_0::TemperatureThreshold; +using ::android::hardware::thermal::V2_0::TemperatureType; + +struct CallbackSetting { + CallbackSetting(sp<IThermalChangedCallback> callback, bool is_filter_type, TemperatureType type) + : callback(callback), is_filter_type(is_filter_type), type(type) {} + sp<IThermalChangedCallback> callback; + bool is_filter_type; + TemperatureType type; +}; + +class Thermal : public IThermal { + public: + // Methods from ::android::hardware::thermal::V1_0::IThermal follow. + Return<void> getTemperatures(getTemperatures_cb _hidl_cb) override; + Return<void> getCpuUsages(getCpuUsages_cb _hidl_cb) override; + Return<void> getCoolingDevices(getCoolingDevices_cb _hidl_cb) override; + + // Methods from ::android::hardware::thermal::V2_0::IThermal follow. + Return<void> getCurrentTemperatures(bool filterType, TemperatureType type, + getCurrentTemperatures_cb _hidl_cb) override; + Return<void> getTemperatureThresholds(bool filterType, TemperatureType type, + getTemperatureThresholds_cb _hidl_cb) override; + Return<void> registerThermalChangedCallback( + const sp<IThermalChangedCallback>& callback, bool filterType, TemperatureType type, + registerThermalChangedCallback_cb _hidl_cb) override; + Return<void> unregisterThermalChangedCallback( + const sp<IThermalChangedCallback>& callback, + unregisterThermalChangedCallback_cb _hidl_cb) override; + Return<void> getCurrentCoolingDevices(bool filterType, CoolingType type, + getCurrentCoolingDevices_cb _hidl_cb) override; + + private: + std::mutex thermal_callback_mutex_; + std::vector<CallbackSetting> callbacks_; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace thermal +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_THERMAL_V2_0_THERMAL_H diff --git a/thermal/2.0/default/android.hardware.thermal@2.0-service.rc b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc new file mode 100644 index 0000000000..046c771767 --- /dev/null +++ b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc @@ -0,0 +1,5 @@ +service vendor.thermal-hal-2-0-mock /vendor/bin/hw/android.hardware.thermal@2.0-service.mock + interface android.hardware.thermal@2.0::IThermal default + class hal + user system + group system diff --git a/thermal/2.0/default/android.hardware.thermal@2.0-service.xml b/thermal/2.0/default/android.hardware.thermal@2.0-service.xml new file mode 100644 index 0000000000..bcd6344bc4 --- /dev/null +++ b/thermal/2.0/default/android.hardware.thermal@2.0-service.xml @@ -0,0 +1,12 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.thermal</name> + <transport>hwbinder</transport> + <version>1.0</version> + <version>2.0</version> + <interface> + <name>IThermal</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/thermal/2.0/default/service.cpp b/thermal/2.0/default/service.cpp new file mode 100644 index 0000000000..dd240785a7 --- /dev/null +++ b/thermal/2.0/default/service.cpp @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.thermal@2.0-service-mock" + +#include <android-base/logging.h> +#include <hidl/HidlTransportSupport.h> +#include "Thermal.h" + +using ::android::OK; +using ::android::status_t; + +// libhwbinder: +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::joinRpcThreadpool; + +// Generated HIDL files: +using ::android::hardware::thermal::V2_0::IThermal; +using ::android::hardware::thermal::V2_0::implementation::Thermal; + +static int shutdown() { + LOG(ERROR) << "Thermal Service is shutting down."; + return 1; +} + +int main(int /* argc */, char** /* argv */) { + status_t status; + android::sp<IThermal> service = nullptr; + + LOG(INFO) << "Thermal HAL Service Mock 2.0 starting..."; + + service = new Thermal(); + if (service == nullptr) { + LOG(ERROR) << "Error creating an instance of ThermalHAL. Exiting..."; + return shutdown(); + } + + configureRpcThreadpool(1, true /* callerWillJoin */); + + status = service->registerAsService(); + if (status != OK) { + LOG(ERROR) << "Could not register service for ThermalHAL (" << status << ")"; + return shutdown(); + } + + LOG(INFO) << "Thermal Service started successfully."; + joinRpcThreadpool(); + // We should not get past the joinRpcThreadpool(). + return shutdown(); +} diff --git a/thermal/2.0/types.hal b/thermal/2.0/types.hal new file mode 100644 index 0000000000..3fc3fdc180 --- /dev/null +++ b/thermal/2.0/types.hal @@ -0,0 +1,173 @@ +/* + * 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. + */ + +package android.hardware.thermal@2.0; + +import android.hardware.thermal@1.0::types; + +/** Device temperature types */ +enum TemperatureType : @1.0::TemperatureType { + USB_PORT = 4, + POWER_AMPLIFIER = 5, + + /** Battery Charge Limit - virtual thermal sensors */ + BCL_VOLTAGE = 6, + BCL_CURRENT = 7, + BCL_PERCENTAGE = 8, + + /** Neural Processing Unit */ + NPU = 9, +}; + + +/** Device cooling device types */ +enum CoolingType : uint32_t { + FAN, + BATTERY, + CPU, + GPU, + MODEM, + NPU, + COMPONENT, // for the rest of components +}; + +/** Device throttling severity */ +enum ThrottlingSeverity : uint32_t { + /** + * Not under throttling. + */ + NONE = 0, + + /** + * Light throttling where UX is not impacted. + */ + LIGHT, + + /** + * Moderate throttling where UX is not largely impacted. + */ + MODERATE, + + /** + * Severe throttling where UX is largely impacted. + * Similar to 1.0 throttlingThreshold. + */ + SEVERE, + + /** + * Platform has done everything to reduce power. + */ + CRITICAL, + + /** + * Key components in platform are shutting down due to thermal condition. + * Device functionalities will be limited. + */ + EMERGENCY, + + /** + * Need shutdown immediately. + */ + SHUTDOWN, +}; + +struct TemperatureThreshold { + /** + * This temperature's type. + */ + TemperatureType type; + + /** + * Name of this temperature matching the Temperature struct. + * All temperatures of the same "type" must have a different "name", + * e.g., cpu0, battery. Clients use it to match Temperature struct. + */ + string name; + + /** + * Hot throttling temperature constant for this temperature sensor in + * level defined in ThrottlingSeverity including shutdown. Throttling + * happens when temperature >= threshold. If not available, set to NAN. + * Unit is same as Temperature's value. + */ + float[ThrottlingSeverity#len] hotThrottlingThresholds; + + /** + * Cold throttling temperature constant for this temperature sensor in + * level defined in ThrottlingSeverity including shutdown. Throttling + * happens when temperature <= threshold. If not available, set to NAN. + * Unit is same as Temperature's value. + */ + float[ThrottlingSeverity#len] coldThrottlingThresholds; + + /** + * Threshold temperature above which the VR mode clockrate minimums cannot + * be maintained for this device. If not available, set by HAL to NAN. + * Unit is same as Temperature's value. + */ + float vrThrottlingThreshold; +}; + +struct Temperature { + /** + * This temperature's type. + */ + TemperatureType type; + + /** + * Name of this temperature matching the TemperatureThreshold. + * All temperatures of the same "type" must have a different "name", + * e.g., cpu0, battery. Clients use it to match with TemperatureThreshold + * struct. + */ + string name; + + /** + * For BCL, this is the current reading of the virtual sensor and the unit is + * millivolt, milliamp, percentage for BCL_VOLTAGE, BCL_CURRENT and BCL_PERCENTAGE + * respectively. For everything else, this is the current temperature in Celsius. + * If not available set by HAL to NAN. + */ + float value; + + /** + * The current throttling level of the sensor. + */ + ThrottlingSeverity throttlingStatus; +}; + +struct CoolingDevice { + /** + * This cooling device type, CPU, GPU, BATTERY, and etc. + */ + CoolingType type; + + /** + * Name of this cooling device. + * All cooling devices of the same "type" must have a different "name". + * The name is usually defined in kernel device tree, and this is for client + * logging purpose. + */ + string name; + + /** + * Current throttle state of the cooling device. The value can any unsigned integer + * numbers between 0 and max_state defined in its driver, usually representing the + * associated device's power state. 0 means device is not in throttling, higher value + * means deeper throttling. + */ + uint64_t value; +}; diff --git a/thermal/2.0/vts/functional/Android.bp b/thermal/2.0/vts/functional/Android.bp new file mode 100644 index 0000000000..f4e95f8ae5 --- /dev/null +++ b/thermal/2.0/vts/functional/Android.bp @@ -0,0 +1,26 @@ +// +// 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. +// + +cc_test { + name: "VtsHalThermalV2_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalThermalV2_0TargetTest.cpp"], + static_libs: [ + "android.hardware.thermal@1.0", + "android.hardware.thermal@2.0", + ], +} + diff --git a/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp new file mode 100644 index 0000000000..3893014e20 --- /dev/null +++ b/thermal/2.0/vts/functional/VtsHalThermalV2_0TargetTest.cpp @@ -0,0 +1,263 @@ +/* + * 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/hardware/thermal/2.0/IThermal.h> +#include <android/hardware/thermal/2.0/IThermalChangedCallback.h> +#include <android/hardware/thermal/2.0/types.h> + +#include <VtsHalHidlTargetCallbackBase.h> +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> + +using ::android::sp; +using ::android::hardware::hidl_enum_range; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::thermal::V1_0::ThermalStatus; +using ::android::hardware::thermal::V1_0::ThermalStatusCode; +using ::android::hardware::thermal::V2_0::CoolingDevice; +using ::android::hardware::thermal::V2_0::CoolingType; +using ::android::hardware::thermal::V2_0::IThermal; +using ::android::hardware::thermal::V2_0::IThermalChangedCallback; +using ::android::hardware::thermal::V2_0::Temperature; +using ::android::hardware::thermal::V2_0::TemperatureThreshold; +using ::android::hardware::thermal::V2_0::TemperatureType; +using ::android::hardware::thermal::V2_0::ThrottlingSeverity; + +constexpr char kCallbackNameNotifyThrottling[] = "notifyThrottling"; +static const Temperature kThrottleTemp = { + .type = TemperatureType::SKIN, + .name = "test temperature sensor", + .value = 98.6, + .throttlingStatus = ThrottlingSeverity::CRITICAL, +}; + +class ThermalCallbackArgs { + public: + Temperature temperature; +}; + +// Callback class for receiving thermal event notifications from main class +class ThermalCallback : public ::testing::VtsHalHidlTargetCallbackBase<ThermalCallbackArgs>, + public IThermalChangedCallback { + public: + Return<void> notifyThrottling(const Temperature& temperature) override { + ThermalCallbackArgs args; + args.temperature = temperature; + NotifyFromCallback(kCallbackNameNotifyThrottling, args); + return Void(); + } +}; + +// Test environment for Thermal HIDL HAL. +class ThermalHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static ThermalHidlEnvironment* Instance() { + static ThermalHidlEnvironment* instance = new ThermalHidlEnvironment; + return instance; + } + + void registerTestServices() override { registerTestService<IThermal>(); } + + private: + ThermalHidlEnvironment() {} +}; + +// The main test class for THERMAL HIDL HAL 2.0. +class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + mThermal = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>( + ThermalHidlEnvironment::Instance()->getServiceName<IThermal>()); + ASSERT_NE(mThermal, nullptr); + mThermalCallback = new (std::nothrow) ThermalCallback(); + ASSERT_NE(mThermalCallback, nullptr); + auto ret = mThermal->registerThermalChangedCallback( + mThermalCallback, false, TemperatureType::SKIN, + [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + // Expect to fail if register again + ret = mThermal->registerThermalChangedCallback( + mThermalCallback, false, TemperatureType::SKIN, + [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + } + + virtual void TearDown() override { + auto ret = mThermal->unregisterThermalChangedCallback( + mThermalCallback, + [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + // Expect to fail if unregister again + ret = mThermal->unregisterThermalChangedCallback( + mThermalCallback, + [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + } + + protected: + sp<IThermal> mThermal; + sp<ThermalCallback> mThermalCallback; +}; // class ThermalHidlTest + +// Test ThermalChangedCallback::notifyThrottling(). +// This just calls into and back from our local ThermalChangedCallback impl. +// Note: a real thermal throttling event from the Thermal HAL could be +// inadvertently received here. +TEST_F(ThermalHidlTest, NotifyThrottlingTest) { + auto ret = mThermalCallback->notifyThrottling(kThrottleTemp); + ASSERT_TRUE(ret.isOk()); + auto res = mThermalCallback->WaitForCallback(kCallbackNameNotifyThrottling); + EXPECT_TRUE(res.no_timeout); + ASSERT_TRUE(res.args); + EXPECT_EQ(kThrottleTemp, res.args->temperature); +} + +// Test Thermal->registerThermalChangedCallback. +TEST_F(ThermalHidlTest, RegisterThermalChangedCallbackTest) { + // Expect to fail with same callback + auto ret = mThermal->registerThermalChangedCallback( + mThermalCallback, false, TemperatureType::SKIN, + [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback(); + // Expect to succeed with different callback + ret = mThermal->registerThermalChangedCallback( + localThermalCallback, false, TemperatureType::SKIN, + [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + // Remove the local callback. + ret = mThermal->unregisterThermalChangedCallback( + localThermalCallback, + [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); +} + +// Test Thermal->unregisterThermalChangedCallback. +TEST_F(ThermalHidlTest, UnregisterThermalChangedCallbackTest) { + sp<ThermalCallback> localThermalCallback = new (std::nothrow) ThermalCallback(); + // Expect to fail as the callback was not registered before + auto ret = mThermal->unregisterThermalChangedCallback( + localThermalCallback, + [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + // Register a local callback + ret = mThermal->registerThermalChangedCallback( + localThermalCallback, false, TemperatureType::SKIN, + [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + // Expect to succeed with callback removed + ret = mThermal->unregisterThermalChangedCallback( + localThermalCallback, + [](ThermalStatus status) { EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); + // Expect to fail as the callback has been unregistered already + ret = mThermal->unregisterThermalChangedCallback( + localThermalCallback, + [](ThermalStatus status) { EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); }); + ASSERT_TRUE(ret.isOk()); +} + +// Sanity test for Thermal::getCurrentTemperatures(). +TEST_F(ThermalHidlTest, TemperatureTest) { + mThermal->getCurrentTemperatures(false, TemperatureType::SKIN, + [](ThermalStatus status, hidl_vec<Temperature> temperatures) { + if (temperatures.size()) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + } else { + EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); + } + }); + auto types = hidl_enum_range<TemperatureType>(); + for (const auto& type : types) { + mThermal->getCurrentTemperatures( + true, type, [&type](ThermalStatus status, hidl_vec<Temperature> temperatures) { + if (temperatures.size()) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + } else { + EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); + } + for (int i = 0; i < temperatures.size(); ++i) { + EXPECT_EQ(type, temperatures[i].type); + } + }); + } +} + +// Sanity test for Thermal::getTemperatureThresholds(). +TEST_F(ThermalHidlTest, TemperatureThresholdTest) { + mThermal->getTemperatureThresholds( + false, TemperatureType::SKIN, + [](ThermalStatus status, hidl_vec<TemperatureThreshold> temperatures) { + if (temperatures.size()) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + } else { + EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); + } + }); + for (int i = static_cast<int>(TemperatureType::UNKNOWN); + i <= static_cast<int>(TemperatureType::POWER_AMPLIFIER); ++i) { + auto type = static_cast<TemperatureType>(i); + mThermal->getTemperatureThresholds( + true, type, [&type](ThermalStatus status, hidl_vec<TemperatureThreshold> temperatures) { + if (temperatures.size()) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + } else { + EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); + } + for (int i = 0; i < temperatures.size(); ++i) { + EXPECT_EQ(type, temperatures[i].type); + } + }); + } +} + +// Sanity test for Thermal::getCurrentCoolingDevices(). +TEST_F(ThermalHidlTest, CoolingDeviceTest) { + mThermal->getCurrentCoolingDevices( + false, CoolingType::CPU, [](ThermalStatus status, hidl_vec<CoolingDevice> cooling_devices) { + if (cooling_devices.size()) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + } else { + EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); + } + }); + for (int i = 0; i <= static_cast<int>(CoolingType::COMPONENT); ++i) { + auto type = static_cast<CoolingType>(i); + mThermal->getCurrentCoolingDevices( + true, type, [&type](ThermalStatus status, hidl_vec<CoolingDevice> cooling_devices) { + if (cooling_devices.size()) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + } else { + EXPECT_NE(ThermalStatusCode::SUCCESS, status.code); + } + for (int i = 0; i < cooling_devices.size(); ++i) { + EXPECT_EQ(type, cooling_devices[i].type); + } + }); + } +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(ThermalHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + ThermalHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + cout << "Test result = " << status << std::endl; + return status; +} diff --git a/tv/cec/1.0/types.hal b/tv/cec/1.0/types.hal index c734c4d7ad..ebe65ae9d0 100644 --- a/tv/cec/1.0/types.hal +++ b/tv/cec/1.0/types.hal @@ -114,6 +114,8 @@ enum CecMessageType : int32_t { VENDOR_COMMAND_WITH_ID = 0xA0, CLEAR_EXTERNAL_TIMER = 0xA1, SET_EXTERNAL_TIMER = 0xA2, + REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3, + REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4, INITIATE_ARC = 0xC0, REPORT_ARC_INITIATED = 0xC1, REPORT_ARC_TERMINATED = 0xC2, diff --git a/tv/cec/2.0/Android.bp b/tv/cec/2.0/Android.bp new file mode 100644 index 0000000000..998cb23ecb --- /dev/null +++ b/tv/cec/2.0/Android.bp @@ -0,0 +1,46 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.tv.cec@2.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IHdmiCec.hal", + "IHdmiCecCallback.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + types: [ + "AbortReason", + "CecAllDeviceTypeValue", + "CecDeviceFeature", + "CecDeviceInfo", + "CecDeviceType", + "CecLogicalAddress", + "CecMessage", + "CecMessageType", + "CecPowerState", + "CecRcProfile", + "CecRcProfile1", + "CecRcProfileId", + "CecRcProfileSource", + "CecTopologyEvent", + "CecTopologyEventType", + "CecUICommandCodes", + "CecVersion", + "HdmiPortInfo", + "HdmiPortType", + "HotplugEvent", + "MaxLength", + "OptionKey", + "Result", + "SendMessageResult", + ], + gen_java: true, +} + diff --git a/tv/cec/2.0/IHdmiCec.hal b/tv/cec/2.0/IHdmiCec.hal new file mode 100644 index 0000000000..0723bad8c6 --- /dev/null +++ b/tv/cec/2.0/IHdmiCec.hal @@ -0,0 +1,209 @@ +/* + * 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. + */ + +package android.hardware.tv.cec@2.0; + +import IHdmiCecCallback; + +/** + * HDMI-CEC HAL interface definition. + */ +interface IHdmiCec { + /** + * Passes Primary Device Type that must be used in this system. + * + * HAL must use it to allocate logical address as specified in CEC section + * 11.3.2 of the CEC spec 2.0b. Then CEC commands addressed the given + * logical address can be filtered in. + * This method shall be able to be called up to twice to support two Primary + * Device Type as specified in CEC Table 11-8 of the CEC spec 2.0b. + * + * @param deviceType that must be used in this system. It must be a valid + * value in CecDeviceType for the call to succeed. + * @return result Result status of the operation. SUCCESS if successful, + * FAILURE_INVALID_ARGS if the given device type is invalid, + * FAILURE_BUSY if device or resource is busy + */ + @callflow(next={"*"}) + addDeviceType(CecDeviceType deviceType) generates (Result result); + + /** + * Clears all Primary Device Types. + * + * It is used when the system plan to reconfigure Primary Device Type, + * hence to tell HAL to release all logical address associated to them, + * and change the state back to the beginning. + */ + @callflow(next="addDeviceType") + @exit + clearDeviceTypes(); + + /** + * Set All Device Types for a Primary Device Type. + * + * This value must be used in REPORT_FEATURES message to response + * GIVE_FEATURES message in HAL. + * + * @param allDeviceTypes device all device types for a Primary Device Type. + */ + @callflow(next="addDeviceType") + setAllDeviceTypes(CecAllDeviceTypes allDeviceTypes); + + /** + * Set Device Features for a Primary Device Type. + * + * This value must be used in REPORT_FEATURES message to response + * GIVE_FEATURES message in HAL. + * + * @param deviceType The device Primary Device Type. + * @param deviceFeatures device features for a Primary Device Type. + */ + @callflow(next="addDeviceType") + setDeviceFeatures(CecDeviceType deviceType, + CecDeviceFeatures deviceFeatures); + + /** + * Set Remote Control Profile for a Primary Device Type. + * + * This value must be used in REPORT_FEATURES message to response + * GIVE_FEATURES message in HAL. + * + * @param deviceType The device Primary Device Type. + * @param rcProliles remote control profiles for a Primary Device Type. + */ + @callflow(next="addDeviceType") + setRcProfile(CecDeviceType deviceType, CecRcProfile rcProfile); + + /** + * Retrieve CEC device information. + * + * CEC section 11.3 of the CEC spec 2.0b specify that a device should not + * ask for static information that another device has already supplied. + * Therefore, CEC 2.0 software stack need a map to store all cec + * devices’ information of current CEC network. + * The device information is broadcasted by a device after it allocates a + * logical address. Messages used to send out these information are + * REPORT_FEATURES, REPORT_PHYSICAL_ADDRESS, DEVICE_VENDOR_ID. + * The spec also requires less than 1 second between REPORT_FEATURES and + * REPORT_PHYSICAL_ADDRESS message, and less than 2 second between + * REPORT_PHYSICAL_ADDRESS and DEVICE_VENDOR_ID. An Implementation of + * device information map in hal can help to meet the timing constraints. + * Logical addressing is part of the process to build this map, so the + * implementation shall include allocating logical address too. + * Whenever a device plug/unplug, the topology of CEC network changes. + * The hal implementation shall update devices’ information map, and + * send out onTopologyEvent to Android system. Then Android system + * will use readDeviceInfo to retreive latest devices’ information of CEC + * network. + * If SYSTEM_CEC_CONTROL is false, the hal implementation need continue to + * maintain and update device information map, and send out pending + * onTopologyEvent to Android system when SYSTEM_CEC_CONTROL is + * changed to true. + * + * @param logicalAddress logical address of CEC device. + * @param physicalAddress physical address of CEC device. + * @return CecDeviceInfo from device information map. + * @return result Result status of the operation. SUCCESS if successful, + * FAILURE_INVALID_ARGS if logical or physical address is invalid. + * FAILURE_INVALID_STATE if device information isn't available yet. + */ + @callflow(next="onTopologyChangeEvent") + readDeviceInfo(CecLogicalAddress logicalAddress, + CecPhysicalAddress physicalAddress) + generates (Result result, CecDeviceInfo deviceInfo); + + /** + * Transmits HDMI-CEC message to other HDMI device. + * + * The method must be designed to return in a certain amount of time and not + * hanging forever. This method MUST complete with in 1 second. + * + * It must try retransmission at least once as specified in the section '7.1 + * Frame Re-transmissions' of the CEC Spec 1.4b. + * + * @param message CEC message to be sent to other HDMI device. + * @return result Result status of the operation. SUCCESS if successful, + * NACK if the sent message is not acknowledged, + * BUSY if the CEC bus is busy. + */ + @callflow(next="*") + sendMessage(CecMessage message) generates (SendMessageResult result); + + /** + * Set the callback + * + * It is used by the framework to receive CecMessages, HDMI hotplug event + * and topology update event. Only one callback client is supported. + * + * @param callback Callback object to pass hdmi events to the system. The + * previously registered callback must be replaced with this one. + */ + @callflow(next={"*"}) + @entry + setCallback(IHdmiCecCallback callback); + + /** + * Gets the hdmi port information of underlying hardware. + * + * @return infos The list of HDMI port information + */ + @callflow(next={"*"}) + getPortInfo() generates (vec<HdmiPortInfo> infos); + + /** + * Sets flags controlling the way HDMI-CEC service works down to HAL + * implementation. Those flags must be used in case the feature needs update + * in HAL itself, firmware or microcontroller. + * + * @param key The key of the option to be updated with a new value. + * @param value Value to be set. + */ + @callflow(next="*") + setOption(OptionKey key, bool value); + + /** + * Passes the updated language information of Android system. Contains + * three-letter code as defined in ISO/FDIS 639-2. Must be used for HAL to + * respond to <Get Menu Language> while in standby mode. + * + * @param language Three-letter code defined in ISO/FDIS 639-2. Must be + * lowercase letters. (e.g., eng for English) + */ + @callflow(next="*") + setLanguage(string language); + + /** + * Configures ARC circuit in the hardware logic to start or stop the + * feature. + * + * @param portId Port id to be configured. + * @param enable Flag must be either true to start the feature or false to + * stop it. + */ + @callflow(next="*") + enableAudioReturnChannel(HdmiPortId portId, bool enable); + + /** + * Gets the connection status of the specified port. + * + * It's specified in CEC section 10.8 of the CEC spec 2.0b + * + * @param portId Port id to be inspected for the connection status. + * @return status True if a device is connected, otherwise false. + */ + @callflow(next="*") + isConnected(HdmiPortId portId) generates (bool connected); +}; diff --git a/tv/cec/2.0/IHdmiCecCallback.hal b/tv/cec/2.0/IHdmiCecCallback.hal new file mode 100644 index 0000000000..1a8a4895cd --- /dev/null +++ b/tv/cec/2.0/IHdmiCecCallback.hal @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package android.hardware.tv.cec@2.0; + +interface IHdmiCecCallback { + /** + * The callback function that must be called by HAL implementation to notify + * the system of new CEC message arrival. + */ + oneway onCecMessage(CecMessage message); + + /** + * The callback function that must be called by HAL implementation to notify + * the system of new hotplug event. + */ + oneway onHotplugEvent(HotplugEvent event); + + /** + * The callback function must be called by HAL implementation to notify the + * system whenever CEC device information of CEC network change. + * HAL shall be ready for readDeviceInfo call before invoke this callback. + * This event is triggered by topology change of whole CEC network. It's + * different from HotplugEvent which is triggered between devices which are + * connected directly through HDMI cable. + */ + oneway onTopologyEvent(CecTopologyEvent event); +}; diff --git a/tv/cec/2.0/default/Android.bp b/tv/cec/2.0/default/Android.bp new file mode 100644 index 0000000000..6e624e3e7d --- /dev/null +++ b/tv/cec/2.0/default/Android.bp @@ -0,0 +1,42 @@ +cc_library_shared { + name: "android.hardware.tv.cec@2.0-impl", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: ["HdmiCec.cpp"], + + shared_libs: [ + "libhidlbase", + "libhidltransport", + "liblog", + "libbase", + "libutils", + "libhardware", + "android.hardware.tv.cec@2.0", + ], + +} + +cc_binary { + name: "android.hardware.tv.cec@2.0-service", + vintf_fragments: ["android.hardware.tv.cec@2.0-service.xml"], + defaults: ["hidl_defaults"], + relative_install_path: "hw", + vendor: true, + init_rc: ["android.hardware.tv.cec@2.0-service.rc"], + srcs: ["service.cpp"], + + shared_libs: [ + "liblog", + "libcutils", + "libdl", + "libbase", + "libutils", + "libhardware_legacy", + "libhardware", + "libhidlbase", + "libhidltransport", + "android.hardware.tv.cec@2.0", + ], + +} diff --git a/tv/cec/2.0/default/HdmiCec.cpp b/tv/cec/2.0/default/HdmiCec.cpp new file mode 100644 index 0000000000..f45171955b --- /dev/null +++ b/tv/cec/2.0/default/HdmiCec.cpp @@ -0,0 +1,421 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.tv.cec@2.0-impl" +#include <android-base/logging.h> + +#include <hardware/hardware.h> +#include <hardware/hdmi_cec.h> +#include "HdmiCec.h" + +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V2_0 { +namespace implementation { + +static_assert(CEC_DEVICE_INACTIVE == static_cast<int>(CecDeviceType::INACTIVE), + "CecDeviceType::INACTIVE must match legacy value."); +static_assert(CEC_DEVICE_TV == static_cast<int>(CecDeviceType::TV), + "CecDeviceType::TV must match legacy value."); +static_assert(CEC_DEVICE_RECORDER == static_cast<int>(CecDeviceType::RECORDER), + "CecDeviceType::RECORDER must match legacy value."); +static_assert(CEC_DEVICE_TUNER == static_cast<int>(CecDeviceType::TUNER), + "CecDeviceType::TUNER must match legacy value."); +static_assert(CEC_DEVICE_PLAYBACK == static_cast<int>(CecDeviceType::PLAYBACK), + "CecDeviceType::PLAYBACK must match legacy value."); +static_assert(CEC_DEVICE_AUDIO_SYSTEM == static_cast<int>(CecDeviceType::AUDIO_SYSTEM), + "CecDeviceType::AUDIO_SYSTEM must match legacy value."); +/* TODO: Adjust for cec@2.0 +static_assert(CEC_DEVICE_MAX == static_cast<int>(CecDeviceType::MAX), + "CecDeviceType::MAX must match legacy value."); +*/ +static_assert(CEC_ADDR_TV == static_cast<int>(CecLogicalAddress::TV), + "CecLogicalAddress::TV must match legacy value."); +static_assert(CEC_ADDR_RECORDER_1 == static_cast<int>(CecLogicalAddress::RECORDER_1), + "CecLogicalAddress::RECORDER_1 must match legacy value."); +static_assert(CEC_ADDR_RECORDER_2 == static_cast<int>(CecLogicalAddress::RECORDER_2), + "CecLogicalAddress::RECORDER_2 must match legacy value."); +static_assert(CEC_ADDR_TUNER_1 == static_cast<int>(CecLogicalAddress::TUNER_1), + "CecLogicalAddress::TUNER_1 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_1 == static_cast<int>(CecLogicalAddress::PLAYBACK_1), + "CecLogicalAddress::PLAYBACK_1 must match legacy value."); +static_assert(CEC_ADDR_AUDIO_SYSTEM == static_cast<int>(CecLogicalAddress::AUDIO_SYSTEM), + "CecLogicalAddress::AUDIO_SYSTEM must match legacy value."); +static_assert(CEC_ADDR_TUNER_2 == static_cast<int>(CecLogicalAddress::TUNER_2), + "CecLogicalAddress::TUNER_2 must match legacy value."); +static_assert(CEC_ADDR_TUNER_3 == static_cast<int>(CecLogicalAddress::TUNER_3), + "CecLogicalAddress::TUNER_3 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_2 == static_cast<int>(CecLogicalAddress::PLAYBACK_2), + "CecLogicalAddress::PLAYBACK_2 must match legacy value."); +static_assert(CEC_ADDR_RECORDER_3 == static_cast<int>(CecLogicalAddress::RECORDER_3), + "CecLogicalAddress::RECORDER_3 must match legacy value."); +static_assert(CEC_ADDR_TUNER_4 == static_cast<int>(CecLogicalAddress::TUNER_4), + "CecLogicalAddress::TUNER_4 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_3 == static_cast<int>(CecLogicalAddress::PLAYBACK_3), + "CecLogicalAddress::PLAYBACK_3 must match legacy value."); +/* TODO: Adjust for cec@2.0 +static_assert(CEC_ADDR_FREE_USE == static_cast<int>(CecLogicalAddress::FREE_USE), + "CecLogicalAddress::FREE_USE must match legacy value."); +*/ +static_assert(CEC_ADDR_UNREGISTERED == static_cast<int>(CecLogicalAddress::UNREGISTERED), + "CecLogicalAddress::UNREGISTERED must match legacy value."); +static_assert(CEC_ADDR_BROADCAST == static_cast<int>(CecLogicalAddress::BROADCAST), + "CecLogicalAddress::BROADCAST must match legacy value."); + +static_assert(CEC_MESSAGE_FEATURE_ABORT == static_cast<int>(CecMessageType::FEATURE_ABORT), + "CecMessageType::FEATURE_ABORT must match legacy value."); +static_assert(CEC_MESSAGE_IMAGE_VIEW_ON == static_cast<int>(CecMessageType::IMAGE_VIEW_ON), + "CecMessageType::IMAGE_VIEW_ON must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_STEP_INCREMENT == + static_cast<int>(CecMessageType::TUNER_STEP_INCREMENT), + "CecMessageType::TUNER_STEP_INCREMENT must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_STEP_DECREMENT == + static_cast<int>(CecMessageType::TUNER_STEP_DECREMENT), + "CecMessageType::TUNER_STEP_DECREMENT must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_DEVICE_STATUS == + static_cast<int>(CecMessageType::TUNER_DEVICE_STATUS), + "CecMessageType::TUNER_DEVICE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_TUNER_DEVICE_STATUS == + static_cast<int>(CecMessageType::GIVE_TUNER_DEVICE_STATUS), + "CecMessageType::GIVE_TUNER_DEVICE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_ON == static_cast<int>(CecMessageType::RECORD_ON), + "CecMessageType::RECORD_ON must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_STATUS == static_cast<int>(CecMessageType::RECORD_STATUS), + "CecMessageType::RECORD_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_OFF == static_cast<int>(CecMessageType::RECORD_OFF), + "CecMessageType::RECORD_OFF must match legacy value."); +static_assert(CEC_MESSAGE_TEXT_VIEW_ON == static_cast<int>(CecMessageType::TEXT_VIEW_ON), + "CecMessageType::TEXT_VIEW_ON must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_TV_SCREEN == static_cast<int>(CecMessageType::RECORD_TV_SCREEN), + "CecMessageType::RECORD_TV_SCREEN must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DECK_STATUS == static_cast<int>(CecMessageType::GIVE_DECK_STATUS), + "CecMessageType::GIVE_DECK_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_STANDBY == static_cast<int>(CecMessageType::STANDBY), + "CecMessageType::STANDBY must match legacy value."); +static_assert(CEC_MESSAGE_PLAY == static_cast<int>(CecMessageType::PLAY), + "CecMessageType::PLAY must match legacy value."); +static_assert(CEC_MESSAGE_DECK_CONTROL == static_cast<int>(CecMessageType::DECK_CONTROL), + "CecMessageType::DECK_CONTROL must match legacy value."); +static_assert(CEC_MESSAGE_TIMER_CLEARED_STATUS == + static_cast<int>(CecMessageType::TIMER_CLEARED_STATUS), + "CecMessageType::TIMER_CLEARED_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_USER_CONTROL_PRESSED == + static_cast<int>(CecMessageType::USER_CONTROL_PRESSED), + "CecMessageType::USER_CONTROL_PRESSED must match legacy value."); +static_assert(CEC_MESSAGE_USER_CONTROL_RELEASED == + static_cast<int>(CecMessageType::USER_CONTROL_RELEASED), + "CecMessageType::USER_CONTROL_RELEASED must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_OSD_NAME == static_cast<int>(CecMessageType::GIVE_OSD_NAME), + "CecMessageType::GIVE_OSD_NAME must match legacy value."); +static_assert(CEC_MESSAGE_SET_OSD_NAME == static_cast<int>(CecMessageType::SET_OSD_NAME), + "CecMessageType::SET_OSD_NAME must match legacy value."); +static_assert(CEC_MESSAGE_SYSTEM_AUDIO_MODE_REQUEST == + static_cast<int>(CecMessageType::SYSTEM_AUDIO_MODE_REQUEST), + "CecMessageType::SYSTEM_AUDIO_MODE_REQUEST must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_AUDIO_STATUS == static_cast<int>(CecMessageType::GIVE_AUDIO_STATUS), + "CecMessageType::GIVE_AUDIO_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_SET_SYSTEM_AUDIO_MODE == + static_cast<int>(CecMessageType::SET_SYSTEM_AUDIO_MODE), + "CecMessageType::SET_SYSTEM_AUDIO_MODE must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_AUDIO_STATUS == + static_cast<int>(CecMessageType::REPORT_AUDIO_STATUS), + "CecMessageType::REPORT_AUDIO_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS == + static_cast<int>(CecMessageType::GIVE_SYSTEM_AUDIO_MODE_STATUS), + "CecMessageType::GIVE_SYSTEM_AUDIO_MODE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_SYSTEM_AUDIO_MODE_STATUS == + static_cast<int>(CecMessageType::SYSTEM_AUDIO_MODE_STATUS), + "CecMessageType::SYSTEM_AUDIO_MODE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_ROUTING_CHANGE == static_cast<int>(CecMessageType::ROUTING_CHANGE), + "CecMessageType::ROUTING_CHANGE must match legacy value."); +static_assert(CEC_MESSAGE_ROUTING_INFORMATION == + static_cast<int>(CecMessageType::ROUTING_INFORMATION), + "CecMessageType::ROUTING_INFORMATION must match legacy value."); +static_assert(CEC_MESSAGE_ACTIVE_SOURCE == static_cast<int>(CecMessageType::ACTIVE_SOURCE), + "CecMessageType::ACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS == + static_cast<int>(CecMessageType::GIVE_PHYSICAL_ADDRESS), + "CecMessageType::GIVE_PHYSICAL_ADDRESS must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS == + static_cast<int>(CecMessageType::REPORT_PHYSICAL_ADDRESS), + "CecMessageType::REPORT_PHYSICAL_ADDRESS must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ACTIVE_SOURCE == + static_cast<int>(CecMessageType::REQUEST_ACTIVE_SOURCE), + "CecMessageType::REQUEST_ACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_SET_STREAM_PATH == static_cast<int>(CecMessageType::SET_STREAM_PATH), + "CecMessageType::SET_STREAM_PATH must match legacy value."); +static_assert(CEC_MESSAGE_DEVICE_VENDOR_ID == static_cast<int>(CecMessageType::DEVICE_VENDOR_ID), + "CecMessageType::DEVICE_VENDOR_ID must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_COMMAND == static_cast<int>(CecMessageType::VENDOR_COMMAND), + "CecMessageType::VENDOR_COMMAND must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_REMOTE_BUTTON_DOWN == + static_cast<int>(CecMessageType::VENDOR_REMOTE_BUTTON_DOWN), + "CecMessageType::VENDOR_REMOTE_BUTTON_DOWN must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_REMOTE_BUTTON_UP == + static_cast<int>(CecMessageType::VENDOR_REMOTE_BUTTON_UP), + "CecMessageType::VENDOR_REMOTE_BUTTON_UP must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID == + static_cast<int>(CecMessageType::GIVE_DEVICE_VENDOR_ID), + "CecMessageType::GIVE_DEVICE_VENDOR_ID must match legacy value."); +static_assert(CEC_MESSAGE_MENU_REQUEST == static_cast<int>(CecMessageType::MENU_REQUEST), + "CecMessageType::MENU_REQUEST must match legacy value."); +static_assert(CEC_MESSAGE_MENU_STATUS == static_cast<int>(CecMessageType::MENU_STATUS), + "CecMessageType::MENU_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DEVICE_POWER_STATUS == + static_cast<int>(CecMessageType::GIVE_DEVICE_POWER_STATUS), + "CecMessageType::GIVE_DEVICE_POWER_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_POWER_STATUS == + static_cast<int>(CecMessageType::REPORT_POWER_STATUS), + "CecMessageType::REPORT_POWER_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GET_MENU_LANGUAGE == static_cast<int>(CecMessageType::GET_MENU_LANGUAGE), + "CecMessageType::GET_MENU_LANGUAGE must match legacy value."); +static_assert(CEC_MESSAGE_SELECT_ANALOG_SERVICE == + static_cast<int>(CecMessageType::SELECT_ANALOG_SERVICE), + "CecMessageType::SELECT_ANALOG_SERVICE must match legacy value."); +static_assert(CEC_MESSAGE_SELECT_DIGITAL_SERVICE == + static_cast<int>(CecMessageType::SELECT_DIGITAL_SERVICE), + "CecMessageType::SELECT_DIGITAL_SERVICE must match legacy value."); +static_assert(CEC_MESSAGE_SET_DIGITAL_TIMER == static_cast<int>(CecMessageType::SET_DIGITAL_TIMER), + "CecMessageType::SET_DIGITAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_CLEAR_DIGITAL_TIMER == + static_cast<int>(CecMessageType::CLEAR_DIGITAL_TIMER), + "CecMessageType::CLEAR_DIGITAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_SET_AUDIO_RATE == static_cast<int>(CecMessageType::SET_AUDIO_RATE), + "CecMessageType::SET_AUDIO_RATE must match legacy value."); +static_assert(CEC_MESSAGE_INACTIVE_SOURCE == static_cast<int>(CecMessageType::INACTIVE_SOURCE), + "CecMessageType::INACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_CEC_VERSION == static_cast<int>(CecMessageType::CEC_VERSION), + "CecMessageType::CEC_VERSION must match legacy value."); +static_assert(CEC_MESSAGE_GET_CEC_VERSION == static_cast<int>(CecMessageType::GET_CEC_VERSION), + "CecMessageType::GET_CEC_VERSION must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_COMMAND_WITH_ID == + static_cast<int>(CecMessageType::VENDOR_COMMAND_WITH_ID), + "CecMessageType::VENDOR_COMMAND_WITH_ID must match legacy value."); +static_assert(CEC_MESSAGE_CLEAR_EXTERNAL_TIMER == + static_cast<int>(CecMessageType::CLEAR_EXTERNAL_TIMER), + "CecMessageType::CLEAR_EXTERNAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_SET_EXTERNAL_TIMER == + static_cast<int>(CecMessageType::SET_EXTERNAL_TIMER), + "CecMessageType::SET_EXTERNAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_INITIATE_ARC == static_cast<int>(CecMessageType::INITIATE_ARC), + "CecMessageType::INITIATE_ARC must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_ARC_INITIATED == + static_cast<int>(CecMessageType::REPORT_ARC_INITIATED), + "CecMessageType::REPORT_ARC_INITIATED must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_ARC_TERMINATED == + static_cast<int>(CecMessageType::REPORT_ARC_TERMINATED), + "CecMessageType::REPORT_ARC_TERMINATED must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ARC_INITIATION == + static_cast<int>(CecMessageType::REQUEST_ARC_INITIATION), + "CecMessageType::REQUEST_ARC_INITIATION must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ARC_TERMINATION == + static_cast<int>(CecMessageType::REQUEST_ARC_TERMINATION), + "CecMessageType::REQUEST_ARC_TERMINATION must match legacy value."); +static_assert(CEC_MESSAGE_TERMINATE_ARC == static_cast<int>(CecMessageType::TERMINATE_ARC), + "CecMessageType::TERMINATE_ARC must match legacy value."); +static_assert(CEC_MESSAGE_ABORT == static_cast<int>(CecMessageType::ABORT), + "CecMessageType::ABORT must match legacy value."); + +static_assert(ABORT_UNRECOGNIZED_MODE == static_cast<int>(AbortReason::UNRECOGNIZED_MODE), + "AbortReason::UNRECOGNIZED_MODE must match legacy value."); +static_assert(ABORT_NOT_IN_CORRECT_MODE == static_cast<int>(AbortReason::NOT_IN_CORRECT_MODE), + "AbortReason::NOT_IN_CORRECT_MODE must match legacy value."); +static_assert(ABORT_CANNOT_PROVIDE_SOURCE == static_cast<int>(AbortReason::CANNOT_PROVIDE_SOURCE), + "AbortReason::CANNOT_PROVIDE_SOURCE must match legacy value."); +static_assert(ABORT_INVALID_OPERAND == static_cast<int>(AbortReason::INVALID_OPERAND), + "AbortReason::INVALID_OPERAND must match legacy value."); +static_assert(ABORT_REFUSED == static_cast<int>(AbortReason::REFUSED), + "AbortReason::REFUSED must match legacy value."); +static_assert(ABORT_UNABLE_TO_DETERMINE == static_cast<int>(AbortReason::UNABLE_TO_DETERMINE), + "AbortReason::UNABLE_TO_DETERMINE must match legacy value."); + +static_assert(HDMI_RESULT_SUCCESS == static_cast<int>(SendMessageResult::SUCCESS), + "SendMessageResult::SUCCESS must match legacy value."); +static_assert(HDMI_RESULT_NACK == static_cast<int>(SendMessageResult::NACK), + "SendMessageResult::NACK must match legacy value."); +static_assert(HDMI_RESULT_BUSY == static_cast<int>(SendMessageResult::BUSY), + "SendMessageResult::BUSY must match legacy value."); +static_assert(HDMI_RESULT_FAIL == static_cast<int>(SendMessageResult::FAIL), + "SendMessageResult::FAIL must match legacy value."); + +static_assert(HDMI_INPUT == static_cast<int>(HdmiPortType::INPUT), + "HdmiPortType::INPUT must match legacy value."); +static_assert(HDMI_OUTPUT == static_cast<int>(HdmiPortType::OUTPUT), + "HdmiPortType::OUTPUT must match legacy value."); + +static_assert(HDMI_OPTION_WAKEUP == static_cast<int>(OptionKey::WAKEUP), + "OptionKey::WAKEUP must match legacy value."); +static_assert(HDMI_OPTION_ENABLE_CEC == static_cast<int>(OptionKey::ENABLE_CEC), + "OptionKey::ENABLE_CEC must match legacy value."); +static_assert(HDMI_OPTION_SYSTEM_CEC_CONTROL == static_cast<int>(OptionKey::SYSTEM_CEC_CONTROL), + "OptionKey::SYSTEM_CEC_CONTROL must match legacy value."); + +sp<IHdmiCecCallback> HdmiCec::mCallback = nullptr; + +HdmiCec::HdmiCec(hdmi_cec_device_t* device) : mDevice(device) {} + +// Methods from ::android::hardware::tv::cec::V2_0::IHdmiCec follow. +Return<Result> HdmiCec::addDeviceType(CecDeviceType deviceType) { + // TODO implement + if (deviceType <= CecDeviceType::MAX) { + return Result::SUCCESS; + } else { + return Result::FAILURE_INVALID_ARGS; + } +} + +Return<void> HdmiCec::clearDeviceTypes() { + // TODO implement + return Void(); +} + +Return<void> HdmiCec::setAllDeviceTypes(CecAllDeviceTypes allDeviceTypes) { + // TODO implement + if (allDeviceTypes == 1) { + } + return Void(); +} + +Return<void> HdmiCec::setDeviceFeatures(CecDeviceType deviceType, + CecDeviceFeatures /* deviceFeatures */) { + // TODO implement + if (deviceType != CecDeviceType::MAX) { + } + return Void(); +} + +Return<void> HdmiCec::setRcProfile(CecDeviceType deviceType, const CecRcProfile& /* rcProfile */) { + // TODO implement + if (deviceType != CecDeviceType::MAX) { + } + return Void(); +} + +Return<void> HdmiCec::readDeviceInfo(CecLogicalAddress logicalAddress, + CecPhysicalAddress physicalAddress, + const readDeviceInfo_cb _hidl_cb) { + // TODO implement + CecDeviceInfo deviceInfo; + + if (logicalAddress == CecLogicalAddress::TV) { + _hidl_cb(Result::SUCCESS, deviceInfo); + if (physicalAddress) { + } + } + return Void(); +} + +Return<SendMessageResult> HdmiCec::sendMessage(const CecMessage& message) { + cec_message_t legacyMessage{ + .initiator = static_cast<cec_logical_address_t>(message.initiator), + .destination = static_cast<cec_logical_address_t>(message.destination), + .length = message.body.size(), + }; + for (size_t i = 0; i < message.body.size(); ++i) { + legacyMessage.body[i] = static_cast<unsigned char>(message.body[i]); + } + return static_cast<SendMessageResult>(mDevice->send_message(mDevice, &legacyMessage)); +} + +Return<void> HdmiCec::setCallback(const sp<IHdmiCecCallback>& callback) { + if (mCallback != nullptr) { + mCallback->unlinkToDeath(this); + mCallback = nullptr; + } + + if (callback != nullptr) { + mCallback = callback; + mCallback->linkToDeath(this, 0 /*cookie*/); + mDevice->register_event_callback(mDevice, eventCallback, nullptr); + } + return Void(); +} + +Return<void> HdmiCec::getPortInfo(getPortInfo_cb _hidl_cb) { + struct hdmi_port_info* legacyPorts; + int numPorts; + hidl_vec<HdmiPortInfo> portInfos; + mDevice->get_port_info(mDevice, &legacyPorts, &numPorts); + portInfos.resize(numPorts); + for (int i = 0; i < numPorts; ++i) { + portInfos[i] = {.type = static_cast<HdmiPortType>(legacyPorts[i].type), + .portId = static_cast<HdmiPortId>(legacyPorts[i].port_id), + .cecSupported = legacyPorts[i].cec_supported != 0, + .arcSupported = legacyPorts[i].arc_supported != 0, + .physicalAddress = legacyPorts[i].physical_address}; + } + _hidl_cb(portInfos); + return Void(); +} + +Return<void> HdmiCec::setOption(OptionKey key, bool value) { + mDevice->set_option(mDevice, static_cast<int>(key), value ? 1 : 0); + return Void(); +} + +Return<void> HdmiCec::setLanguage(const hidl_string& language) { + if (language.size() != 3) { + LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size() + << "."; + return Void(); + } + const char* languageStr = language.c_str(); + int convertedLanguage = ((languageStr[0] & 0xFF) << 16) | ((languageStr[1] & 0xFF) << 8) | + (languageStr[2] & 0xFF); + mDevice->set_option(mDevice, HDMI_OPTION_SET_LANG, convertedLanguage); + return Void(); +} + +Return<void> HdmiCec::enableAudioReturnChannel(HdmiPortId portId, bool enable) { + mDevice->set_audio_return_channel(mDevice, portId, enable ? 1 : 0); + return Void(); +} + +Return<bool> HdmiCec::isConnected(HdmiPortId portId) { + return mDevice->is_connected(mDevice, portId) > 0; +} + +IHdmiCec* HIDL_FETCH_IHdmiCec(const char* hal) { + hdmi_cec_device_t* hdmi_cec_device; + int ret = 0; + const hw_module_t* hw_module = nullptr; + + ret = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, &hw_module); + if (ret == 0) { + ret = hdmi_cec_open(hw_module, &hdmi_cec_device); + if (ret != 0) { + LOG(ERROR) << "hdmi_cec_open " << hal << " failed: " << ret; + } + } else { + LOG(ERROR) << "hw_get_module " << hal << " failed: " << ret; + } + + if (ret == 0) { + return new HdmiCec(hdmi_cec_device); + } else { + LOG(ERROR) << "Passthrough failed to load legacy HAL."; + return nullptr; + } +} + +} // namespace implementation +} // namespace V2_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android diff --git a/tv/cec/2.0/default/HdmiCec.h b/tv/cec/2.0/default/HdmiCec.h new file mode 100644 index 0000000000..ab5477089f --- /dev/null +++ b/tv/cec/2.0/default/HdmiCec.h @@ -0,0 +1,115 @@ +/* + * 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 ANDROID_HARDWARE_TV_CEC_V2_0_HDMICEC_H +#define ANDROID_HARDWARE_TV_CEC_V2_0_HDMICEC_H + +#include <algorithm> + +#include <android/hardware/tv/cec/2.0/IHdmiCec.h> +#include <hardware/hardware.h> +#include <hardware/hdmi_cec.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V2_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::tv::cec::V2_0::CecLogicalAddress; +using ::android::hardware::tv::cec::V2_0::CecMessage; +using ::android::hardware::tv::cec::V2_0::CecPhysicalAddress; +using ::android::hardware::tv::cec::V2_0::HdmiPortId; +using ::android::hardware::tv::cec::V2_0::HdmiPortInfo; +using ::android::hardware::tv::cec::V2_0::IHdmiCec; +using ::android::hardware::tv::cec::V2_0::IHdmiCecCallback; +using ::android::hardware::tv::cec::V2_0::MaxLength; +using ::android::hardware::tv::cec::V2_0::OptionKey; +using ::android::hardware::tv::cec::V2_0::Result; +using ::android::hardware::tv::cec::V2_0::SendMessageResult; + +struct HdmiCec : public IHdmiCec, public hidl_death_recipient { + HdmiCec(hdmi_cec_device_t* device); + // Methods from ::android::hardware::tv::cec::V2_0::IHdmiCec follow. + Return<Result> addDeviceType(CecDeviceType deviceType) override; + Return<void> clearDeviceTypes() override; + Return<void> setAllDeviceTypes(CecAllDeviceTypes allDeviceTypes) override; + Return<void> setDeviceFeatures(CecDeviceType deviceType, + CecDeviceFeatures /* deviceFeatures */) override; + Return<void> setRcProfile(CecDeviceType deviceType, + const CecRcProfile& /* rcProfile */) override; + Return<void> readDeviceInfo(CecLogicalAddress logicalAddress, + CecPhysicalAddress physicalAddress, + const readDeviceInfo_cb _hidl_cb) override; + Return<SendMessageResult> sendMessage(const CecMessage& message) override; + Return<void> setCallback(const sp<IHdmiCecCallback>& callback) override; + Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override; + Return<void> setOption(OptionKey key, bool value) override; + Return<void> setLanguage(const hidl_string& language) override; + Return<void> enableAudioReturnChannel(HdmiPortId portId, bool enable) override; + Return<bool> isConnected(HdmiPortId portId) override; + + static void eventCallback(const hdmi_event_t* event, void* /* arg */) { + if (mCallback != nullptr && event != nullptr) { + if (event->type == HDMI_EVENT_CEC_MESSAGE) { + size_t length = + std::min(event->cec.length, static_cast<size_t>(MaxLength::MESSAGE_BODY)); + CecMessage cecMessage{ + .initiator = static_cast<CecLogicalAddress>(event->cec.initiator), + .destination = static_cast<CecLogicalAddress>(event->cec.destination), + }; + cecMessage.body.resize(length); + for (size_t i = 0; i < length; ++i) { + cecMessage.body[i] = static_cast<uint8_t>(event->cec.body[i]); + } + mCallback->onCecMessage(cecMessage); + } else if (event->type == HDMI_EVENT_HOT_PLUG) { + HotplugEvent hotplugEvent{ + .connected = event->hotplug.connected > 0, + .portId = static_cast<HdmiPortId>(event->hotplug.port_id)}; + mCallback->onHotplugEvent(hotplugEvent); + } + } + } + + virtual void serviceDied(uint64_t /*cookie*/, + const wp<::android::hidl::base::V1_0::IBase>& /*who*/) { + setCallback(nullptr); + } + + private: + static sp<IHdmiCecCallback> mCallback; + const hdmi_cec_device_t* mDevice; +}; + +extern "C" IHdmiCec* HIDL_FETCH_IHdmiCec(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_CEC_V2_0_HDMICEC_H diff --git a/tv/cec/2.0/default/OWNERS b/tv/cec/2.0/default/OWNERS new file mode 100644 index 0000000000..1b3d095f9c --- /dev/null +++ b/tv/cec/2.0/default/OWNERS @@ -0,0 +1,4 @@ +nchalko@google.com +amyjojo@google.com +shubang@google.com +quxiangfang@google.com diff --git a/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.rc b/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.rc new file mode 100644 index 0000000000..1e8cd8052c --- /dev/null +++ b/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.rc @@ -0,0 +1,4 @@ +service vendor.cec-hal-2-0 /vendor/bin/hw/android.hardware.tv.cec@2.0-service + class hal + user system + group system diff --git a/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.xml b/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.xml new file mode 100644 index 0000000000..61fb1bbf9b --- /dev/null +++ b/tv/cec/2.0/default/android.hardware.tv.cec@2.0-service.xml @@ -0,0 +1,11 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.tv.cec</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>IHdmiCec</name> + <instance>default</instance> + </interface> + </hal> +</manifest> diff --git a/audio/core/2.0/default/include/core/2.0/default/Conversions.h b/tv/cec/2.0/default/service.cpp index b3a6ea886e..dacc38cc9d 100644 --- a/audio/core/2.0/default/include/core/2.0/default/Conversions.h +++ b/tv/cec/2.0/default/service.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -14,13 +14,14 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_AUDIO_V2_0_CONVERSIONS_H_ -#define ANDROID_HARDWARE_AUDIO_V2_0_CONVERSIONS_H_ +#define LOG_TAG "android.hardware.tv.cec@2.0-service" -#include <android/hardware/audio/2.0/types.h> +#include <android/hardware/tv/cec/2.0/IHdmiCec.h> +#include <hidl/LegacySupport.h> -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/Conversions.h> -#undef AUDIO_HAL_VERSION +using android::hardware::defaultPassthroughServiceImplementation; +using android::hardware::tv::cec::V2_0::IHdmiCec; -#endif // ANDROID_HARDWARE_AUDIO_V2_0_CONVERSIONS_H_ +int main() { + return defaultPassthroughServiceImplementation<IHdmiCec>(); +} diff --git a/tv/cec/2.0/types.hal b/tv/cec/2.0/types.hal new file mode 100644 index 0000000000..cad6c396e9 --- /dev/null +++ b/tv/cec/2.0/types.hal @@ -0,0 +1,548 @@ +/* + * 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. + */ + +package android.hardware.tv.cec@2.0; + +import android.hidl.safe_union@1.0; + +/** + * CEC device type as specified in CEC Table 11-7 of the CEC spec 2.0b. + */ +enum CecDeviceType : int32_t { + INACTIVE = -1, + TV = 0, + RECORDER = 1, + TUNER = 3, + PLAYBACK = 4, + AUDIO_SYSTEM = 5, + PURE_CEC_SWITCH = 6, + PROCESSOR = 7, + MAX = PROCESSOR, +}; + +/** + * CEC logical address as specified in CEC Table 11-9 of the CEC spec 2.0b. + */ +enum CecLogicalAddress : int32_t { + TV = 0, + RECORDER_1 = 1, + RECORDER_2 = 2, + TUNER_1 = 3, + PLAYBACK_1 = 4, + AUDIO_SYSTEM = 5, + TUNER_2 = 6, + TUNER_3 = 7, + PLAYBACK_2 = 8, + RECORDER_3 = 9, + TUNER_4 = 10, + PLAYBACK_3 = 11, + BACKUP_1 = 12, // backup1 for Playback/Recording/Tuner/Processor device + BACKUP_2 = 13, // backup2 for Playback/Recording/Tuner/Processor device + SPECIFIC_USE = 14, + UNREGISTERED = 15, // as Initiator address + BROADCAST = 15, // as Destination address +}; + +/** + * HDMI CEC message types. + * + * The assigned values represent opcode used in CEC frame as specified in + * Section 11.10 of the CEC spec 2.0b on top of Section CEC 15 of the CEC + * Spec 1.4b. + */ +enum CecMessageType : int32_t { + FEATURE_ABORT = 0x00, + IMAGE_VIEW_ON = 0x04, + TUNER_STEP_INCREMENT = 0x05, + TUNER_STEP_DECREMENT = 0x06, + TUNER_DEVICE_STATUS = 0x07, + GIVE_TUNER_DEVICE_STATUS = 0x08, + RECORD_ON = 0x09, + RECORD_STATUS = 0x0A, + RECORD_OFF = 0x0B, + TEXT_VIEW_ON = 0x0D, + RECORD_TV_SCREEN = 0x0F, + GIVE_DECK_STATUS = 0x1A, + DECK_STATUS = 0x1B, + SET_MENU_LANGUAGE = 0x32, + CLEAR_ANALOG_TIMER = 0x33, + SET_ANALOG_TIMER = 0x34, + TIMER_STATUS = 0x35, + STANDBY = 0x36, + PLAY = 0x41, + DECK_CONTROL = 0x42, + TIMER_CLEARED_STATUS = 0x43, + USER_CONTROL_PRESSED = 0x44, + USER_CONTROL_RELEASED = 0x45, + GIVE_OSD_NAME = 0x46, + SET_OSD_NAME = 0x47, + SET_OSD_STRING = 0x64, + SET_TIMER_PROGRAM_TITLE = 0x67, + SYSTEM_AUDIO_MODE_REQUEST = 0x70, + GIVE_AUDIO_STATUS = 0x71, + SET_SYSTEM_AUDIO_MODE = 0x72, + REPORT_AUDIO_STATUS = 0x7A, + GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D, + SYSTEM_AUDIO_MODE_STATUS = 0x7E, + ROUTING_CHANGE = 0x80, + ROUTING_INFORMATION = 0x81, + ACTIVE_SOURCE = 0x82, + GIVE_PHYSICAL_ADDRESS = 0x83, + REPORT_PHYSICAL_ADDRESS = 0x84, + REQUEST_ACTIVE_SOURCE = 0x85, + SET_STREAM_PATH = 0x86, + DEVICE_VENDOR_ID = 0x87, + VENDOR_COMMAND = 0x89, + VENDOR_REMOTE_BUTTON_DOWN = 0x8A, + VENDOR_REMOTE_BUTTON_UP = 0x8B, + GIVE_DEVICE_VENDOR_ID = 0x8C, + MENU_REQUEST = 0x8D, + MENU_STATUS = 0x8E, + GIVE_DEVICE_POWER_STATUS = 0x8F, + REPORT_POWER_STATUS = 0x90, + GET_MENU_LANGUAGE = 0x91, + SELECT_ANALOG_SERVICE = 0x92, + SELECT_DIGITAL_SERVICE = 0x93, + SET_DIGITAL_TIMER = 0x97, + CLEAR_DIGITAL_TIMER = 0x99, + SET_AUDIO_RATE = 0x9A, + INACTIVE_SOURCE = 0x9D, + CEC_VERSION = 0x9E, + GET_CEC_VERSION = 0x9F, + VENDOR_COMMAND_WITH_ID = 0xA0, + CLEAR_EXTERNAL_TIMER = 0xA1, + SET_EXTERNAL_TIMER = 0xA2, + REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3, + REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4, + GIVE_FEATURES = 0XA5, + REPORT_FEATURES = 0xA6, + REQUEST_CURRENT_LATENCY = 0xA7, + REPORT_CURRENT_LATENCY = 0xA8, + INITIATE_ARC = 0xC0, + REPORT_ARC_INITIATED = 0xC1, + REPORT_ARC_TERMINATED = 0xC2, + REQUEST_ARC_INITIATION = 0xC3, + REQUEST_ARC_TERMINATION = 0xC4, + TERMINATE_ARC = 0xC5, + ABORT = 0xFF, + POLLING_MESSAGE = 0xFFFFFF00, // used for cec polling message +}; + +/** + * Abort Reason as specified in CEC Table 29 of the CEC spec 1.4b. + */ +enum AbortReason : int32_t { + UNRECOGNIZED_MODE = 0, + NOT_IN_CORRECT_MODE = 1, + CANNOT_PROVIDE_SOURCE = 2, + INVALID_OPERAND = 3, + REFUSED = 4, + UNABLE_TO_DETERMINE = 5, +}; + +enum MaxLength : int32_t { + MESSAGE_BODY = 14, +}; + +struct CecMessage { + /** logical address of sender */ + CecLogicalAddress initiator; + + /** logical address of receiver */ + CecLogicalAddress destination; + + /** cec message type */ + CecMessageType cecMessageType; + + /** + * The maximum size of body is 14 (MaxLength::MESSAGE_BODY) as specified in + * the section 6 of the CEC Spec 1.4b. Overflowed data must be ignored. + */ + vec<uint8_t> body; +}; + +/** + * error code used for send_message. + */ +enum SendMessageResult : int32_t { + SUCCESS = 0, + NACK = 1, // not acknowledged + BUSY = 2, // bus is busy + FAIL = 3, +}; + +/** + * CEC All Device Type Value as specified in Table 11-30 of the CEC spec 2.0b. + */ +enum CecAllDeviceTypeValue : uint8_t { + RESERVED_DEVICE_2 = 1 << 0, + RESERVED_DEVICE_1 = 1 << 1, + CEC_SWITCH_DEVICE = 1 << 2, + AUDIO_DEVICE = 1 << 3, + PLAYBACK_DEVICE = 1 << 4, + TUNER_DEVICE = 1 << 5, + RECORDING_DEVICE = 1 << 6, + TV_DEVICE = 1 << 7, +}; + +/** + * CEC All Device Types + * + * It is a combination of all supported type from CecAllDeviceTypeValue. + * For example a record with tuner functionalitye, + * cecAllDeviceTypes = ((CecAllDeviceTypeValue::RECORDING_DEVICE) + * |(CecAllDeviceTypeValue::TUNER_DEVICE)) + */ +typedef bitfield<CecAllDeviceTypeValue> CecAllDeviceTypes; + +/** + * CEC Versions as specified in CEC Table 11-30 of the CEC spec 2.0b. + */ +enum CecVersion : int32_t { + V_1_3_A = 0x04, + V_1_4 = 0x05, // indicate CEC 1.4, 1.4a or 1.4b + V_2_0 = 0x06, +}; + +/** + * Device Feature + * + * It is specified in CEC Table 11-30 of the CEC spec 2.0b. As a uint32 there + * is room for future extensions aka DeviceFeature2 through DeviceFeature4. + */ +enum CecDeviceFeature : uint32_t { + RESERVED = 1 << 0, + SOURCE_SUPPORT_ARC_RX = 1 << 1, + SINK_SUPPORT_ARC_TX = 1 << 2, + SOURCE_SUPPORT_SET_AUDIO_RATE = 1 << 3, + SUPPORT_CONTROLLED_BY_DECK = 1 << 4, + TV_SUPPORT_SET_OSD_STRINGS = 1 << 5, + TV_SUPPORT_RECORD_TV_SCREEN = 1 << 6, +}; + +/** + * CEC Device Features + * + * It is a combination of all supported features from CecDeviceFeature. + * For example a TV with OSD and ARC capabilities, + * CecDeviceFeatures = ((CecDeviceFeature::TV_SUPPORT_SET_OSD_STRINGS) + * |(CecDeviceFeature::SINK_SUPPORT_ARC_TX)) + */ +typedef bitfield<CecDeviceFeature> CecDeviceFeatures; + +/** + * Remote Control Profile + * + * It is specified in CEC Table 11-30 of the CEC spec 2.0b. + */ +enum CecRcProfileId : uint8_t { + NONE = 0, // TV doesn’t support any of these profiles + RC_PROFILE_1 = 0x02, // minimalistic zapper (low button count) + RC_PROFILE_2 = 0x06, // intermediate between profile 1 and profile 3 + RC_PROFILE_3 = 0x0A, // typical TV remote + RC_PROFILE_4 = 0x0E, // extended form of profile 3 +}; + +/** + * Remote Control Profile Source + * + * It is specified in CEC Table 11-30 of the CEC spec 2.0b. + */ +enum CecRcProfileSource : uint8_t { + MEDIA_CONTEXT_SENSITIVE = 1 << 0, // source can handle UI command 0x11 + MEDIA_TO = 1 << 1, // source can handle UI command 0x10 + CONTENTS = 1 << 2, // source can handle UI command 0x0B + DEVICE_SETUP = 1 << 3, // source can handle UI command 0x0A + DEVICE_ROOT = 1 << 4, // source can handle UI command 0x09 + SOURCE_FLAG = 1 << 6, // Indicate the profile is for source +}; + +/** + * Remote Control Profile for either TV or Source. + */ +safe_union CecRcProfile1 { + /** CEC remote control profile for TV. */ + CecRcProfileId profileId; + + /* CEC remote control profile for source + * + * It is a combination of all supported profiles from CecRcProfileSource. + * For example a playback device support root menu and setup menu, + * profileSource = ((CecRcProfileSource::DEVICE_ROOT) + * |(CecRcProfileSource::DEVICE_SETUP) + * |(CecRcProfileSource::SOURCE_FLAG)) + */ + bitfield<CecRcProfileSource> profileSource; +}; + +/** + * CEC Remote Control Profiles + * + * CEC 2.0 only use one byte to represent Remote Control Profile. + */ +struct CecRcProfile { + CecRcProfile1 rcProfile1; +}; + +/** + * CEC device power states as specified in CEC Table 11-10 of the CEC spec 2.0b + */ +enum CecPowerState : int8_t { + ON = 0, + STANDBY = 1, + ON_TO_STANDBY = 2, + STANDBY_TO_ON = 4, + UNKNOWN = 0xFF, // some devices may not report power status +}; + +/** CEC physical address of device */ +typedef uint16_t CecPhysicalAddress; + +/** + * CEC device information + * + * It is initially built during addressing specified in CEC section 11.3 of + * the CEC spec 2.0b. It may be updated with cec devices's status changed. + */ +struct CecDeviceInfo { + /** CEC version which device supports */ + CecVersion version; + + /** CEC device primary type */ + CecDeviceType devceType; + + /** CEC all device types */ + CecAllDeviceTypes allDeviceTypes; + + /** CEC device features */ + CecDeviceFeatures deviceFeatures; + + /** CEC Device Remote Control Profile */ + CecRcProfile rcProfile; + + /** CEC Device Vendor ID */ + uint32_t vendorId; + + /** logical address of device */ + CecLogicalAddress logicalAddress; + + /** physical of device */ + CecPhysicalAddress physicalAddress; + + /** power status of device */ + CecPowerState powerState; +}; + +/** + * Topology Event Type. + */ +enum CecTopologyEventType : int32_t { + DEVICE_ADDED, + DEVICE_REMOVED, + DEVICE_UPDATED, +}; + +/** + * Topology Event. + */ +struct CecTopologyEvent { + CecTopologyEventType eventType; + CecLogicalAddress logicalAddress; + CecPhysicalAddress physicalAddress; + + /** true if the event is about the device which the system run on */ + bool isHostDevice; +}; + + +/** + * CEC UI Command Codes as specified in CEC Table 11-31 of the CEC spec 2.0b + */ +enum CecUICommandCodes : int32_t { + SELECT_OK = 0x00, + UP = 0x01, + DOWN = 0x02, + LEFT = 0x03, + RIGHT = 0x04, + RIGHT_UP = 0x05, + RIGHT_DOWN = 0x06, + LEFT_UP = 0x07, + LEFT_DOWN = 0x08, + DEVICE_ROOT_MENU = 0x09, + DEVICE_SETUP_MENU = 0x0A, + CONTENTS_MENU = 0x0B, + FAVORITE_MENU = 0x0C, + BACK = 0x0D, + MEDIA_TOP_MENU = 0x10, + MEDIA_CONTEXT_SENSITIVE_MENU = 0x11, + NUMBER_ENTRY_MODE = 0x1D, + NUMBER_11 = 0x1E, + NUMBER_12 = 0x1F, + NUMBER_0 = 0x20, // or NUMBER 10 + NUMBER_1 = 0x21, + NUMBER_2 = 0x22, + NUMBER_3 = 0x23, + NUMBER_4 = 0x24, + NUMBER_5 = 0x25, + NUMBER_6 = 0x26, + NUMBER_7 = 0x27, + NUMBER_8 = 0x28, + NUMBER_9 = 0x29, + DOT = 0x2A, + ENTER = 0x2B, + CLEAR = 0x2C, + NEXT_FAVORITE = 0x2F, + CHANNEL_UP = 0x30, + CHANNEL_DOWN = 0x31, + PREVIOUS_CHANNEL = 0x32, + SOUND_SELECT = 0x33, + INPUT_SELECT = 0x34, + DISPLAY_INFORMATION = 0x35, + HELP = 0x36, + PAGE_UP = 0x37, + PAGE_DOWN = 0x38, + POWER = 0x40, + VOLUME_UP = 0x41, + VOLUME_DOWN = 0x42, + MUTE = 0x43, + PLAY = 0x44, + STOP = 0x45, + PAUSE = 0x46, + RECORD = 0x47, + REWIND = 0x48, + FAST_FORWARD = 0x49, + EJECT = 0x4A, + SKIP_FORWARD = 0x4B, + SKIP_BACKWARD = 0x4C, + STOP_RECORD = 0x4D, + PAUSE_RECORD = 0x4E, + ANGLE = 0x50, + SUB_PICTURE = 0x51, + VIDEO_ON_DEMAND = 0x52, + ELECTRONIC_PROGRAM_GUIDE = 0x53, + TIMER_PROGRAMMING = 0x54, + INITIAL_CONFIGURATION = 0x55, + SELECT_BROADCAST_TYPE = 0x56, + SELECT_SOUND_PRESENTATION = 0x57, + AUDIO_DESCRIPTION = 0x58, + INTERNET = 0x59, + THREE_DIMENSIONAL_MODE = 0x5A, + PLAY_FUNCTION = 0x60, + PAUSE_PLAY_FUNCTION = 0x61, + RECORD_FUNCTION = 0x62, + PAUSE_RECORD_FUNCTION = 0x63, + STOP_FUNCTION = 0x64, + MUTE_FUNCTION = 0x65, + RESTORE_VOLUME_FUNCTION = 0x66, + TUNE_FUNCTION = 0x67, + SELECT_MEDIA_FUNCTION = 0x68, + SELECT_AV_INPUT_FUNCTION = 0x69, + SELECT_AUDIO_INPUT_FUNCTION = 0x6A, + POWER_TOGGLE_FUNCTION = 0x6B, + POWER_OFF_FUNCTION = 0x6C, + POWER_ON_FUNCTION = 0x6D, + F1 = 0x71, // BLUE + F2 = 0x72, // RED + F3 = 0x73, // GREEN + F4 = 0x74, // YELLOW + F5 = 0x75, + DATA = 0x76, +}; + +/** + * HDMI port type. + */ +enum HdmiPortType : int32_t { + INPUT = 0, + OUTPUT = 1, +}; + +/** + * Options used for IHdmiCec.setOption() + */ +enum OptionKey : int32_t { + /** + * When set to false, HAL does not wake up the system upon receiving <Image + * View On> or <Text View On>. Used when user changes the TV settings to + * disable the auto TV on functionality. + * Deprecated since <Image View On> and <Text View On> become mandatory + * featrues for CEC device. Use ENABLE_CEC OptionKey to disable CEC + * functionality instead. + * True by Default + */ + WAKEUP = 1, + + /** + * When set to false, all the CEC commands are discarded. if logical address + * is ever used, it shall be released. Used when user changes the TV + * settings to disable CEC functionality. + * True by default. + * + */ + ENABLE_CEC = 2, + + /** + * Setting this flag to false means Android system must stop handling CEC + * service and yield the control over to the microprocessor that is powered + * on through the standby mode.The microprocessor shall keep current logical + * and physical address. It shall response POLLING_MESSAGE, GIVE_FEATURES, + * GIVE_DEVICE_POWER_STATUS,GIVE_DEVICE_VENDOR_ID and GIVE_PHYSICAL_ADDRESS + * to allow other CEC devices to build CEC devices map specified in CEC + * section 11.3 of the CEC spec 2.0b. + * When set to true, the system must gain the control over, hence telling + * the microprocessor to start forwarding CEC messages to Android system. + * For example, this may be called when system goes in and out of + * standby mode to notify the microprocessor that it should start/stop + * handling CEC commands on behalf of the system. + * True by default. + */ + SYSTEM_CEC_CONTROL = 3, + + /* Option 4 not used */ +}; + +/** + * Hdmi port ID. + * + * It shall start from 1 which corresponds to HDMI "port 1". + */ +typedef uint32_t HdmiPortId; + +/** Hdmi hotplug event */ +struct HotplugEvent { + bool connected; + HdmiPortId portId; +}; + +/** + * HDMI port descriptor + */ +struct HdmiPortInfo { + HdmiPortType type; + HdmiPortId portId; + bool cecSupported; + bool arcSupported; + CecPhysicalAddress physicalAddress; +}; + +enum Result : int32_t { + SUCCESS = 0, + FAILURE_UNKNOWN = 1, + FAILURE_INVALID_ARGS = 2, + FAILURE_INVALID_STATE = 3, + FAILURE_NOT_SUPPORTED = 4, + FAILURE_BUSY = 5, +}; diff --git a/update-base-files.sh b/update-base-files.sh index 75d2be5d61..daaa53017b 100755 --- a/update-base-files.sh +++ b/update-base-files.sh @@ -36,6 +36,9 @@ hidl-gen $options \ hidl-gen $options \ -o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base-v1.1.h \ android.hardware.graphics.common@1.1 +hidl-gen $options \ + -o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base-v1.2.h \ + android.hardware.graphics.common@1.2 # system/media hidl-gen $options \ diff --git a/usb/1.2/Android.bp b/usb/1.2/Android.bp new file mode 100644 index 0000000000..55ffad06b1 --- /dev/null +++ b/usb/1.2/Android.bp @@ -0,0 +1,29 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.usb@1.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IUsb.hal", + "IUsbCallback.hal", + ], + interfaces: [ + "android.hardware.usb@1.0", + "android.hardware.usb@1.1", + "android.hidl.base@1.0", + ], + types: [ + "ContaminantDetectionStatus", + "ContaminantProtectionMode", + "ContaminantProtectionStatus", + "PortStatus", + "Status", + ], + gen_java: true, + gen_java_constants: true, +} + diff --git a/usb/1.2/IUsb.hal b/usb/1.2/IUsb.hal new file mode 100644 index 0000000000..ecc911ebf2 --- /dev/null +++ b/usb/1.2/IUsb.hal @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package android.hardware.usb@1.2; + +import android.hardware.usb@1.1::IUsb; + +/** + * The setCallback function in V1_0 is used to register the V1_2 + * IUsbCallback object as well. The implementation can use the + * castFrom method to cast the IUsbCallback object. + */ +interface IUsb extends @1.1::IUsb { + /** + * When supportsEnableContaminantPresenceDetection is true, + * enableContaminantPresenceDetection enables/disables contaminant + * presence detection algorithm. Calling enableContaminantPresenceDetection + * when supportsEnableContaminantPresenceDetection is false does + * not have any effect. + * Change in contantaminant presence status should notify should + * be notified to the client via notifyPortStatusChange_1_2 through + * PortStatus. + * + * @param portName name of the port. + * @param enable true Enable contaminant presence detection algorithm. + * false Disable contaminant presence detection algorithm. + */ + oneway enableContaminantPresenceDetection(string portName, bool enable); + + /** + * When supportsEnableContaminantPresenceProtection is true, + * enableContaminantPresenceProtection enables/disables contaminant + * presence protection algorithm. Calling + * enableContaminantPresenceProtection + * when supportsEnableContaminantPresenceProtection is false does + * not have any effect. + * Used to enable/disable contaminant presence protection algorithm. + * Enabling port protection algoritm must make the lower layers to autonomously + * act on taking the corresponding preventive measure mentioned at + * ContaminantProtectionModes when contaminant is detected on the USB Port. + * Calling this method with enable set to true must set to contaminantProtectionEnabled + * to true upon success and vice versa. + * currentContaminantProtectionMode should be updated whenever there is a + * change in the status of contaminant presence protection algorithm. + * + * @param portName name of the port. + * @param enable true Reduce capabilities of the port to protect port + * from damage due to contaminant presence. + * false No action is taken upon contaminant presence. + */ + oneway enableContaminantPresenceProtection(string portName, bool enable); +}; diff --git a/usb/1.2/IUsbCallback.hal b/usb/1.2/IUsbCallback.hal new file mode 100644 index 0000000000..8cc16df10c --- /dev/null +++ b/usb/1.2/IUsbCallback.hal @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package android.hardware.usb@1.2; + +import android.hardware.usb@1.1::IUsbCallback; +import android.hardware.usb@1.0::Status; + +/** + * Callback object used for all the IUsb async methods which expects a result. + * Caller is expected to register the callback object using setCallback method + * to receive updates on the PortStatus. + */ +interface IUsbCallback extends @1.1::IUsbCallback { + /** + * Used to convey the current port status to the caller. + * Must be called either when PortState changes due to the port partner or + * when caller requested for the PortStatus update through queryPortStatus. + * + * @param currentPortStatus vector object of current status(PortStatus + * of all the typeC ports in the device. + * @param retval SUCCESS when the required information was enquired form + * kernel and the PortStatus_1_2 object was built. + * ERROR otherwise. + */ + oneway notifyPortStatusChange_1_2(vec<PortStatus> currentPortStatus, + @1.0::Status retval); +}; + diff --git a/usb/1.2/types.hal b/usb/1.2/types.hal new file mode 100644 index 0000000000..081a64391b --- /dev/null +++ b/usb/1.2/types.hal @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package android.hardware.usb@1.2; + +import android.hardware.usb@1.1::PortStatus_1_1; +import android.hardware.usb@1.0::Status; + +enum Status : @1.0::Status { + /** + * Error value returned when the operation is not supported. + */ + NOT_SUPPORTED = 4, +}; + +@export +enum ContaminantDetectionStatus : uint32_t { + /** + * Contaminant presence detection is not supported. + */ + NOT_SUPPORTED = 0, + + /** + * Contaminant presence detection is supported but disabled. + */ + DISABLED = 1, + + /** + * Contaminant presence detection is enabled and contaminant not detected. + */ + NOT_DETECTED = 2, + + /** + * Contaminant presence detection is enabled and contaminant detected. + */ + DETECTED = 3, +}; + +@export +enum ContaminantProtectionMode : uint32_t { + /** + * No action performed upon detection of contaminant presence. + */ + NONE = 0, + + /** + * Upon detection of contaminant presence, Port is forced to sink only + * mode where a port shall only detect chargers until contaminant presence + * is no longer detected. + */ + FORCE_SINK = 1 << 0, + + /** + * Upon detection of contaminant presence, Port is forced to source only + * mode where a port shall only detect usb accessories such as headsets + * until contaminant presence is no longer detected. + */ + FORCE_SOURCE = 1 << 1, + + /** + * Upon detection of contaminant presence, port is disabled until contaminant + * presence is no longer detected. In the disabled state port will + * not respond to connection of chargers or usb accessories. + */ + FORCE_DISABLE = 1 << 2, +}; + +@export +enum ContaminantProtectionStatus : ContaminantProtectionMode { + /** + * Client disabled cotaminant protection by calling + * enableContaminantPresencePortProtection set to false. Low level drivers should + * not autmomously take any corrective action when contaminant presence is detected. + */ + DISABLED = 1 << 3, +}; + +struct PortStatus { + PortStatus_1_1 status_1_1; + + /** + * Contaminant presence protection modes supported by the port. + */ + bitfield<ContaminantProtectionMode> supportedContaminantProtectionModes; + + /** + * Client can enable/disable contaminant presence protection through + * enableContaminantPresenceProtection when true. + */ + bool supportsEnableContaminantPresenceProtection; + + /** + * Contaminant presence protection modes currently active for the port. + */ + ContaminantProtectionStatus contaminantProtectionStatus; + + /** + * Client can enable/disable contaminant presence detection through + * enableContaminantPresenceDetection when true. + */ + bool supportsEnableContaminantPresenceDetection; + + /** + * Current status of contaminant detection algorithm. + */ + ContaminantDetectionStatus contaminantDetectionStatus; +}; diff --git a/usb/1.2/vts/OWNERS b/usb/1.2/vts/OWNERS new file mode 100644 index 0000000000..f60d39a3b4 --- /dev/null +++ b/usb/1.2/vts/OWNERS @@ -0,0 +1,2 @@ +badhri@google.com +yim@google.com diff --git a/audio/core/2.0/vts/functional/Android.bp b/usb/1.2/vts/functional/Android.bp index c8441cf8e5..761d37f184 100644 --- a/audio/core/2.0/vts/functional/Android.bp +++ b/usb/1.2/vts/functional/Android.bp @@ -1,5 +1,5 @@ // -// Copyright (C) 2017 The Android Open Source Project +// 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. @@ -15,20 +15,14 @@ // cc_test { - name: "VtsHalAudioV2_0TargetTest", + name: "VtsHalUsbV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], - srcs: [ - "AudioPrimaryHidlHalTest.cpp", - "ValidateAudioConfiguration.cpp" - ], + srcs: ["VtsHalUsbV1_2TargetTest.cpp"], static_libs: [ - "android.hardware.audio.common.test.utility", - "android.hardware.audio@2.0", - "android.hardware.audio.common@2.0", - "libicuuc", - "libicuuc_stubdata", - "libandroidicu", - "libxml2", + "android.hardware.usb@1.0", + "android.hardware.usb@1.1", + "android.hardware.usb@1.2", ], test_suites: ["general-tests"], } + diff --git a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp new file mode 100644 index 0000000000..7b3dea938e --- /dev/null +++ b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp @@ -0,0 +1,380 @@ +/* + * 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. + */ + +#define LOG_TAG "VtsHalUsbV1_2TargetTest" +#include <android-base/logging.h> + +#include <android/hardware/usb/1.2/IUsb.h> +#include <android/hardware/usb/1.2/IUsbCallback.h> +#include <android/hardware/usb/1.2/types.h> + +#include <VtsHalHidlTargetCallbackBase.h> +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> +#include <log/log.h> +#include <stdlib.h> +#include <chrono> +#include <condition_variable> +#include <mutex> + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::usb::V1_0::PortDataRole; +using ::android::hardware::usb::V1_0::PortMode; +using ::android::hardware::usb::V1_0::PortPowerRole; +using ::android::hardware::usb::V1_0::PortRole; +using ::android::hardware::usb::V1_0::PortRoleType; +using ::android::hardware::usb::V1_0::Status; +using ::android::hardware::usb::V1_1::PortMode_1_1; +using ::android::hardware::usb::V1_1::PortStatus_1_1; +using ::android::hardware::usb::V1_2::ContaminantDetectionStatus; +using ::android::hardware::usb::V1_2::ContaminantProtectionMode; +using ::android::hardware::usb::V1_2::ContaminantProtectionStatus; +using ::android::hardware::usb::V1_2::IUsb; +using ::android::hardware::usb::V1_2::IUsbCallback; +using ::android::hardware::usb::V1_2::PortStatus; +using ::android::hidl::base::V1_0::IBase; + +constexpr char kCallbackNameNotifyPortStatusChange_1_2[] = "notifyPortStatusChange_1_2"; +const int kCallbackIdentifier = 2; + +// Worst case wait time 20secs +#define WAIT_FOR_TIMEOUT std::chrono::milliseconds(20000) + +class UsbClientCallbackArgs { + public: + // The last conveyed status of the USB ports. + // Stores information of currentt_data_role, power_role for all the USB ports + PortStatus usb_last_port_status; + + // Status of the last role switch operation. + Status usb_last_status; + + // Identifier for the usb callback object. + // Stores the cookie of the last invoked usb callback object. + int last_usb_cookie; +}; + +// Callback class for the USB HIDL hal. +// Usb Hal will call this object upon role switch or port query. +class UsbCallback : public ::testing::VtsHalHidlTargetCallbackBase<UsbClientCallbackArgs>, + public IUsbCallback { + int cookie; + + public: + UsbCallback(int cookie) : cookie(cookie){}; + + virtual ~UsbCallback() = default; + + // V1_0 Callback method for the port status. + // This should not be called so not signalling the Test here assuming that + // the test thread will timeout + Return<void> notifyPortStatusChange(const hidl_vec<android::hardware::usb::V1_0::PortStatus>& + /* currentPortStatus */, + Status /* retval */) override { + return Void(); + }; + + // V1_1 Callback method for the port status. + // This should not be called so not signalling the Test here assuming that + // the test thread will timeout + Return<void> notifyPortStatusChange_1_1(const hidl_vec<PortStatus_1_1>& /* currentPortStatus */, + Status /* retval */) override { + return Void(); + } + + // This callback method should be used. + Return<void> notifyPortStatusChange_1_2(const hidl_vec<PortStatus>& currentPortStatus, + Status retval) override { + UsbClientCallbackArgs arg; + if (retval == Status::SUCCESS) { + arg.usb_last_port_status.status_1_1.status.supportedModes = + currentPortStatus[0].status_1_1.status.supportedModes; + arg.usb_last_port_status.status_1_1.status.currentMode = + currentPortStatus[0].status_1_1.status.currentMode; + arg.usb_last_port_status.status_1_1.status.portName = + currentPortStatus[0].status_1_1.status.portName; + arg.usb_last_port_status.contaminantDetectionStatus = + currentPortStatus[0].contaminantDetectionStatus; + arg.usb_last_port_status.contaminantProtectionStatus = + currentPortStatus[0].contaminantProtectionStatus; + arg.usb_last_port_status.supportsEnableContaminantPresenceProtection = + currentPortStatus[0].supportsEnableContaminantPresenceProtection; + arg.usb_last_port_status.supportsEnableContaminantPresenceDetection = + currentPortStatus[0].supportsEnableContaminantPresenceDetection; + arg.usb_last_port_status.supportedContaminantProtectionModes = + currentPortStatus[0].supportedContaminantProtectionModes; + } + arg.usb_last_status = retval; + arg.last_usb_cookie = cookie; + + NotifyFromCallback(kCallbackNameNotifyPortStatusChange_1_2, arg); + return Void(); + } + + // Callback method for the status of role switch operation. + // RoleSwitch operation has not changed since V1_0 so leaving + // the callback blank here. + Return<void> notifyRoleSwitchStatus(const hidl_string& /*portName*/, + const PortRole& /*newRole*/, Status /*retval*/) override { + return Void(); + }; +}; + +// Test environment for Usb HIDL HAL. +class UsbHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static UsbHidlEnvironment* Instance() { + static UsbHidlEnvironment* instance = new UsbHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<IUsb>(); } +}; + +// The main test class for the USB hidl HAL +class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + ALOGI(__FUNCTION__); + usb = ::testing::VtsHalHidlTargetTestBase::getService<IUsb>(); + ASSERT_NE(usb, nullptr); + + usb_cb_2 = new UsbCallback(kCallbackIdentifier); + ASSERT_NE(usb_cb_2, nullptr); + usb_cb_2->SetWaitTimeout(kCallbackNameNotifyPortStatusChange_1_2, WAIT_FOR_TIMEOUT); + Return<void> ret = usb->setCallback(usb_cb_2); + ASSERT_TRUE(ret.isOk()); + } + + virtual void TearDown() override { ALOGI("Teardown"); } + + // USB hidl hal Proxy + sp<IUsb> usb; + + // Callback objects for usb hidl + // Methods of these objects are called to notify port status updates. + sp<UsbCallback> usb_cb_1; + sp<UsbCallback> usb_cb_2; +}; + +/* + * Test to see if setCallback on V1_1 callback object succeeds. + * Callback oject is created and registered. + * Check to see if the hidl transaction succeeded. + */ +TEST_F(UsbHidlTest, setCallback) { + usb_cb_1 = new UsbCallback(1); + ASSERT_NE(usb_cb_1, nullptr); + Return<void> ret = usb->setCallback(usb_cb_1); + ASSERT_TRUE(ret.isOk()); +} + +/* + * Check to see if querying type-c + * port status succeeds. + * HAL service should call notifyPortStatusChange_1_2 + * instead of notifyPortStatusChange of V1_0/V1_1 interface + */ +TEST_F(UsbHidlTest, queryPortStatus) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); +} + +/* + * supportedContaminantProtectionModes is immutable. + * Check if supportedContaminantProtectionModes changes across queryPortStatus + * call. + */ +TEST_F(UsbHidlTest, checkSupportedContaminantProtectionModes) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + uint32_t supportedContaminantProtectionModes = static_cast<uint32_t>( + res.args->usb_last_port_status.supportedContaminantProtectionModes); + for (int runs = 1; runs <= 10; runs++) { + ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); + EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + EXPECT_EQ(supportedContaminantProtectionModes, + static_cast<uint32_t>( + res.args->usb_last_port_status.supportedContaminantProtectionModes)); + } +} + +/* + * When supportsEnableContaminantPresenceDetection is set false, + * enableContaminantPresenceDetection should not enable/disable + * contaminantPresenceProtection. + */ +TEST_F(UsbHidlTest, presenceDetectionSupportedCheck) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceDetection) { + for (int runs = 1; runs <= 10; runs++) { + bool currentStatus = !(res.args->usb_last_port_status.contaminantDetectionStatus == + ContaminantDetectionStatus::DISABLED); + + ret = usb->enableContaminantPresenceDetection( + res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); + ASSERT_TRUE(ret.isOk()); + + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(currentStatus, !(res.args->usb_last_port_status.contaminantDetectionStatus == + ContaminantDetectionStatus::DISABLED)); + } + } +} + +/* + * enableContaminantPresenceDetection should succeed atleast 90% when supported. + */ +TEST_F(UsbHidlTest, contaminantPresenceDetectionStability) { + int successCount = 0; + bool currentStatus; + bool supported = true; + + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceDetection) return; + + for (int count = 1; count <= 10; count++) { + currentStatus = !(res.args->usb_last_port_status.contaminantDetectionStatus == + ContaminantDetectionStatus::DISABLED); + + ret = usb->enableContaminantPresenceDetection( + res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); + ASSERT_TRUE(ret.isOk()); + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + if (!currentStatus == !(res.args->usb_last_port_status.contaminantDetectionStatus == + ContaminantDetectionStatus::DISABLED)) + successCount++; + } + + if (!supported) EXPECT_GE(successCount, 9); +} + +/* + * When supportsEnableContaminantPresenceProtection is set false, + * enableContaminantPresenceProtection should not enable/disable + * contaminantPresenceProtection. + */ +TEST_F(UsbHidlTest, presenceProtectionSupportedCheck) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceProtection) { + for (int runs = 1; runs <= 10; runs++) { + bool currentStatus = !(res.args->usb_last_port_status.contaminantProtectionStatus == + ContaminantProtectionStatus::DISABLED); + + ret = usb->enableContaminantPresenceProtection( + res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); + ASSERT_TRUE(ret.isOk()); + + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(currentStatus, !(res.args->usb_last_port_status.contaminantProtectionStatus == + ContaminantProtectionStatus::DISABLED)); + } + } +} + +/* + * enableContaminantPresenceProtection should succeed atleast 90% when supported. + */ +TEST_F(UsbHidlTest, contaminantPresenceProtectionStability) { + int successCount = 0; + bool currentStatus; + bool supported = true; + + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); + + if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceProtection) return; + + for (int count = 1; count <= 10; count++) { + currentStatus = !(res.args->usb_last_port_status.contaminantProtectionStatus == + ContaminantProtectionStatus::DISABLED); + + ret = usb->enableContaminantPresenceProtection( + res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); + ASSERT_TRUE(ret.isOk()); + res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); + if (!currentStatus == !(res.args->usb_last_port_status.contaminantProtectionStatus == + ContaminantProtectionStatus::DISABLED)) + successCount++; + } + + if (!supported) EXPECT_GE(successCount, 9); +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(UsbHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + UsbHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} diff --git a/vibrator/1.3/Android.bp b/vibrator/1.3/Android.bp new file mode 100644 index 0000000000..28370d6e4d --- /dev/null +++ b/vibrator/1.3/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.vibrator@1.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IVibrator.hal", + ], + interfaces: [ + "android.hardware.vibrator@1.0", + "android.hardware.vibrator@1.1", + "android.hardware.vibrator@1.2", + "android.hidl.base@1.0", + ], + gen_java: true, +} + diff --git a/vibrator/1.3/IVibrator.hal b/vibrator/1.3/IVibrator.hal new file mode 100644 index 0000000000..01c2801720 --- /dev/null +++ b/vibrator/1.3/IVibrator.hal @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package android.hardware.vibrator@1.3; + +import @1.0::Status; +import @1.2::IVibrator; + +interface IVibrator extends @1.2::IVibrator { + /** + * Returns whether the vibrator supports control through an alternate interface. + */ + supportsExternalControl() generates (bool supports); + + /** + * Enables/disables control override of vibrator to audio. + * + * When this API is set, the vibrator control should be ceded to audio system + * for haptic audio. While this is enabled, issuing of other commands to control + * the vibrator is unsupported and the resulting behavior is undefined. Amplitude + * control may or may not be supported and is reflected in the return value of + * supportsAmplitudeControl() while this is enabled. When this is disabled, the + * vibrator should resume to an off state. + * + * @param enabled Whether external control should be enabled or disabled. + * @return status Whether the command was successful or not. Must return + * Status::UNSUPPORTED_OPERATION if external control is + * not supported by the device. + */ + setExternalControl(bool enabled) generates (Status status); +}; diff --git a/vibrator/1.3/vts/functional/Android.bp b/vibrator/1.3/vts/functional/Android.bp new file mode 100644 index 0000000000..5b4c8933d2 --- /dev/null +++ b/vibrator/1.3/vts/functional/Android.bp @@ -0,0 +1,29 @@ +// +// 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. +// + +cc_test { + name: "VtsHalVibratorV1_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalVibratorV1_3TargetTest.cpp"], + static_libs: [ + "android.hardware.vibrator@1.0", + "android.hardware.vibrator@1.1", + "android.hardware.vibrator@1.2", + "android.hardware.vibrator@1.3", + ], + test_suites: ["general-tests"], +} + diff --git a/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp b/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp new file mode 100644 index 0000000000..a67d1dc8c7 --- /dev/null +++ b/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#define LOG_TAG "vibrator_hidl_hal_test" + +#include <VtsHalHidlTargetTestBase.h> +#include <VtsHalHidlTargetTestEnvBase.h> +#include <android-base/logging.h> +#include <android/hardware/vibrator/1.0/types.h> +#include <android/hardware/vibrator/1.3/IVibrator.h> +#include <unistd.h> + +using ::android::sp; +using ::android::hardware::vibrator::V1_0::Status; +using ::android::hardware::vibrator::V1_3::IVibrator; + +// Test environment for Vibrator HIDL HAL. +class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static VibratorHidlEnvironment* Instance() { + static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<IVibrator>(); } + + private: + VibratorHidlEnvironment() {} +}; + +// The main test class for VIBRATOR HIDL HAL 1.3. +class VibratorHidlTest_1_3 : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>( + VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>()); + ASSERT_NE(vibrator, nullptr); + } + + virtual void TearDown() override {} + + sp<IVibrator> vibrator; +}; + +TEST_F(VibratorHidlTest_1_3, ChangeVibrationalExternalControl) { + if (vibrator->supportsExternalControl()) { + EXPECT_EQ(Status::OK, vibrator->setExternalControl(true)); + sleep(1); + EXPECT_EQ(Status::OK, vibrator->setExternalControl(false)); + sleep(1); + } +} + +TEST_F(VibratorHidlTest_1_3, SetExternalControlReturnUnsupportedOperationIfNotSupported) { + if (!vibrator->supportsExternalControl()) { + EXPECT_EQ(Status::UNSUPPORTED_OPERATION, vibrator->setExternalControl(true)); + } +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + VibratorHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/wifi/1.2/default/OWNERS b/wifi/1.0/vts/OWNERS index 8bfb14882c..8bfb14882c 100644 --- a/wifi/1.2/default/OWNERS +++ b/wifi/1.0/vts/OWNERS diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp index d7c84cc413..397ad179af 100644 --- a/wifi/1.0/vts/functional/Android.bp +++ b/wifi/1.0/vts/functional/Android.bp @@ -45,6 +45,9 @@ cc_test { static_libs: [ "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "android.hardware.wifi@1.2", + "android.hardware.wifi@1.3", ], test_suites: ["general-tests"], } diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp index c0af30bf5a..e5762f28f0 100644 --- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -29,17 +29,23 @@ using ::android::hardware::wifi::V1_0::WifiBand; using ::android::hardware::wifi::V1_0::WifiStatusCode; using ::android::sp; +extern WifiHidlEnvironment* gEnv; + /** * Fixture to use for all AP Iface HIDL interface tests. */ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { + if (!gEnv->isSoftApOn) return; wifi_ap_iface_ = getWifiApIface(); ASSERT_NE(nullptr, wifi_ap_iface_.get()); } - virtual void TearDown() override { stopWifi(); } + virtual void TearDown() override { + if (!gEnv->isSoftApOn) return; + stopWifi(); + } protected: sp<IWifiApIface> wifi_ap_iface_; @@ -51,6 +57,7 @@ class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { * successfully created. */ TEST(WifiApIfaceHidlTestNoFixture, Create) { + if (!gEnv->isSoftApOn) return; EXPECT_NE(nullptr, getWifiApIface().get()); stopWifi(); } @@ -60,6 +67,7 @@ TEST(WifiApIfaceHidlTestNoFixture, Create) { * Ensures that the correct interface type is returned for AP interface. */ TEST_F(WifiApIfaceHidlTest, GetType) { + if (!gEnv->isSoftApOn) return; const auto& status_and_type = HIDL_INVOKE(wifi_ap_iface_, getType); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code); EXPECT_EQ(IfaceType::AP, status_and_type.second); @@ -71,6 +79,7 @@ TEST_F(WifiApIfaceHidlTest, GetType) { * status code. */ TEST_F(WifiApIfaceHidlTest, SetCountryCode) { + if (!gEnv->isSoftApOn) return; const android::hardware::hidl_array<int8_t, 2> kCountryCode{ std::array<int8_t, 2>{{0x55, 0x53}}}; EXPECT_EQ(WifiStatusCode::SUCCESS, @@ -82,6 +91,7 @@ TEST_F(WifiApIfaceHidlTest, SetCountryCode) { * Ensures that we can retrieve valid frequencies for 2.4 GHz band. */ TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) { + if (!gEnv->isSoftApOn) return; const auto& status_and_freqs = HIDL_INVOKE( wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ); EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code); diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp index d16f1e7777..72cafd1e9f 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp @@ -17,6 +17,7 @@ #include <android-base/logging.h> #include <android/hardware/wifi/1.0/IWifiChip.h> +#include <android/hardware/wifi/1.3/IWifiChip.h> #include <VtsHalHidlTargetTestBase.h> @@ -87,7 +88,19 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { uint32_t configureChipForStaIfaceAndGetCapabilities() { configureChipForIfaceType(IfaceType::STA, true); - const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities); + + sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted = + ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_); + + std::pair<WifiStatus, uint32_t> status_and_caps; + + if (chip_converted != nullptr) { + // Call the newer HAL version + status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3); + } else { + status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities); + } + if (status_and_caps.first.code != WifiStatusCode::SUCCESS) { EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status_and_caps.first.code); return 0; @@ -352,6 +365,7 @@ TEST_F(WifiChipHidlTest, GetDebugHostWakeReasonStats) { * succeeds. The 2nd iface creation should be rejected. */ TEST_F(WifiChipHidlTest, CreateApIface) { + if (!gEnv->isSoftApOn) return; configureChipForIfaceType(IfaceType::AP, true); sp<IWifiApIface> iface; @@ -368,6 +382,7 @@ TEST_F(WifiChipHidlTest, CreateApIface) { * iface name is returned via the list. */ TEST_F(WifiChipHidlTest, GetApIfaceNames) { + if (!gEnv->isSoftApOn) return; configureChipForIfaceType(IfaceType::AP, true); const auto& status_and_iface_names1 = @@ -400,6 +415,7 @@ TEST_F(WifiChipHidlTest, GetApIfaceNames) { * doesn't retrieve an iface object. */ TEST_F(WifiChipHidlTest, GetApIface) { + if (!gEnv->isSoftApOn) return; configureChipForIfaceType(IfaceType::AP, true); sp<IWifiApIface> ap_iface; @@ -426,6 +442,7 @@ TEST_F(WifiChipHidlTest, GetApIface) { * doesn't remove the iface. */ TEST_F(WifiChipHidlTest, RemoveApIface) { + if (!gEnv->isSoftApOn) return; configureChipForIfaceType(IfaceType::AP, true); sp<IWifiApIface> ap_iface; @@ -735,10 +752,10 @@ TEST_F(WifiChipHidlTest, RemoveStaIface) { * CreateRttController */ TEST_F(WifiChipHidlTest, CreateRttController) { - configureChipForIfaceType(IfaceType::AP, true); + configureChipForIfaceType(IfaceType::STA, true); - sp<IWifiApIface> iface; - EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface)); + sp<IWifiStaIface> iface; + EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface)); EXPECT_NE(nullptr, iface.get()); const auto& status_and_rtt_controller = diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h index 2b1c8ec82e..d430ce0bea 100644 --- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h +++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h @@ -58,26 +58,33 @@ class WifiHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: // Whether NaN feature is supported on the device. bool isNanOn = false; + // Whether SoftAp feature is supported on the device. + bool isSoftApOn = false; void usage(char* me, char* arg) { fprintf(stderr, "unrecognized option: %s\n\n" "usage: %s <gtest options> <test options>\n\n" "test options are:\n\n" - "-N, --nan_on: Whether NAN feature is supported\n", + "-N, --nan_on: Whether NAN feature is supported\n" + "-S, --softap_on: Whether SOFTAP feature is supported\n", arg, me); } int initFromOptions(int argc, char** argv) { static struct option options[] = {{"nan_on", no_argument, 0, 'N'}, + {"softap_on", no_argument, 0, 'S'}, {0, 0, 0, 0}}; int c; - while ((c = getopt_long(argc, argv, "N", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "NS", options, NULL)) >= 0) { switch (c) { case 'N': isNanOn = true; break; + case 'S': + isSoftApOn = true; + break; default: usage(argv[0], argv[optind]); return 2; diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp index a3410287eb..a22cd72682 100644 --- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -17,6 +17,7 @@ #include <android-base/logging.h> #include <android/hardware/wifi/1.0/IWifiStaIface.h> +#include <android/hardware/wifi/1.3/IWifiStaIface.h> #include <VtsHalHidlTargetTestBase.h> @@ -143,6 +144,14 @@ TEST_F(WifiStaIfaceHidlTest, LinkLayerStatsCollection) { return; } + sp<::android::hardware::wifi::V1_3::IWifiStaIface> iface_converted = + ::android::hardware::wifi::V1_3::IWifiStaIface::castFrom( + wifi_sta_iface_); + if (iface_converted != nullptr) { + // Skip this test since this API is deprecated in this newer HAL version + return; + } + // Enable link layer stats collection. EXPECT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true) diff --git a/wifi/1.1/vts/OWNERS b/wifi/1.1/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/1.1/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp index 78d7a854b3..6662314aa5 100644 --- a/wifi/1.1/vts/functional/Android.bp +++ b/wifi/1.1/vts/functional/Android.bp @@ -24,6 +24,8 @@ cc_test { "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi@1.0", "android.hardware.wifi@1.1", + "android.hardware.wifi@1.2", + "android.hardware.wifi@1.3", ], test_suites: ["general-tests"], } diff --git a/wifi/1.1/vts/functional/OWNERS b/wifi/1.1/vts/functional/OWNERS deleted file mode 100644 index 2878acc7fd..0000000000 --- a/wifi/1.1/vts/functional/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -rpius@google.com -quiche@google.com diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp index d3a983cc8c..63235472af 100644 --- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp @@ -18,6 +18,7 @@ #include <android/hardware/wifi/1.1/IWifi.h> #include <android/hardware/wifi/1.1/IWifiChip.h> +#include <android/hardware/wifi/1.3/IWifiChip.h> #include <VtsHalHidlTargetTestBase.h> @@ -58,7 +59,19 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { ChipModeId mode_id; EXPECT_TRUE(configureChipToSupportIfaceType( wifi_chip_, IfaceType::STA, &mode_id)); - const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities); + + sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted = + ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_); + + std::pair<WifiStatus, uint32_t> status_and_caps; + + if (chip_converted != nullptr) { + // Call the newer HAL version + status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3); + } else { + status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities); + } + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code); return status_and_caps.second; } diff --git a/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp deleted file mode 100644 index 1d6e9e4a14..0000000000 --- a/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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_2 { -namespace implementation { -using namespace android::hardware::wifi::V1_0; - -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<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(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<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 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(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 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(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); -} -} // namespace implementation -} // namespace V1_2 -} // namespace wifi -} // namespace hardware -} // namespace android diff --git a/wifi/1.2/default/tests/runtests.sh b/wifi/1.2/default/tests/runtests.sh deleted file mode 100755 index 966a6a751c..0000000000 --- a/wifi/1.2/default/tests/runtests.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/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 - -echo "Running tests" -set -e # fail early - -#NOTE We can't actually run these commands, since they rely on functions added by -#build / envsetup.sh to the bash shell environment. -echo "+ mmma -j32 $ANDROID_BUILD_TOP/" -make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk \ - MODULES-IN-hardware-interfaces-wifi-1.2-default - -set -x # print commands - -adb wait-for-device -adb root -adb wait-for-device - -#'disable-verity' will appear in 'adb remount' output if -#dm - verity is enabled and needs to be disabled. -if adb remount | grep 'disable-verity'; then - adb disable-verity - adb reboot - adb wait-for-device - adb root - adb wait-for-device - adb remount -fi - -adb sync - -adb shell /data/nativetest/vendor/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests diff --git a/wifi/1.2/default/wifi_feature_flags.cpp b/wifi/1.2/default/wifi_feature_flags.cpp deleted file mode 100644 index 778944dd92..0000000000 --- a/wifi/1.2/default/wifi_feature_flags.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wifi_feature_flags.h" - -namespace { -#ifdef WIFI_HIDL_FEATURE_AWARE -static const bool wifiHidlFeatureAware = true; -#else -static const bool wifiHidlFeatureAware = false; -#endif // WIFI_HIDL_FEATURE_AWARE -#ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE -static const bool wifiHidlFeatureDualInterface = true; -#else -static const bool wifiHidlFeatureDualInterface = false; -#endif // WIFI_HIDL_FEATURE_DUAL_INTERFACE -#ifdef WIFI_HIDL_FEATURE_DISABLE_AP -static const bool wifiHidlFeatureDisableAp = true; -#else -static const bool wifiHidlFeatureDisableAp = false; -#endif // WIFI_HIDL_FEATURE_DISABLE_AP - -} // namespace - -namespace android { -namespace hardware { -namespace wifi { -namespace V1_2 { -namespace implementation { -namespace feature_flags { - -WifiFeatureFlags::WifiFeatureFlags() {} -bool WifiFeatureFlags::isAwareSupported() { return wifiHidlFeatureAware; } -bool WifiFeatureFlags::isDualInterfaceSupported() { - return wifiHidlFeatureDualInterface; -} -bool WifiFeatureFlags::isApDisabled() { - return wifiHidlFeatureDisableAp; -} - -} // namespace feature_flags -} // namespace implementation -} // namespace V1_2 -} // namespace wifi -} // namespace hardware -} // namespace android diff --git a/wifi/1.2/vts/OWNERS b/wifi/1.2/vts/OWNERS index 811c857946..8bfb14882c 100644 --- a/wifi/1.2/vts/OWNERS +++ b/wifi/1.2/vts/OWNERS @@ -1,4 +1,2 @@ rpius@google.com -quiche@google.com -arabawy@google.com -yim@google.com
\ No newline at end of file +etancohen@google.com diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp index a969f655ad..b2956ce3c4 100644 --- a/wifi/1.2/vts/functional/Android.bp +++ b/wifi/1.2/vts/functional/Android.bp @@ -27,6 +27,7 @@ cc_test { "android.hardware.wifi@1.0", "android.hardware.wifi@1.1", "android.hardware.wifi@1.2", + "android.hardware.wifi@1.3", ], test_suites: ["general-tests"], } diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp index a5457b761d..9d567feafa 100644 --- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp +++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp @@ -18,6 +18,7 @@ #include <android/hardware/wifi/1.2/IWifiChip.h> #include <android/hardware/wifi/1.2/IWifiChipEventCallback.h> +#include <android/hardware/wifi/1.3/IWifiChip.h> #include <VtsHalHidlTargetCallbackBase.h> #include <VtsHalHidlTargetTestBase.h> @@ -104,7 +105,19 @@ class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { ChipModeId mode_id; EXPECT_TRUE( configureChipToSupportIfaceType(wifi_chip_, IfaceType::STA, &mode_id)); - const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities); + + sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted = + ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_); + + std::pair<WifiStatus, uint32_t> status_and_caps; + + if (chip_converted != nullptr) { + // Call the newer HAL version + status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3); + } else { + status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities); + } + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code); return status_and_caps.second; } diff --git a/wifi/1.3/Android.bp b/wifi/1.3/Android.bp new file mode 100644 index 0000000000..45e2e88c15 --- /dev/null +++ b/wifi/1.3/Android.bp @@ -0,0 +1,28 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.wifi@1.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IWifi.hal", + "IWifiChip.hal", + "IWifiStaIface.hal", + ], + interfaces: [ + "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "android.hardware.wifi@1.2", + "android.hidl.base@1.0", + ], + types: [ + "StaLinkLayerRadioStats", + "StaLinkLayerStats", + "WifiChannelStats", + ], + gen_java: true, +} + diff --git a/audio/core/2.0/default/DevicesFactory.cpp b/wifi/1.3/IWifi.hal index 65a9ccdc4e..298e722a7c 100644 --- a/audio/core/2.0/default/DevicesFactory.cpp +++ b/wifi/1.3/IWifi.hal @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright 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. @@ -14,12 +14,15 @@ * limitations under the License. */ -#define LOG_TAG "DevicesFactoryHAL" +package android.hardware.wifi@1.3; -#include "core/2.0/default/DevicesFactory.h" -#include "core/2.0/default/Device.h" -#include "core/2.0/default/PrimaryDevice.h" +import @1.2::IWifi; -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/DevicesFactory.impl.h> -#undef AUDIO_HAL_VERSION +/** + * This is the root of the HAL module and is the interface returned when + * loading an implementation of the Wi-Fi HAL. There must be at most one + * module loaded in the system. + * IWifi.getChip() must return @1.2::IWifiChip + */ +interface IWifi extends @1.2::IWifi { +}; diff --git a/wifi/1.3/IWifiChip.hal b/wifi/1.3/IWifiChip.hal new file mode 100644 index 0000000000..fc6dbac40e --- /dev/null +++ b/wifi/1.3/IWifiChip.hal @@ -0,0 +1,87 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.3; + +import @1.0::WifiStatus; +import @1.2::IWifiChip; + +/** + * Interface that represents a chip that must be configured as a single unit. + */ +interface IWifiChip extends @1.2::IWifiChip { + + /** + * Capabilities exposed by this chip. + */ + enum ChipCapabilityMask : @1.2::IWifiChip.ChipCapabilityMask { + /** + * Set Latency Mode. + */ + SET_LATENCY_MODE = 1 << 12, + + /** + * Support P2P MAC randomization + */ + P2P_RAND_MAC = 1 << 13 + }; + + /** + * Get the capabilities supported by this chip. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return capabilities Bitset of |ChipCapabilityMask| values. + */ + getCapabilities_1_3() + generates (WifiStatus status, bitfield<ChipCapabilityMask> capabilities); + + /** + * This enum represents the different latency modes that can be set through + * setLatencyMode() + */ + enum LatencyMode : uint32_t { + NORMAL = 0, + LOW = 1 + }; + + /** + * API to set the wifi latency mode + * + * Latency mode determines whether or not to optimize for reducing wifi + * latency as a tradeoff with other wifi functionality such as scanning, + * roaming, etc. This optimization is suitable for some applications such + * as gaming and virtual reality applications. + */ + setLatencyMode(LatencyMode mode) generates (WifiStatus status); + + /** + * API to flush debug ring buffer data to files. + * + * Force flush debug ring buffer using IBase::debug. + * This API help to collect firmware/driver/pkt logs. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.UNKNOWN| + */ + flushRingBufferToFile() generates (WifiStatus status); +}; diff --git a/wifi/1.3/IWifiStaIface.hal b/wifi/1.3/IWifiStaIface.hal new file mode 100644 index 0000000000..81c0c3869b --- /dev/null +++ b/wifi/1.3/IWifiStaIface.hal @@ -0,0 +1,56 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.3; + +import @1.0::WifiStatus; +import @1.0::MacAddress; +import @1.2::IWifiStaIface; + +/** + * Interface used to represent a single STA iface. + * + * IWifiChip.createStaIface() may return a @1.3::IWifiStaIface when supported. + */ +interface IWifiStaIface extends @1.2::IWifiStaIface { + /** + * Retrieve the latest link layer stats. + * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set or if + * link layer stats collection hasn't been explicitly enabled. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_NOT_STARTED|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return stats Instance of |LinkLayerStats|. + */ + getLinkLayerStats_1_3() generates (WifiStatus status, StaLinkLayerStats stats); + + /** + * Gets the factory MAC address of the Sta Interface + * @return status WifiStatus of the operation + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return mac Factory MAC address of the Sta Interface + */ + getFactoryMacAddress() generates (WifiStatus status, MacAddress mac); +}; diff --git a/wifi/1.2/default/Android.mk b/wifi/1.3/default/Android.mk index 391969018c..8312c314ad 100644 --- a/wifi/1.2/default/Android.mk +++ b/wifi/1.3/default/Android.mk @@ -21,6 +21,9 @@ LOCAL_MODULE := android.hardware.wifi@1.0-service-lib LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra +ifdef WIFI_HAL_INTERFACE_COMBINATIONS +LOCAL_CPPFLAGS += -DWIFI_HAL_INTERFACE_COMBINATIONS="$(WIFI_HAL_INTERFACE_COMBINATIONS)" +endif ifdef WIFI_HIDL_FEATURE_AWARE LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE endif @@ -30,6 +33,8 @@ endif ifdef WIFI_HIDL_FEATURE_DISABLE_AP LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP endif +# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed. +LOCAL_CFLAGS += -Wno-error=implicit-fallthrough LOCAL_SRC_FILES := \ hidl_struct_util.cpp \ hidl_sync_util.cpp \ @@ -58,7 +63,8 @@ LOCAL_SHARED_LIBRARIES := \ libwifi-system-iface \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ - android.hardware.wifi@1.2 + android.hardware.wifi@1.2 \ + android.hardware.wifi@1.3 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_STATIC_LIBRARY) @@ -84,7 +90,8 @@ LOCAL_SHARED_LIBRARIES := \ libwifi-system-iface \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ - android.hardware.wifi@1.2 + android.hardware.wifi@1.2 \ + android.hardware.wifi@1.3 LOCAL_STATIC_LIBRARIES := \ android.hardware.wifi@1.0-service-lib LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc @@ -96,6 +103,7 @@ include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-tests LOCAL_PROPRIETARY_MODULE := true +LOCAL_CPPFLAGS := -Wall -Werror -Wextra LOCAL_SRC_FILES := \ tests/hidl_struct_util_unit_tests.cpp \ tests/main.cpp \ @@ -107,11 +115,11 @@ LOCAL_SRC_FILES := \ LOCAL_STATIC_LIBRARIES := \ libgmock \ libgtest \ + libhidlbase \ android.hardware.wifi@1.0-service-lib LOCAL_SHARED_LIBRARIES := \ libbase \ libcutils \ - libhidlbase \ libhidltransport \ liblog \ libnl \ @@ -120,5 +128,6 @@ LOCAL_SHARED_LIBRARIES := \ libwifi-system-iface \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ - android.hardware.wifi@1.2 + android.hardware.wifi@1.2 \ + android.hardware.wifi@1.3 include $(BUILD_NATIVE_TEST) diff --git a/wifi/1.3/default/OWNERS b/wifi/1.3/default/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/1.3/default/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/1.2/default/THREADING.README b/wifi/1.3/default/THREADING.README index 8366ca0201..8366ca0201 100644 --- a/wifi/1.2/default/THREADING.README +++ b/wifi/1.3/default/THREADING.README diff --git a/wifi/1.2/default/android.hardware.wifi@1.0-service.rc b/wifi/1.3/default/android.hardware.wifi@1.0-service.rc index cf849d04ab..cf849d04ab 100644 --- a/wifi/1.2/default/android.hardware.wifi@1.0-service.rc +++ b/wifi/1.3/default/android.hardware.wifi@1.0-service.rc diff --git a/wifi/1.2/default/hidl_callback_util.h b/wifi/1.3/default/hidl_callback_util.h index 97f312a605..a44af79fe3 100644 --- a/wifi/1.2/default/hidl_callback_util.h +++ b/wifi/1.3/default/hidl_callback_util.h @@ -52,7 +52,7 @@ class HidlDeathHandler : public android::hardware::hidl_death_recipient { namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace hidl_callback_util { template <typename CallbackType> @@ -117,7 +117,7 @@ class HidlCallbackHandler { } // namespace hidl_callback_util } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/hidl_return_util.h b/wifi/1.3/default/hidl_return_util.h index 914c1b4ed8..9707444fe6 100644 --- a/wifi/1.2/default/hidl_return_util.h +++ b/wifi/1.3/default/hidl_return_util.h @@ -23,7 +23,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace hidl_return_util { using namespace android::hardware::wifi::V1_0; @@ -113,7 +113,7 @@ Return<void> validateAndCall( } // namespace hidl_return_util } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/hidl_struct_util.cpp b/wifi/1.3/default/hidl_struct_util.cpp index 39ac544e6b..49c14771f9 100644 --- a/wifi/1.2/default/hidl_struct_util.cpp +++ b/wifi/1.3/default/hidl_struct_util.cpp @@ -22,7 +22,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace hidl_struct_util { @@ -69,9 +69,9 @@ convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) { return {}; } -IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability( +V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability( uint32_t feature) { - using HidlChipCaps = IWifiChip::ChipCapabilityMask; + using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask; switch (feature) { case WIFI_FEATURE_SET_TX_POWER_LIMIT: return HidlChipCaps::SET_TX_POWER_LIMIT; @@ -81,6 +81,10 @@ IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability( return HidlChipCaps::D2D_RTT; case WIFI_FEATURE_D2AP_RTT: return HidlChipCaps::D2AP_RTT; + 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 {}; @@ -139,13 +143,18 @@ bool convertLegacyFeaturesToHidlChipCapabilities( convertLegacyLoggerFeatureToHidlChipCapability(feature); } } - for (const auto feature : {WIFI_FEATURE_SET_TX_POWER_LIMIT, - WIFI_FEATURE_USE_BODY_HEAD_SAR, - WIFI_FEATURE_D2D_RTT, WIFI_FEATURE_D2AP_RTT}) { + std::vector<uint32_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT, + WIFI_FEATURE_USE_BODY_HEAD_SAR, + WIFI_FEATURE_D2D_RTT, + WIFI_FEATURE_D2AP_RTT, + 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; @@ -267,34 +276,45 @@ 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: + 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( - IWifiChip::TxPowerScenario hidl_scenario) { + V1_2::IWifiChip::TxPowerScenario hidl_scenario) { switch (hidl_scenario) { // This is the only supported scenario for V1_1 - case IWifiChip::TxPowerScenario::VOICE_CALL: + case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL: return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL; // Those are the supported scenarios for V1_2 - case IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF: + case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF: return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF; - case IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON: + case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON: return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON; - case IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF: + case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF: return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF; - case IWifiChip::TxPowerScenario::ON_BODY_CELL_ON: + 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( + IWifiChip::LatencyMode hidl_latency_mode) { + switch (hidl_latency_mode) { + case IWifiChip::LatencyMode::NORMAL: + return legacy_hal::WIFI_LATENCY_MODE_NORMAL; + case IWifiChip::LatencyMode::LOW: + return legacy_hal::WIFI_LATENCY_MODE_LOW; + } + CHECK(false); +} + bool convertLegacyWifiMacInfoToHidl( const legacy_hal::WifiMacInfo& legacy_mac_info, - IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) { + V1_2::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) { if (!hidl_radio_mode_info) { return false; } @@ -313,9 +333,9 @@ bool convertLegacyWifiMacInfoToHidl( } else { hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED; } - std::vector<IWifiChipEventCallback::IfaceInfo> iface_info_vec; + std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec; for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) { - IWifiChipEventCallback::IfaceInfo iface_info; + 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); @@ -326,14 +346,15 @@ bool convertLegacyWifiMacInfoToHidl( bool convertLegacyWifiMacInfosToHidl( const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos, - std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) { + std::vector<V1_2::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) { - IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info; + V1_2::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info; if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info, &hidl_radio_mode_info)) { return false; @@ -782,9 +803,58 @@ bool convertLegacyVectorOfDebugRxPacketFateToHidl( return true; } +bool convertLegacyLinkLayerRadioStatsToHidl( + const legacy_hal::LinkLayerRadioStats& legacy_radio_stat, + V1_3::StaLinkLayerRadioStats* hidl_radio_stat) { + if (!hidl_radio_stat) { + return false; + } + *hidl_radio_stat = {}; + + 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_3::WifiChannelStats> hidl_channel_stats; + + for (const auto& channel_stat : legacy_radio_stat.channel_stats) { + V1_3::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, - StaLinkLayerStats* hidl_stats) { + V1_3::StaLinkLayerStats* hidl_stats) { if (!hidl_stats) { return false; } @@ -825,16 +895,13 @@ bool convertLegacyLinkLayerStatsToHidl( hidl_stats->iface.wmeVoPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries; // radio legacy_stats conversion. - std::vector<StaLinkLayerRadioStats> hidl_radios_stats; + std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats; for (const auto& legacy_radio_stats : legacy_stats.radios) { - StaLinkLayerRadioStats hidl_radio_stats; - hidl_radio_stats.onTimeInMs = legacy_radio_stats.stats.on_time; - hidl_radio_stats.txTimeInMs = legacy_radio_stats.stats.tx_time; - hidl_radio_stats.rxTimeInMs = legacy_radio_stats.stats.rx_time; - hidl_radio_stats.onTimeInMsForScan = - legacy_radio_stats.stats.on_time_scan; - hidl_radio_stats.txTimeInMsPerLevel = - legacy_radio_stats.tx_time_per_levels; + V1_3::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; @@ -1192,12 +1259,16 @@ bool convertHidlNanEnableRequestToLegacy( hidl_request.debugConfigs .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ]; + // disable NANv3 NDPe + legacy_request->config_ndpe_attr = 1; + legacy_request->use_ndpe_attr = 0; + return true; } bool convertHidlNanEnableRequest_1_2ToLegacy( const NanEnableRequest& hidl_request1, - const NanConfigRequestSupplemental& hidl_request2, + const V1_2::NanConfigRequestSupplemental& hidl_request2, legacy_hal::NanEnableRequest* legacy_request) { if (!legacy_request) { LOG(ERROR) @@ -1703,12 +1774,16 @@ bool convertHidlNanConfigRequestToLegacy( hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] .discoveryWindowIntervalVal; + // disable NANv3 NDPe + legacy_request->config_ndpe_attr = 1; + legacy_request->use_ndpe_attr = 0; + return true; } bool convertHidlNanConfigRequest_1_2ToLegacy( const NanConfigRequest& hidl_request1, - const NanConfigRequestSupplemental& hidl_request2, + const V1_2::NanConfigRequestSupplemental& hidl_request2, legacy_hal::NanConfigRequest* legacy_request) { if (!legacy_request) { LOG(ERROR) << "convertHidlNanConfigRequest_1_2ToLegacy: legacy_request " @@ -2039,7 +2114,7 @@ bool convertLegacyNanDataPathRequestIndToHidl( bool convertLegacyNdpChannelInfoToHidl( const legacy_hal::NanChannelInfo& legacy_struct, - NanDataPathChannelInfo* hidl_struct) { + V1_2::NanDataPathChannelInfo* hidl_struct) { if (!hidl_struct) { LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null"; return false; @@ -2056,7 +2131,7 @@ bool convertLegacyNdpChannelInfoToHidl( bool convertLegacyNanDataPathConfirmIndToHidl( const legacy_hal::NanDataPathConfirmInd& legacy_ind, - NanDataPathConfirmInd* hidl_ind) { + V1_2::NanDataPathConfirmInd* hidl_ind) { if (!hidl_ind) { LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null"; @@ -2077,9 +2152,9 @@ bool convertLegacyNanDataPathConfirmIndToHidl( convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code); hidl_ind->V1_0.status.description = ""; // TODO: b/34059183 - std::vector<NanDataPathChannelInfo> channelInfo; + std::vector<V1_2::NanDataPathChannelInfo> channelInfo; for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) { - NanDataPathChannelInfo hidl_struct; + V1_2::NanDataPathChannelInfo hidl_struct; if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) { return false; @@ -2093,7 +2168,7 @@ bool convertLegacyNanDataPathConfirmIndToHidl( bool convertLegacyNanDataPathScheduleUpdateIndToHidl( const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind, - NanDataPathScheduleUpdateInd* hidl_ind) { + V1_2::NanDataPathScheduleUpdateInd* hidl_ind) { if (!hidl_ind) { LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: " "hidl_ind is null"; @@ -2103,9 +2178,9 @@ bool convertLegacyNanDataPathScheduleUpdateIndToHidl( hidl_ind->peerDiscoveryAddress = hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr); - std::vector<NanDataPathChannelInfo> channelInfo; + std::vector<V1_2::NanDataPathChannelInfo> channelInfo; for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) { - NanDataPathChannelInfo hidl_struct; + V1_2::NanDataPathChannelInfo hidl_struct; if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) { return false; @@ -2616,7 +2691,7 @@ bool convertLegacyVectorOfRttResultToHidl( } } // namespace hidl_struct_util } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/hidl_struct_util.h b/wifi/1.3/default/hidl_struct_util.h index 3c789c046f..3eefd9592b 100644 --- a/wifi/1.2/default/hidl_struct_util.h +++ b/wifi/1.3/default/hidl_struct_util.h @@ -21,9 +21,10 @@ #include <android/hardware/wifi/1.0/IWifiChip.h> #include <android/hardware/wifi/1.0/types.h> -#include <android/hardware/wifi/1.2/IWifiChip.h> #include <android/hardware/wifi/1.2/IWifiChipEventCallback.h> #include <android/hardware/wifi/1.2/types.h> +#include <android/hardware/wifi/1.3/IWifiChip.h> +#include <android/hardware/wifi/1.3/types.h> #include "wifi_legacy_hal.h" @@ -36,7 +37,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace hidl_struct_util { using namespace android::hardware::wifi::V1_0; @@ -56,11 +57,14 @@ bool convertLegacyWakeReasonStatsToHidl( 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( - IWifiChip::TxPowerScenario hidl_scenario); + V1_2::IWifiChip::TxPowerScenario hidl_scenario); bool convertLegacyWifiMacInfosToHidl( const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos, - std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos); + std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>* + hidl_radio_mode_infos); // STA iface conversion methods. bool convertLegacyFeaturesToHidlStaCapabilities( @@ -88,7 +92,7 @@ bool convertLegacyVectorOfCachedGscanResultsToHidl( std::vector<StaScanData>* hidl_scan_datas); bool convertLegacyLinkLayerStatsToHidl( const legacy_hal::LinkLayerStats& legacy_stats, - StaLinkLayerStats* hidl_stats); + V1_3::StaLinkLayerStats* hidl_stats); bool convertLegacyRoamingCapabilitiesToHidl( const legacy_hal::wifi_roaming_capabilities& legacy_caps, StaRoamingCapabilities* hidl_caps); @@ -115,11 +119,11 @@ bool convertHidlNanConfigRequestToLegacy( legacy_hal::NanConfigRequest* legacy_request); bool convertHidlNanEnableRequest_1_2ToLegacy( const NanEnableRequest& hidl_request1, - const NanConfigRequestSupplemental& hidl_request2, + const V1_2::NanConfigRequestSupplemental& hidl_request2, legacy_hal::NanEnableRequest* legacy_request); bool convertHidlNanConfigRequest_1_2ToLegacy( const NanConfigRequest& hidl_request1, - const NanConfigRequestSupplemental& hidl_request2, + const V1_2::NanConfigRequestSupplemental& hidl_request2, legacy_hal::NanConfigRequest* legacy_request); bool convertHidlNanPublishRequestToLegacy( const NanPublishRequest& hidl_request, @@ -152,10 +156,10 @@ bool convertLegacyNanDataPathRequestIndToHidl( NanDataPathRequestInd* hidl_ind); bool convertLegacyNanDataPathConfirmIndToHidl( const legacy_hal::NanDataPathConfirmInd& legacy_ind, - NanDataPathConfirmInd* hidl_ind); + V1_2::NanDataPathConfirmInd* hidl_ind); bool convertLegacyNanDataPathScheduleUpdateIndToHidl( const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind, - NanDataPathScheduleUpdateInd* hidl_ind); + V1_2::NanDataPathScheduleUpdateInd* hidl_ind); // RTT controller conversion methods. bool convertHidlVectorOfRttConfigToLegacy( @@ -184,7 +188,7 @@ bool convertLegacyVectorOfRttResultToHidl( std::vector<RttResult>* hidl_results); } // namespace hidl_struct_util } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/hidl_sync_util.cpp b/wifi/1.3/default/hidl_sync_util.cpp index ad8448a17a..160727f609 100644 --- a/wifi/1.2/default/hidl_sync_util.cpp +++ b/wifi/1.3/default/hidl_sync_util.cpp @@ -23,7 +23,7 @@ std::recursive_mutex g_mutex; namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace hidl_sync_util { @@ -33,7 +33,7 @@ std::unique_lock<std::recursive_mutex> acquireGlobalLock() { } // namespace hidl_sync_util } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/hidl_sync_util.h b/wifi/1.3/default/hidl_sync_util.h index 8381862785..ebfb05144b 100644 --- a/wifi/1.2/default/hidl_sync_util.h +++ b/wifi/1.3/default/hidl_sync_util.h @@ -24,13 +24,13 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace hidl_sync_util { std::unique_lock<std::recursive_mutex> acquireGlobalLock(); } // namespace hidl_sync_util } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/ringbuffer.cpp b/wifi/1.3/default/ringbuffer.cpp index c126b36912..1294c52982 100644 --- a/wifi/1.2/default/ringbuffer.cpp +++ b/wifi/1.3/default/ringbuffer.cpp @@ -21,7 +21,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {} @@ -48,7 +48,7 @@ const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const { } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/ringbuffer.h b/wifi/1.3/default/ringbuffer.h index 4808e40b78..d9f8df685d 100644 --- a/wifi/1.2/default/ringbuffer.h +++ b/wifi/1.3/default/ringbuffer.h @@ -23,7 +23,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { /** @@ -45,7 +45,7 @@ class Ringbuffer { }; } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/service.cpp b/wifi/1.3/default/service.cpp index 01d22bd881..5fd83c1aa8 100644 --- a/wifi/1.2/default/service.cpp +++ b/wifi/1.3/default/service.cpp @@ -26,10 +26,10 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; -using android::hardware::wifi::V1_2::implementation::feature_flags:: +using android::hardware::wifi::V1_3::implementation::feature_flags:: WifiFeatureFlags; -using android::hardware::wifi::V1_2::implementation::legacy_hal::WifiLegacyHal; -using android::hardware::wifi::V1_2::implementation::mode_controller:: +using android::hardware::wifi::V1_3::implementation::legacy_hal::WifiLegacyHal; +using android::hardware::wifi::V1_3::implementation::mode_controller:: WifiModeController; int main(int /*argc*/, char** argv) { @@ -40,8 +40,8 @@ int main(int /*argc*/, char** argv) { configureRpcThreadpool(1, true /* callerWillJoin */); // Setup hwbinder service - android::sp<android::hardware::wifi::V1_2::IWifi> service = - new android::hardware::wifi::V1_2::implementation::Wifi( + android::sp<android::hardware::wifi::V1_3::IWifi> service = + new android::hardware::wifi::V1_3::implementation::Wifi( std::make_shared<WifiLegacyHal>(), std::make_shared<WifiModeController>(), std::make_shared<WifiFeatureFlags>()); diff --git a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp new file mode 100644 index 0000000000..dbf7bd6113 --- /dev/null +++ b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp @@ -0,0 +1,296 @@ +/* + * 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_3 { +namespace implementation { +using namespace android::hardware::wifi::V1_0; +using ::android::hardware::wifi::V1_0::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_2::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(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_2::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_2::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(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_2::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(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.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_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_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_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(); + + for (auto& radio : legacy_stats.radios) { + 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}, + .cca_busy_time = 0x55, + .on_time = 0x1111}; + legacy_hal::wifi_channel_stat channel_stat2 = { + .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0}, + .cca_busy_time = 0x66, + .on_time = 0x2222}; + radio.channel_stats.push_back(channel_stat1); + radio.channel_stats.push_back(channel_stat2); + } + + V1_3::StaLinkLayerStats converted{}; + hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, + &converted); + EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.beaconRx); + EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu, + converted.iface.wmeBePktStats.rxMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu, + converted.iface.wmeBePktStats.txMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost, + converted.iface.wmeBePktStats.lostMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries, + converted.iface.wmeBePktStats.retries); + + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu, + converted.iface.wmeBkPktStats.rxMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu, + converted.iface.wmeBkPktStats.txMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost, + converted.iface.wmeBkPktStats.lostMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries, + converted.iface.wmeBkPktStats.retries); + + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu, + converted.iface.wmeViPktStats.rxMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu, + converted.iface.wmeViPktStats.txMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost, + converted.iface.wmeViPktStats.lostMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries, + converted.iface.wmeViPktStats.retries); + + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu, + converted.iface.wmeVoPktStats.rxMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu, + converted.iface.wmeVoPktStats.txMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost, + converted.iface.wmeVoPktStats.lostMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries, + converted.iface.wmeVoPktStats.retries); + + 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.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); + } + } +} + +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); +} +} // namespace implementation +} // namespace V1_3 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/tests/main.cpp b/wifi/1.3/default/tests/main.cpp index 9aac837242..9aac837242 100644 --- a/wifi/1.2/default/tests/main.cpp +++ b/wifi/1.3/default/tests/main.cpp diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp index 8d0b1921c2..a393fdc539 100644 --- a/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp +++ b/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp @@ -21,7 +21,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace feature_flags { @@ -29,7 +29,7 @@ MockWifiFeatureFlags::MockWifiFeatureFlags() {} } // namespace feature_flags } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.h b/wifi/1.3/default/tests/mock_wifi_feature_flags.h index 2a36dd50f4..8b0baa41a6 100644 --- a/wifi/1.2/default/tests/mock_wifi_feature_flags.h +++ b/wifi/1.3/default/tests/mock_wifi_feature_flags.h @@ -18,13 +18,14 @@ #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_2 { +namespace V1_3 { namespace implementation { namespace feature_flags { @@ -32,14 +33,12 @@ class MockWifiFeatureFlags : public WifiFeatureFlags { public: MockWifiFeatureFlags(); - MOCK_METHOD0(isAwareSupported, bool()); - MOCK_METHOD0(isDualInterfaceSupported, bool()); - MOCK_METHOD0(isApDisabled, bool()); + MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>()); }; } // namespace feature_flags } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp index 8381ddef4e..4cd279d543 100644 --- a/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp +++ b/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp @@ -24,14 +24,14 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace legacy_hal { MockWifiLegacyHal::MockWifiLegacyHal() : WifiLegacyHal() {} } // namespace legacy_hal } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.h b/wifi/1.3/default/tests/mock_wifi_legacy_hal.h index 43370b4f5c..deb3a5ae4b 100644 --- a/wifi/1.2/default/tests/mock_wifi_legacy_hal.h +++ b/wifi/1.3/default/tests/mock_wifi_legacy_hal.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace legacy_hal { @@ -49,7 +49,7 @@ class MockWifiLegacyHal : public WifiLegacyHal { }; } // namespace legacy_hal } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp index 461a581a22..2b0ea366f3 100644 --- a/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp +++ b/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp @@ -24,14 +24,14 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace mode_controller { MockWifiModeController::MockWifiModeController() : WifiModeController() {} } // namespace mode_controller } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.h b/wifi/1.3/default/tests/mock_wifi_mode_controller.h index 50c3e35bbc..c204059e67 100644 --- a/wifi/1.2/default/tests/mock_wifi_mode_controller.h +++ b/wifi/1.3/default/tests/mock_wifi_mode_controller.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace mode_controller { @@ -38,7 +38,7 @@ class MockWifiModeController : public WifiModeController { }; } // namespace mode_controller } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp index ad5289b919..0cf1e4f256 100644 --- a/wifi/1.2/default/tests/ringbuffer_unit_tests.cpp +++ b/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp @@ -24,7 +24,7 @@ using testing::Test; namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { class RingbufferTest : public Test { @@ -91,7 +91,7 @@ TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) { EXPECT_EQ(input, buffer_.getData().front()); } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/tests/runtests.sh b/wifi/1.3/default/tests/runtests.sh new file mode 100755 index 0000000000..eefc697b2e --- /dev/null +++ b/wifi/1.3/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/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp index 8722d0ac4c..3fcc39eb8f 100644 --- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp @@ -16,6 +16,7 @@ #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 @@ -38,54 +39,96 @@ constexpr ChipId kFakeChipId = 5; namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { class WifiChipTest : public Test { protected: void setupV1IfaceCombination() { - EXPECT_CALL(*feature_flags_, isAwareSupported()) - .WillRepeatedly(testing::Return(false)); - EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) - .WillRepeatedly(testing::Return(false)); - EXPECT_CALL(*feature_flags_, isApDisabled()) - .WillRepeatedly(testing::Return(false)); + // clang-format off + const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = { + {{{{IfaceType::STA}, 1}, {{IfaceType::P2P}, 1}}} + }; + const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = { + {{{{IfaceType::AP}, 1}}} + }; + const std::vector<V1_0::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()) + .WillRepeatedly(testing::Return(modes)); } void setupV1_AwareIfaceCombination() { - EXPECT_CALL(*feature_flags_, isAwareSupported()) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) - .WillRepeatedly(testing::Return(false)); - EXPECT_CALL(*feature_flags_, isApDisabled()) - .WillRepeatedly(testing::Return(false)); + // clang-format off + const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = { + {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}} + }; + const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = { + {{{{IfaceType::AP}, 1}}} + }; + const std::vector<V1_0::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()) + .WillRepeatedly(testing::Return(modes)); } void setupV1_AwareDisabledApIfaceCombination() { - EXPECT_CALL(*feature_flags_, isAwareSupported()) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) - .WillRepeatedly(testing::Return(false)); - EXPECT_CALL(*feature_flags_, isApDisabled()) - .WillRepeatedly(testing::Return(true)); + // clang-format off + const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = { + {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}} + }; + const std::vector<V1_0::IWifiChip::ChipMode> modes = { + {feature_flags::chip_mode_ids::kV1Sta, combinationsSta} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes()) + .WillRepeatedly(testing::Return(modes)); } void setupV2_AwareIfaceCombination() { - EXPECT_CALL(*feature_flags_, isAwareSupported()) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(*feature_flags_, isApDisabled()) - .WillRepeatedly(testing::Return(false)); + // clang-format off + const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = { + {{{{IfaceType::STA}, 1}, {{IfaceType::AP}, 1}}}, + {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}} + }; + const std::vector<V1_0::IWifiChip::ChipMode> modes = { + {feature_flags::chip_mode_ids::kV3, combinations} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes()) + .WillRepeatedly(testing::Return(modes)); } void setupV2_AwareDisabledApIfaceCombination() { - EXPECT_CALL(*feature_flags_, isAwareSupported()) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(*feature_flags_, isApDisabled()) - .WillRepeatedly(testing::Return(true)); + // clang-format off + const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = { + {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}} + }; + const std::vector<V1_0::IWifiChip::ChipMode> modes = { + {feature_flags::chip_mode_ids::kV3, combinations} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes()) + .WillRepeatedly(testing::Return(modes)); + } + + void setup_MultiIfaceCombination() { + // clang-format off + const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = { + {{{{IfaceType::STA}, 3}}} + }; + const std::vector<V1_0::IWifiChip::ChipMode> modes = { + {feature_flags::chip_mode_ids::kV3, combinations} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes()) + .WillRepeatedly(testing::Return(modes)); } void assertNumberOfModes(uint32_t num_modes) { @@ -204,6 +247,19 @@ class WifiChipTest : public Test { } } + bool createRttController() { + bool success = false; + chip_->createRttController( + NULL, [&success](const WifiStatus& status, + const sp<IWifiRttController>& rtt) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(rtt.get(), nullptr); + success = true; + } + }); + return success; + } + public: void SetUp() override { chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_, @@ -386,6 +442,29 @@ TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) { ASSERT_TRUE(createIface(IfaceType::NAN).empty()); } +TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowStaModeNoSta) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowStaModeWithSta) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowApToSta) { + findModeAndConfigureForIfaceType(IfaceType::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(IfaceType::STA); + ASSERT_TRUE(createRttController()); +} + ////////// V2 + Aware Iface Combinations //////////// // Mode 1 - STA + STA/AP // - STA + P2P/NAN @@ -540,40 +619,110 @@ TEST_F(WifiChipV2_AwareIfaceCombinationTest, ASSERT_NE(sta_iface_name, ap_iface_name); } +TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_TRUE(createRttController()); +} + ////////// V1 Iface Combinations when AP creation is disabled ////////// class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest { - public: - void SetUp() override { - setupV1_AwareDisabledApIfaceCombination(); - WifiChipTest::SetUp(); - } + public: + void SetUp() override { + setupV1_AwareDisabledApIfaceCombination(); + WifiChipTest::SetUp(); + } }; TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { - findModeAndConfigureForIfaceType(IfaceType::STA); - ASSERT_FALSE(createIface(IfaceType::STA).empty()); - ASSERT_TRUE(createIface(IfaceType::AP).empty()); + findModeAndConfigureForIfaceType(IfaceType::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(); - } +class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest { + public: + void SetUp() override { + setupV2_AwareDisabledApIfaceCombination(); + WifiChipTest::SetUp(); + } }; TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest, CreateSta_ShouldSucceed) { - findModeAndConfigureForIfaceType(IfaceType::STA); - ASSERT_FALSE(createIface(IfaceType::STA).empty()); - ASSERT_TRUE(createIface(IfaceType::AP).empty()); + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +class WifiChip_MultiIfaceTest : public WifiChipTest { + public: + void SetUp() override { + setup_MultiIfaceCombination(); + WifiChipTest::SetUp(); + } +}; + +TEST_F(WifiChip_MultiIfaceTest, Create3Sta) { + findModeAndConfigureForIfaceType(IfaceType::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(IfaceType::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(IfaceType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "test0"); + ASSERT_EQ(createIface(IfaceType::STA), "test1"); + 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(IfaceType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "testA0"); + ASSERT_EQ(createIface(IfaceType::STA), "testA1"); + ASSERT_EQ(createIface(IfaceType::STA), "wlan2"); } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi.cpp b/wifi/1.3/default/wifi.cpp index 79f921fa6e..e3af1eab17 100644 --- a/wifi/1.2/default/wifi.cpp +++ b/wifi/1.3/default/wifi.cpp @@ -28,7 +28,7 @@ static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0; namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using hidl_return_util::validateAndCall; using hidl_return_util::validateAndCallWithLock; @@ -206,7 +206,7 @@ WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController( return createWifiStatus(WifiStatusCode::SUCCESS); } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi.h b/wifi/1.3/default/wifi.h index 86919b194e..e92142492a 100644 --- a/wifi/1.2/default/wifi.h +++ b/wifi/1.3/default/wifi.h @@ -20,7 +20,7 @@ #include <functional> #include <android-base/macros.h> -#include <android/hardware/wifi/1.2/IWifi.h> +#include <android/hardware/wifi/1.3/IWifi.h> #include <utils/Looper.h> #include "hidl_callback_util.h" @@ -32,13 +32,13 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { /** * Root HIDL interface object used to control the Wifi HAL. */ -class Wifi : public V1_2::IWifi { +class Wifi : public V1_3::IWifi { public: Wifi(const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal, const std::shared_ptr<mode_controller::WifiModeController> @@ -88,7 +88,7 @@ class Wifi : public V1_2::IWifi { }; } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_ap_iface.cpp b/wifi/1.3/default/wifi_ap_iface.cpp index 92b7b48d98..c203e47b5d 100644 --- a/wifi/1.2/default/wifi_ap_iface.cpp +++ b/wifi/1.3/default/wifi_ap_iface.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using hidl_return_util::validateAndCall; @@ -93,7 +93,7 @@ WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) { return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies}; } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_ap_iface.h b/wifi/1.3/default/wifi_ap_iface.h index 5363ec2586..9f3d870d35 100644 --- a/wifi/1.2/default/wifi_ap_iface.h +++ b/wifi/1.3/default/wifi_ap_iface.h @@ -25,7 +25,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -65,7 +65,7 @@ class WifiApIface : public V1_0::IWifiApIface { }; } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.3/default/wifi_chip.cpp index 3bd05570f6..e7ebc3b1aa 100644 --- a/wifi/1.2/default/wifi_chip.cpp +++ b/wifi/1.3/default/wifi_chip.cpp @@ -28,28 +28,20 @@ #include "wifi_status_util.h" 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; -using android::sp; - -constexpr ChipModeId kInvalidModeId = UINT32_MAX; -// These mode ID's should be unique (even across combo versions). Refer to -// handleChipConfiguration() for it's usage. -// Mode ID's for V1 -constexpr ChipModeId kV1StaChipModeId = 0; -constexpr ChipModeId kV1ApChipModeId = 1; -// Mode ID for V2 -constexpr ChipModeId kV2ChipModeId = 2; constexpr char kCpioMagic[] = "070701"; -constexpr size_t kMaxBufferSizeBytes = 1024 * 1024; -constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60; +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 unsigned kMaxWlanIfaces = 100; template <typename Iface> void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) { @@ -87,16 +79,25 @@ sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces, return nullptr; } -std::string getWlan0IfaceName() { - std::array<char, PROPERTY_VALUE_MAX> buffer; - property_get("wifi.interface", buffer.data(), "wlan0"); - return buffer.data(); -} +std::string getWlanIfaceName(unsigned idx) { + if (idx >= kMaxWlanIfaces) { + CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces; + return {}; + } -std::string getWlan1IfaceName() { std::array<char, PROPERTY_VALUE_MAX> buffer; - property_get("wifi.concurrent.interface", buffer.data(), "wlan1"); - 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(); + + if (idx == 0 || idx == 1) { + const char* altPropName = + (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface"; + res = property_get(altPropName, buffer.data(), nullptr); + if (res > 0) return buffer.data(); + } + + return "wlan" + std::to_string(idx); } std::string getP2pIfaceName() { @@ -111,16 +112,16 @@ std::string getP2pIfaceName() { bool removeOldFilesInternal() { time_t now = time(0); const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds; - DIR* dir_dump = opendir(kTombstoneFolderPath); + std::unique_ptr<DIR, decltype(&closedir)> dir_dump( + opendir(kTombstoneFolderPath), closedir); if (!dir_dump) { LOG(ERROR) << "Failed to open directory: " << strerror(errno); return false; } - unique_fd dir_auto_closer(dirfd(dir_dump)); struct dirent* dp; bool success = true; std::list<std::pair<const time_t, std::string>> valid_files; - while ((dp = readdir(dir_dump))) { + while ((dp = readdir(dir_dump.get()))) { if (dp->d_type != DT_REG) { continue; } @@ -246,13 +247,13 @@ bool cpioWriteFileTrailer(int out_fd) { size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) { struct dirent* dp; size_t n_error = 0; - DIR* dir_dump = opendir(input_dir); + std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir), + closedir); if (!dir_dump) { LOG(ERROR) << "Failed to open directory: " << strerror(errno); return ++n_error; } - unique_fd dir_auto_closer(dirfd(dir_dump)); - while ((dp = readdir(dir_dump))) { + while ((dp = readdir(dir_dump.get()))) { if (dp->d_type != DT_REG) { continue; } @@ -304,7 +305,7 @@ std::vector<char> makeCharVec(const std::string& str) { namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using hidl_return_util::validateAndCall; using hidl_return_util::validateAndCallWithLock; @@ -318,10 +319,9 @@ WifiChip::WifiChip( mode_controller_(mode_controller), feature_flags_(feature_flags), is_valid_(true), - current_mode_id_(kInvalidModeId), - debug_ring_buffer_cb_registered_(false) { - populateModes(); -} + current_mode_id_(feature_flags::chip_mode_ids::kInvalid), + modes_(feature_flags.lock()->getChipModes()), + debug_ring_buffer_cb_registered_(false) {} void WifiChip::invalidate() { if (!writeRingbufferFilesInternal()) { @@ -335,7 +335,7 @@ void WifiChip::invalidate() { bool WifiChip::isValid() { return is_valid_; } -std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() { +std::set<sp<V1_2::IWifiChipEventCallback>> WifiChip::getEventCallbacks() { return event_cb_handler_.getCallbacks(); } @@ -344,6 +344,7 @@ Return<void> WifiChip::getId(getId_cb hidl_status_cb) { &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) { @@ -524,6 +525,13 @@ Return<void> WifiChip::forceDumpToDebugRingBuffer( 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, @@ -546,7 +554,8 @@ Return<void> WifiChip::enableDebugErrorAlerts( } Return<void> WifiChip::selectTxPowerScenario( - V1_1::IWifiChip::TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) { + V1_1::IWifiChip::TxPowerScenario scenario, + selectTxPowerScenario_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::selectTxPowerScenarioInternal, hidl_status_cb, scenario); @@ -559,8 +568,15 @@ Return<void> WifiChip::resetTxPowerScenario( 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<IWifiChipEventCallback>& event_callback, + const sp<V1_2::IWifiChipEventCallback>& event_callback, registerEventCallback_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::registerEventCallbackInternal_1_2, @@ -568,9 +584,16 @@ Return<void> WifiChip::registerEventCallback_1_2( } Return<void> WifiChip::selectTxPowerScenario_1_2( - TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) { + TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, - &WifiChip::selectTxPowerScenarioInternal_1_2, hidl_status_cb, scenario); + &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::debug(const hidl_handle& handle, @@ -615,16 +638,22 @@ WifiStatus WifiChip::registerEventCallbackInternal( } std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() { + // Deprecated support for this callback. + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0}; +} + +std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() { legacy_hal::wifi_error legacy_status; uint32_t legacy_feature_set; uint32_t legacy_logger_feature_set; + const auto ifname = getWlanIfaceName(0); std::tie(legacy_status, legacy_feature_set) = - legacy_hal_.lock()->getSupportedFeatureSet(getWlan0IfaceName()); + 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(getWlan0IfaceName()); + 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; @@ -685,8 +714,9 @@ WifiChip::requestChipDebugInfoInternal() { IWifiChip::ChipDebugInfo result; legacy_hal::wifi_error legacy_status; std::string driver_desc; + const auto ifname = getWlanIfaceName(0); std::tie(legacy_status, driver_desc) = - legacy_hal_.lock()->getDriverVersion(getWlan0IfaceName()); + legacy_hal_.lock()->getDriverVersion(ifname); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to get driver version: " << legacyErrorToString(legacy_status); @@ -698,7 +728,7 @@ WifiChip::requestChipDebugInfoInternal() { std::string firmware_desc; std::tie(legacy_status, firmware_desc) = - legacy_hal_.lock()->getFirmwareVersion(getWlan0IfaceName()); + legacy_hal_.lock()->getFirmwareVersion(ifname); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to get firmware version: " << legacyErrorToString(legacy_status); @@ -716,7 +746,7 @@ WifiChip::requestDriverDebugDumpInternal() { legacy_hal::wifi_error legacy_status; std::vector<uint8_t> driver_dump; std::tie(legacy_status, driver_dump) = - legacy_hal_.lock()->requestDriverMemoryDump(getWlan0IfaceName()); + legacy_hal_.lock()->requestDriverMemoryDump(getWlanIfaceName(0)); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to get driver debug dump: " << legacyErrorToString(legacy_status); @@ -731,7 +761,7 @@ WifiChip::requestFirmwareDebugDumpInternal() { legacy_hal::wifi_error legacy_status; std::vector<uint8_t> firmware_dump; std::tie(legacy_status, firmware_dump) = - legacy_hal_.lock()->requestFirmwareMemoryDump(getWlan0IfaceName()); + legacy_hal_.lock()->requestFirmwareMemoryDump(getWlanIfaceName(0)); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to get firmware debug dump: " << legacyErrorToString(legacy_status); @@ -791,7 +821,7 @@ std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } // These are still assumed to be based on wlan0. - std::string ifname = getWlan0IfaceName(); + std::string ifname = getWlanIfaceName(0); sp<WifiNanIface> iface = new WifiNanIface(ifname, legacy_hal_); nan_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { @@ -927,8 +957,14 @@ WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) { std::pair<WifiStatus, sp<IWifiRttController>> WifiChip::createRttControllerInternal(const sp<IWifiIface>& bound_iface) { + if (sta_ifaces_.size() == 0 && + !canCurrentModeSupportIfaceOfType(IfaceType::STA)) { + LOG(ERROR) << "createRttControllerInternal: Chip cannot support STAs " + "(and RTT by extension)"; + return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; + } sp<WifiRttController> rtt = - new WifiRttController(getWlan0IfaceName(), bound_iface, legacy_hal_); + new WifiRttController(getWlanIfaceName(0), bound_iface, legacy_hal_); rtt_controllers_.emplace_back(rtt); return {createWifiStatus(WifiStatusCode::SUCCESS), rtt}; } @@ -939,7 +975,7 @@ WifiChip::getDebugRingBuffersStatusInternal() { 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(getWlan0IfaceName()); + legacy_hal_.lock()->getRingBuffersStatus(getWlanIfaceName(0)); if (legacy_status != legacy_hal::WIFI_SUCCESS) { return {createWifiStatusFromLegacyError(legacy_status), {}}; } @@ -961,7 +997,7 @@ WifiStatus WifiChip::startLoggingToDebugRingBufferInternal( } legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRingBufferLogging( - getWlan0IfaceName(), ring_name, + getWlanIfaceName(0), ring_name, static_cast< std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>( verbose_level), @@ -978,15 +1014,23 @@ WifiStatus WifiChip::forceDumpToDebugRingBufferInternal( return status; } legacy_hal::wifi_error legacy_status = - legacy_hal_.lock()->getRingBufferData(getWlan0IfaceName(), ring_name); + legacy_hal_.lock()->getRingBufferData(getWlanIfaceName(0), 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( - getWlan0IfaceName()); + getWlanIfaceName(0)); return createWifiStatusFromLegacyError(legacy_status); } @@ -995,7 +1039,7 @@ WifiChip::getDebugHostWakeReasonStatsInternal() { legacy_hal::wifi_error legacy_status; legacy_hal::WakeReasonStats legacy_stats; std::tie(legacy_status, legacy_stats) = - legacy_hal_.lock()->getWakeReasonStats(getWlan0IfaceName()); + legacy_hal_.lock()->getWakeReasonStats(getWlanIfaceName(0)); if (legacy_status != legacy_hal::WIFI_SUCCESS) { return {createWifiStatusFromLegacyError(legacy_status), {}}; } @@ -1027,39 +1071,47 @@ WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) { } }; legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler( - getWlan0IfaceName(), on_alert_callback); + getWlanIfaceName(0), on_alert_callback); } else { legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler( - getWlan0IfaceName()); + getWlanIfaceName(0)); } return createWifiStatusFromLegacyError(legacy_status); } WifiStatus WifiChip::selectTxPowerScenarioInternal( - V1_1::IWifiChip::TxPowerScenario scenario) { + V1_1::IWifiChip::TxPowerScenario scenario) { auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario( - getWlan0IfaceName(), + getWlanIfaceName(0), hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario)); return createWifiStatusFromLegacyError(legacy_status); } WifiStatus WifiChip::resetTxPowerScenarioInternal() { auto legacy_status = - legacy_hal_.lock()->resetTxPowerScenario(getWlan0IfaceName()); + legacy_hal_.lock()->resetTxPowerScenario(getWlanIfaceName(0)); + return createWifiStatusFromLegacyError(legacy_status); +} + +WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) { + auto legacy_status = legacy_hal_.lock()->setLatencyMode( + getWlanIfaceName(0), + hidl_struct_util::convertHidlLatencyModeToLegacy(mode)); return createWifiStatusFromLegacyError(legacy_status); } WifiStatus WifiChip::registerEventCallbackInternal_1_2( - const sp<IWifiChipEventCallback>& event_callback) { + const sp<V1_2::IWifiChipEventCallback>& event_callback) { if (!event_cb_handler_.addCallback(event_callback)) { return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); } return createWifiStatus(WifiStatusCode::SUCCESS); } -WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario) { +WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2( + TxPowerScenario scenario) { auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario( - getWlan0IfaceName(), + getWlanIfaceName(0), hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario)); return createWifiStatusFromLegacyError(legacy_status); } @@ -1083,9 +1135,9 @@ WifiStatus WifiChip::handleChipConfiguration( } // Firmware mode change not needed for V2 devices. bool success = true; - if (mode_id == kV1StaChipModeId) { + if (mode_id == feature_flags::chip_mode_ids::kV1Sta) { success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA); - } else if (mode_id == kV1ApChipModeId) { + } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) { success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP); } if (!success) { @@ -1139,7 +1191,7 @@ WifiStatus WifiChip::registerDebugRingBufferCallback() { }; legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler( - getWlan0IfaceName(), on_ring_buffer_data_callback); + getWlanIfaceName(0), on_ring_buffer_data_callback); if (legacy_status == legacy_hal::WIFI_SUCCESS) { debug_ring_buffer_cb_registered_ = true; @@ -1156,7 +1208,7 @@ WifiStatus WifiChip::registerRadioModeChangeCallback() { LOG(ERROR) << "Callback invoked on an invalid object"; return; } - std::vector<IWifiChipEventCallback::RadioModeInfo> + std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos; if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl( mac_infos, &hidl_radio_mode_infos)) { @@ -1173,86 +1225,10 @@ WifiStatus WifiChip::registerRadioModeChangeCallback() { }; legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRadioModeChangeCallbackHandler( - getWlan0IfaceName(), on_radio_mode_change_callback); + getWlanIfaceName(0), on_radio_mode_change_callback); return createWifiStatusFromLegacyError(legacy_status); } -void WifiChip::populateModes() { - // The chip combination supported for current devices is fixed. - // They can be one of the following based on device features: - // a) 2 separate modes of operation with 1 interface 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. - // - // b) 1 mode of operation with 2 interface combinations - // (conditional on isDualInterfaceSupported()): - // Interface Combination 1: Will support 1 STA and 1 P2P or NAN(optional) - // concurrent iface operations. - // Interface Combination 2: Will support 1 STA and 1 AP concurrent - // iface operations. - // If Aware is enabled (conditional on isAwareSupported()), the iface - // combination will be modified to support either P2P or NAN in place of - // just P2P. - if (feature_flags_.lock()->isDualInterfaceSupported()) { - // V2 Iface combinations for Mode Id = 2. - const IWifiChip::ChipIfaceCombinationLimit - chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; - const IWifiChip::ChipIfaceCombinationLimit - chip_iface_combination_limit_2 = {{IfaceType::AP}, 1}; - IWifiChip::ChipIfaceCombinationLimit chip_iface_combination_limit_3; - if (feature_flags_.lock()->isAwareSupported()) { - chip_iface_combination_limit_3 = {{IfaceType::P2P, IfaceType::NAN}, - 1}; - } else { - chip_iface_combination_limit_3 = {{IfaceType::P2P}, 1}; - } - const IWifiChip::ChipIfaceCombination chip_iface_combination_1 = { - {chip_iface_combination_limit_1, chip_iface_combination_limit_2}}; - const IWifiChip::ChipIfaceCombination chip_iface_combination_2 = { - {chip_iface_combination_limit_1, chip_iface_combination_limit_3}}; - if (feature_flags_.lock()->isApDisabled()) { - const IWifiChip::ChipMode chip_mode = { - kV2ChipModeId, - {chip_iface_combination_2}}; - modes_ = {chip_mode}; - } else { - const IWifiChip::ChipMode chip_mode = { - kV2ChipModeId, - {chip_iface_combination_1, chip_iface_combination_2}}; - modes_ = {chip_mode}; - } - } else { - // V1 Iface combinations for Mode Id = 0. (STA Mode) - const IWifiChip::ChipIfaceCombinationLimit - sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; - IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2; - if (feature_flags_.lock()->isAwareSupported()) { - sta_chip_iface_combination_limit_2 = { - {IfaceType::P2P, IfaceType::NAN}, 1}; - } else { - sta_chip_iface_combination_limit_2 = {{IfaceType::P2P}, 1}; - } - const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = { - {sta_chip_iface_combination_limit_1, - sta_chip_iface_combination_limit_2}}; - const IWifiChip::ChipMode sta_chip_mode = { - kV1StaChipModeId, {sta_chip_iface_combination}}; - // Iface combinations for Mode Id = 1. (AP Mode) - const IWifiChip::ChipIfaceCombinationLimit - ap_chip_iface_combination_limit = {{IfaceType::AP}, 1}; - const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = { - {ap_chip_iface_combination_limit}}; - const IWifiChip::ChipMode ap_chip_mode = {kV1ApChipModeId, - {ap_chip_iface_combination}}; - if (feature_flags_.lock()->isApDisabled()) { - modes_ = {sta_chip_mode}; - } else { - modes_ = {sta_chip_mode, ap_chip_mode}; - } - } -} - std::vector<IWifiChip::ChipIfaceCombination> WifiChip::getCurrentModeIfaceCombinations() { if (!isValidModeId(current_mode_id_)) { @@ -1366,22 +1342,17 @@ bool WifiChip::isValidModeId(ChipModeId mode_id) { return false; } -// Return "wlan0", if "wlan0" is not already in use, else return "wlan1". -// This is based on the assumption that we'll have a max of 2 concurrent -// AP/STA ifaces. +// Return the first wlan (wlan0, wlan1 etc.) not already in use. +// This doesn't check the actual presence of these interfaces. std::string WifiChip::allocateApOrStaIfaceName() { - auto ap_iface = findUsingName(ap_ifaces_, getWlan0IfaceName()); - auto sta_iface = findUsingName(sta_ifaces_, getWlan0IfaceName()); - if (!ap_iface.get() && !sta_iface.get()) { - return getWlan0IfaceName(); - } - ap_iface = findUsingName(ap_ifaces_, getWlan1IfaceName()); - sta_iface = findUsingName(sta_ifaces_, getWlan1IfaceName()); - if (!ap_iface.get() && !sta_iface.get()) { - return getWlan1IfaceName(); + for (unsigned i = 0; i < kMaxWlanIfaces; i++) { + const auto ifname = getWlanIfaceName(i); + 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(0) << "wlan0 and wlan1 in use already!"; + CHECK(false) << "All wlan interfaces in use already!"; return {}; } @@ -1415,7 +1386,7 @@ bool WifiChip::writeRingbufferFilesInternal() { } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.3/default/wifi_chip.h index ada945885e..d14ced62ce 100644 --- a/wifi/1.2/default/wifi_chip.h +++ b/wifi/1.3/default/wifi_chip.h @@ -21,7 +21,7 @@ #include <map> #include <android-base/macros.h> -#include <android/hardware/wifi/1.2/IWifiChip.h> +#include <android/hardware/wifi/1.3/IWifiChip.h> #include "hidl_callback_util.h" #include "ringbuffer.h" @@ -37,7 +37,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -46,7 +46,7 @@ using namespace android::hardware::wifi::V1_0; * Since there is only a single chip instance used today, there is no * identifying handle information stored here. */ -class WifiChip : public V1_2::IWifiChip { +class WifiChip : public V1_3::IWifiChip { public: WifiChip( ChipId chip_id, @@ -69,10 +69,11 @@ class WifiChip : public V1_2::IWifiChip { // marked valid before processing them. void invalidate(); bool isValid(); - std::set<sp<IWifiChipEventCallback>> getEventCallbacks(); + std::set<sp<V1_2::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; @@ -125,6 +126,8 @@ class WifiChip : public V1_2::IWifiChip { 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( @@ -136,19 +139,25 @@ class WifiChip : public V1_2::IWifiChip { 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<IWifiChipEventCallback>& event_callback, + 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> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override; + private: void invalidateAndRemoveAllIfaces(); // 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(); @@ -191,21 +200,24 @@ class WifiChip : public V1_2::IWifiChip { 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 selectTxPowerScenarioInternal( + V1_1::IWifiChip::TxPowerScenario scenario); WifiStatus resetTxPowerScenarioInternal(); + WifiStatus setLatencyModeInternal(LatencyMode mode); WifiStatus registerEventCallbackInternal_1_2( - const sp<IWifiChipEventCallback>& event_callback); + const sp<V1_2::IWifiChipEventCallback>& event_callback); WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario); + std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3(); WifiStatus handleChipConfiguration( std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id); WifiStatus registerDebugRingBufferCallback(); WifiStatus registerRadioModeChangeCallback(); - void populateModes(); std::vector<IWifiChip::ChipIfaceCombination> getCurrentModeIfaceCombinations(); std::map<IfaceType, size_t> getCurrentIfaceCombination(); @@ -236,14 +248,14 @@ class WifiChip : public V1_2::IWifiChip { // registration mechanism. Use this to check if we have already // registered a callback. bool debug_ring_buffer_cb_registered_; - hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback> + hidl_callback_util::HidlCallbackHandler<V1_2::IWifiChipEventCallback> event_cb_handler_; DISALLOW_COPY_AND_ASSIGN(WifiChip); }; } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/default/wifi_feature_flags.cpp b/wifi/1.3/default/wifi_feature_flags.cpp new file mode 100644 index 0000000000..17b3bee01c --- /dev/null +++ b/wifi/1.3/default/wifi_feature_flags.cpp @@ -0,0 +1,158 @@ +/* + * 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_feature_flags.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_3 { +namespace implementation { +namespace feature_flags { + +using V1_0::ChipModeId; +using V1_0::IfaceType; +using V1_0::IWifiChip; + +/* 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 combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface + * operations. + * Interface 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 interface combinations: + * Interface Combination 1: Will support 1 STA and 1 P2P or NAN (optional) + * concurrent iface operations. + * Interface 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 interface 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 iface 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 ChipIfaceCombination + : public hidl_vec<IWifiChip::ChipIfaceCombinationLimit> { + ChipIfaceCombination( + const std::initializer_list<IWifiChip::ChipIfaceCombinationLimit> list) + : hidl_vec(list) {} + + operator IWifiChip::ChipIfaceCombination() const { return {*this}; } + + static hidl_vec<IWifiChip::ChipIfaceCombination> make_vec( + const std::initializer_list<ChipIfaceCombination> list) { + return hidl_vec<IWifiChip::ChipIfaceCombination>( // + std::begin(list), std::end(list)); + } +}; + +#define STA IfaceType::STA +#define AP IfaceType::AP +#define P2P IfaceType::P2P +#define NAN IfaceType::NAN +static const std::vector<IWifiChip::ChipMode> kChipModes{ + {kMainModeId, + ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})}, +#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP + {chip_mode_ids::kV1Ap, + ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})}, +#endif +}; +#undef STA +#undef AP +#undef P2P +#undef NAN + +WifiFeatureFlags::WifiFeatureFlags() {} + +std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() { + return kChipModes; +} + +} // namespace feature_flags +} // namespace implementation +} // namespace V1_3 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/wifi_feature_flags.h b/wifi/1.3/default/wifi_feature_flags.h index 4a7b2d225c..b99a4166b5 100644 --- a/wifi/1.2/default/wifi_feature_flags.h +++ b/wifi/1.3/default/wifi_feature_flags.h @@ -17,26 +17,37 @@ #ifndef WIFI_FEATURE_FLAGS_H_ #define WIFI_FEATURE_FLAGS_H_ +#include <android/hardware/wifi/1.2/IWifiChip.h> + namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { 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 bool isAwareSupported(); - virtual bool isDualInterfaceSupported(); - virtual bool isApDisabled(); + virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes(); }; } // namespace feature_flags } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.3/default/wifi_legacy_hal.cpp index 375204c70d..2b90f9200c 100644 --- a/wifi/1.2/default/wifi_legacy_hal.cpp +++ b/wifi/1.3/default/wifi_legacy_hal.cpp @@ -18,6 +18,7 @@ #include <chrono> #include <android-base/logging.h> +#include <cutils/properties.h> #include "hidl_sync_util.h" #include "wifi_legacy_hal.h" @@ -35,6 +36,7 @@ static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128; static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32; static constexpr uint32_t kMaxRingBuffers = 10; static constexpr uint32_t kMaxStopCompleteWaitMs = 100; +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) { @@ -48,7 +50,7 @@ std::vector<char> makeCharVec(const std::string& str) { namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace legacy_hal { // Legacy HAL functions accept "C" style function pointers, so use global @@ -366,6 +368,8 @@ wifi_error WifiLegacyHal::start() { LOG(ERROR) << "Timed out awaiting driver ready"; return status; } + property_set(kDriverPropName, "ok"); + LOG(DEBUG) << "Starting legacy HAL"; if (!iface_tool_.SetWifiUpState(true)) { LOG(ERROR) << "Failed to set WiFi interface up"; @@ -547,6 +551,7 @@ wifi_error WifiLegacyHal::startGscan( 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. @@ -648,6 +653,8 @@ std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats( [&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; + if (iface_stats_ptr != nullptr) { link_stats_ptr->iface = *iface_stats_ptr; link_stats_ptr->iface.num_peers = 0; @@ -658,20 +665,35 @@ std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats( 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 = radio_stats_ptr[i]; + + radio.stats = *l_radio_stats_ptr; // Copy over the tx level array to the separate vector. - if (radio_stats_ptr[i].num_tx_levels > 0 && - radio_stats_ptr[i].tx_time_per_levels != nullptr) { + if (l_radio_stats_ptr->num_tx_levels > 0 && + l_radio_stats_ptr->tx_time_per_levels != nullptr) { radio.tx_time_per_levels.assign( - radio_stats_ptr[i].tx_time_per_levels, - radio_stats_ptr[i].tx_time_per_levels + - radio_stats_ptr[i].num_tx_levels); + 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)); } }; @@ -792,6 +814,12 @@ wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) { 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); +} + std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet( const std::string& iface_name) { uint32_t supported_feature_flags; @@ -1417,7 +1445,7 @@ void WifiLegacyHal::invalidate() { } // namespace legacy_hal } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.3/default/wifi_legacy_hal.h index 00dfeefb9a..d6f05ae400 100644 --- a/wifi/1.2/default/wifi_legacy_hal.h +++ b/wifi/1.3/default/wifi_legacy_hal.h @@ -27,14 +27,15 @@ // HACK: The include inside the namespace below also transitively includes a // bunch of libc headers into the namespace, which leads to functions like -// socketpair being defined in android::hardware::wifi::V1_1::implementation::legacy_hal. -// Include this one particular header as a hacky workaround until that's fixed. +// socketpair being defined in +// android::hardware::wifi::V1_1::implementation::legacy_hal. Include this one +// particular header as a hacky workaround until that's fixed. #include <sys/socket.h> namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { // This is in a separate namespace to prevent typename conflicts between // the legacy HAL types and the HIDL interface types. @@ -60,6 +61,7 @@ struct PacketFilterCapabilities { struct LinkLayerRadioStats { wifi_radio_stat stats; std::vector<uint32_t> tx_time_per_levels; + std::vector<wifi_channel_stat> channel_stats; }; struct LinkLayerStats { @@ -106,7 +108,8 @@ struct NanCallbackHandlers { 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; + std::function<void(const NanDataPathScheduleUpdateInd&)> + on_event_schedule_update; }; // Full scan results contain IE info and are hence passed by reference, to @@ -252,6 +255,8 @@ class WifiLegacyHal { wifi_error selectTxPowerScenario(const std::string& iface_name, wifi_power_scenario scenario); wifi_error resetTxPowerScenario(const std::string& iface_name); + wifi_error setLatencyMode(const std::string& iface_name, + wifi_latency_mode mode); // Logger/debug functions. std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet( const std::string& iface_name); @@ -389,7 +394,7 @@ class WifiLegacyHal { } // namespace legacy_hal } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_legacy_hal_stubs.cpp b/wifi/1.3/default/wifi_legacy_hal_stubs.cpp index fc28bb55e8..dedd2d4819 100644 --- a/wifi/1.2/default/wifi_legacy_hal_stubs.cpp +++ b/wifi/1.3/default/wifi_legacy_hal_stubs.cpp @@ -20,7 +20,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace legacy_hal { template <typename> @@ -137,11 +137,12 @@ bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) { 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); return true; } } // namespace legacy_hal } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_legacy_hal_stubs.h b/wifi/1.3/default/wifi_legacy_hal_stubs.h index d560dd4e80..64854e00f6 100644 --- a/wifi/1.2/default/wifi_legacy_hal_stubs.h +++ b/wifi/1.3/default/wifi_legacy_hal_stubs.h @@ -20,7 +20,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace legacy_hal { #include <hardware_legacy/wifi_hal.h> @@ -28,7 +28,7 @@ namespace legacy_hal { bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn); } // namespace legacy_hal } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_mode_controller.cpp b/wifi/1.3/default/wifi_mode_controller.cpp index c286d2439c..c392486f84 100644 --- a/wifi/1.2/default/wifi_mode_controller.cpp +++ b/wifi/1.3/default/wifi_mode_controller.cpp @@ -48,7 +48,7 @@ int convertIfaceTypeToFirmwareMode(IfaceType type) { namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace mode_controller { @@ -85,7 +85,7 @@ bool WifiModeController::deinitialize() { } } // namespace mode_controller } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_mode_controller.h b/wifi/1.3/default/wifi_mode_controller.h index 395aa5d9e8..ace5a52839 100644 --- a/wifi/1.2/default/wifi_mode_controller.h +++ b/wifi/1.3/default/wifi_mode_controller.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { namespace mode_controller { using namespace android::hardware::wifi::V1_0; @@ -55,7 +55,7 @@ class WifiModeController { } // namespace mode_controller } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.3/default/wifi_nan_iface.cpp index 566d36e72b..4325f44dad 100644 --- a/wifi/1.2/default/wifi_nan_iface.cpp +++ b/wifi/1.3/default/wifi_nan_iface.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using hidl_return_util::validateAndCall; @@ -420,7 +420,7 @@ WifiNanIface::WifiNanIface( LOG(ERROR) << "Callback invoked on an invalid object"; return; } - NanDataPathConfirmInd hidl_struct; + V1_2::NanDataPathConfirmInd hidl_struct; if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl( msg, &hidl_struct)) { LOG(ERROR) << "Failed to convert nan capabilities response"; @@ -477,7 +477,7 @@ WifiNanIface::WifiNanIface( LOG(ERROR) << "Callback invoked on an invalid object"; return; } - NanDataPathScheduleUpdateInd hidl_struct; + V1_2::NanDataPathScheduleUpdateInd hidl_struct; if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl( msg, &hidl_struct)) { LOG(ERROR) << "Failed to convert nan capabilities response"; @@ -655,7 +655,7 @@ Return<void> WifiNanIface::terminateDataPathRequest( } Return<void> WifiNanIface::registerEventCallback_1_2( - const sp<IWifiNanIfaceEventCallback>& callback, + 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, @@ -664,7 +664,7 @@ Return<void> WifiNanIface::registerEventCallback_1_2( Return<void> WifiNanIface::enableRequest_1_2( uint16_t cmd_id, const NanEnableRequest& msg1, - const NanConfigRequestSupplemental& msg2, + const V1_2::NanConfigRequestSupplemental& msg2, enableRequest_1_2_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiNanIface::enableRequest_1_2Internal, @@ -673,7 +673,7 @@ Return<void> WifiNanIface::enableRequest_1_2( Return<void> WifiNanIface::configRequest_1_2( uint16_t cmd_id, const NanConfigRequest& msg1, - const NanConfigRequestSupplemental& msg2, + const V1_2::NanConfigRequestSupplemental& msg2, configRequest_1_2_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiNanIface::configRequest_1_2Internal, @@ -832,7 +832,7 @@ WifiStatus WifiNanIface::registerEventCallback_1_2Internal( WifiStatus WifiNanIface::enableRequest_1_2Internal( uint16_t cmd_id, const NanEnableRequest& msg1, - const NanConfigRequestSupplemental& msg2) { + const V1_2::NanConfigRequestSupplemental& msg2) { legacy_hal::NanEnableRequest legacy_msg; if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy( msg1, msg2, &legacy_msg)) { @@ -845,7 +845,7 @@ WifiStatus WifiNanIface::enableRequest_1_2Internal( WifiStatus WifiNanIface::configRequest_1_2Internal( uint16_t cmd_id, const NanConfigRequest& msg1, - const NanConfigRequestSupplemental& msg2) { + const V1_2::NanConfigRequestSupplemental& msg2) { legacy_hal::NanConfigRequest legacy_msg; if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy( msg1, msg2, &legacy_msg)) { @@ -857,7 +857,7 @@ WifiStatus WifiNanIface::configRequest_1_2Internal( } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_nan_iface.h b/wifi/1.3/default/wifi_nan_iface.h index dba527b5f5..f735d61cf9 100644 --- a/wifi/1.2/default/wifi_nan_iface.h +++ b/wifi/1.3/default/wifi_nan_iface.h @@ -27,7 +27,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -89,15 +89,15 @@ class WifiNanIface : public V1_2::IWifiNanIface { terminateDataPathRequest_cb hidl_status_cb) override; Return<void> registerEventCallback_1_2( - const sp<IWifiNanIfaceEventCallback>& callback, + const sp<V1_2::IWifiNanIfaceEventCallback>& callback, registerEventCallback_1_2_cb hidl_status_cb) override; Return<void> enableRequest_1_2( uint16_t cmd_id, const NanEnableRequest& msg1, - const NanConfigRequestSupplemental& msg2, + const V1_2::NanConfigRequestSupplemental& msg2, enableRequest_1_2_cb hidl_status_cb) override; Return<void> configRequest_1_2( uint16_t cmd_id, const NanConfigRequest& msg1, - const NanConfigRequestSupplemental& msg2, + const V1_2::NanConfigRequestSupplemental& msg2, configRequest_1_2_cb hidl_status_cb) override; private: @@ -135,10 +135,10 @@ class WifiNanIface : public V1_2::IWifiNanIface { const sp<V1_2::IWifiNanIfaceEventCallback>& callback); WifiStatus enableRequest_1_2Internal( uint16_t cmd_id, const NanEnableRequest& msg1, - const NanConfigRequestSupplemental& msg2); + const V1_2::NanConfigRequestSupplemental& msg2); WifiStatus configRequest_1_2Internal( uint16_t cmd_id, const NanConfigRequest& msg, - const NanConfigRequestSupplemental& msg2); + const V1_2::NanConfigRequestSupplemental& msg2); // all 1_0 and descendant callbacks std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks(); @@ -157,7 +157,7 @@ class WifiNanIface : public V1_2::IWifiNanIface { }; } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_p2p_iface.cpp b/wifi/1.3/default/wifi_p2p_iface.cpp index 92bbaee388..b5d5886f68 100644 --- a/wifi/1.2/default/wifi_p2p_iface.cpp +++ b/wifi/1.3/default/wifi_p2p_iface.cpp @@ -23,7 +23,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using hidl_return_util::validateAndCall; @@ -60,7 +60,7 @@ std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() { } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_p2p_iface.h b/wifi/1.3/default/wifi_p2p_iface.h index 76120b1574..8a7207a412 100644 --- a/wifi/1.2/default/wifi_p2p_iface.h +++ b/wifi/1.3/default/wifi_p2p_iface.h @@ -25,7 +25,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -58,7 +58,7 @@ class WifiP2pIface : public V1_0::IWifiP2pIface { }; } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_rtt_controller.cpp b/wifi/1.3/default/wifi_rtt_controller.cpp index b68445bf83..fa317e3aeb 100644 --- a/wifi/1.2/default/wifi_rtt_controller.cpp +++ b/wifi/1.3/default/wifi_rtt_controller.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using hidl_return_util::validateAndCall; @@ -269,7 +269,7 @@ WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) { return createWifiStatusFromLegacyError(legacy_status); } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_rtt_controller.h b/wifi/1.3/default/wifi_rtt_controller.h index 1ab01e1702..9798b79f8d 100644 --- a/wifi/1.2/default/wifi_rtt_controller.h +++ b/wifi/1.3/default/wifi_rtt_controller.h @@ -27,7 +27,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { /** @@ -97,7 +97,7 @@ class WifiRttController : public V1_0::IWifiRttController { }; } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_sta_iface.cpp b/wifi/1.3/default/wifi_sta_iface.cpp index daa56101c3..f7157a34af 100644 --- a/wifi/1.2/default/wifi_sta_iface.cpp +++ b/wifi/1.3/default/wifi_sta_iface.cpp @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using hidl_return_util::validateAndCall; @@ -152,6 +152,13 @@ Return<void> WifiStaIface::getLinkLayerStats( 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::startRssiMonitoring( uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi, startRssiMonitoring_cb hidl_status_cb) { @@ -248,6 +255,13 @@ Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac, mac); } +Return<void> WifiStaIface::getFactoryMacAddress( + getFactoryMacAddress_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getFactoryMacAddressInternal, + hidl_status_cb); +} + std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_}; } @@ -445,8 +459,13 @@ WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() { return createWifiStatusFromLegacyError(legacy_status); } -std::pair<WifiStatus, StaLinkLayerStats> +std::pair<WifiStatus, V1_0::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal() { + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}}; +} + +std::pair<WifiStatus, V1_3::StaLinkLayerStats> +WifiStaIface::getLinkLayerStatsInternal_1_3() { legacy_hal::wifi_error legacy_status; legacy_hal::LinkLayerStats legacy_stats; std::tie(legacy_status, legacy_stats) = @@ -454,7 +473,7 @@ WifiStaIface::getLinkLayerStatsInternal() { if (legacy_status != legacy_hal::WIFI_SUCCESS) { return {createWifiStatusFromLegacyError(legacy_status), {}}; } - StaLinkLayerStats hidl_stats; + V1_3::StaLinkLayerStats hidl_stats; if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &hidl_stats)) { return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}}; @@ -621,8 +640,15 @@ WifiStatus WifiStaIface::setMacAddressInternal( return createWifiStatus(WifiStatusCode::SUCCESS); } +std::pair<WifiStatus, std::array<uint8_t, 6>> +WifiStaIface::getFactoryMacAddressInternal() { + std::array<uint8_t, 6> mac = + iface_tool_.GetFactoryMacAddress(ifname_.c_str()); + return {createWifiStatus(WifiStatusCode::SUCCESS), mac}; +} + } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_sta_iface.h b/wifi/1.3/default/wifi_sta_iface.h index 71cd17d30c..69cb82a79f 100644 --- a/wifi/1.2/default/wifi_sta_iface.h +++ b/wifi/1.3/default/wifi_sta_iface.h @@ -19,7 +19,7 @@ #include <android-base/macros.h> #include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h> -#include <android/hardware/wifi/1.2/IWifiStaIface.h> +#include <android/hardware/wifi/1.3/IWifiStaIface.h> #include <wifi_system/interface_tool.h> @@ -29,14 +29,14 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using namespace android::hardware::wifi::V1_0; /** * HIDL interface object used to control a STA Iface instance. */ -class WifiStaIface : public V1_2::IWifiStaIface { +class WifiStaIface : public V1_3::IWifiStaIface { public: WifiStaIface(const std::string& ifname, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal); @@ -75,6 +75,8 @@ class WifiStaIface : public V1_2::IWifiStaIface { 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> startRssiMonitoring( uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi, startRssiMonitoring_cb hidl_status_cb) override; @@ -107,6 +109,8 @@ class WifiStaIface : public V1_2::IWifiStaIface { 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; private: // Corresponding worker functions for the HIDL methods. @@ -130,7 +134,9 @@ class WifiStaIface : public V1_2::IWifiStaIface { WifiStatus stopBackgroundScanInternal(uint32_t cmd_id); WifiStatus enableLinkLayerStatsCollectionInternal(bool debug); WifiStatus disableLinkLayerStatsCollectionInternal(); - std::pair<WifiStatus, StaLinkLayerStats> getLinkLayerStatsInternal(); + std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal(); + std::pair<WifiStatus, V1_3::StaLinkLayerStats> + getLinkLayerStatsInternal_1_3(); WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi); WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id); @@ -151,6 +157,8 @@ class WifiStaIface : public V1_2::IWifiStaIface { 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(); std::string ifname_; std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_; @@ -163,7 +171,7 @@ class WifiStaIface : public V1_2::IWifiStaIface { }; } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_status_util.cpp b/wifi/1.3/default/wifi_status_util.cpp index dd37b6ba80..0a5bb13d4f 100644 --- a/wifi/1.2/default/wifi_status_util.cpp +++ b/wifi/1.3/default/wifi_status_util.cpp @@ -19,7 +19,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { std::string legacyErrorToString(legacy_hal::wifi_error error) { @@ -100,7 +100,7 @@ WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) { } } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.2/default/wifi_status_util.h b/wifi/1.3/default/wifi_status_util.h index e9136b38ca..bc8baa9fe7 100644 --- a/wifi/1.2/default/wifi_status_util.h +++ b/wifi/1.3/default/wifi_status_util.h @@ -24,7 +24,7 @@ namespace android { namespace hardware { namespace wifi { -namespace V1_2 { +namespace V1_3 { namespace implementation { using namespace android::hardware::wifi::V1_0; @@ -37,7 +37,7 @@ WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error, WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error); } // namespace implementation -} // namespace V1_2 +} // namespace V1_3 } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/1.3/types.hal b/wifi/1.3/types.hal new file mode 100644 index 0000000000..3b292b074b --- /dev/null +++ b/wifi/1.3/types.hal @@ -0,0 +1,89 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.3; + +import @1.0::StaLinkLayerRadioStats; +import @1.0::StaLinkLayerIfaceStats; +import @1.0::TimeStampInMs; +import @1.0::WifiChannelInfo; + +struct WifiChannelStats { + /** + * Channel information. + */ + WifiChannelInfo channel; + /** + * Total time for which the radio is awake on this channel. + */ + uint32_t onTimeInMs; + /** + * Total time for which CCA is held busy on this channel. + */ + uint32_t ccaBusyTimeInMs; +}; + +struct StaLinkLayerRadioStats { + /** + * Baseline information as defined in HAL 1.0. + */ + @1.0::StaLinkLayerRadioStats V1_0; + + /** + * Total time for which the radio is awake due to NAN scan since boot or crash. + */ + uint32_t onTimeInMsForNanScan; + + /** + * Total time for which the radio is awake due to background scan since boot or crash. + */ + uint32_t onTimeInMsForBgScan; + + /** + * Total time for which the radio is awake due to roam scan since boot or crash. + */ + uint32_t onTimeInMsForRoamScan; + + /** + * Total time for which the radio is awake due to PNO scan since boot or crash. + */ + uint32_t onTimeInMsForPnoScan; + + /** + * Total time for which the radio is awake due to Hotspot 2.0 scans and GAS exchange since boot + * or crash. + */ + uint32_t onTimeInMsForHs20Scan; + + /** + * List of channel stats associated with this radio + */ + vec<WifiChannelStats> channelStats; +}; + +/** + * Link layer stats retrieved via |getLinkLayerStats|. + */ +struct StaLinkLayerStats { + StaLinkLayerIfaceStats iface; + vec<StaLinkLayerRadioStats> radios; + /** + * TimeStamp for each stats sample. + * This is the absolute milliseconds from boot when these stats were + * sampled. + */ + TimeStampInMs timeStampInMs; +};
\ No newline at end of file diff --git a/wifi/1.3/vts/OWNERS b/wifi/1.3/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/1.3/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp new file mode 100644 index 0000000000..53c8f08516 --- /dev/null +++ b/wifi/1.3/vts/functional/Android.bp @@ -0,0 +1,32 @@ +// +// 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. +// + +cc_test { + name: "VtsHalWifiV1_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiV1_3TargetTest.cpp", + "wifi_chip_hidl_test.cpp", + "wifi_sta_iface_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "android.hardware.wifi@1.2", + "android.hardware.wifi@1.3", + ], +} diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp new file mode 100644 index 0000000000..faf426e999 --- /dev/null +++ b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp @@ -0,0 +1,50 @@ +/* + * 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 <android/hardware/wifi/1.3/IWifi.h> + +#include "wifi_hidl_test_utils.h" + +using ::android::hardware::wifi::V1_3::IWifi; + +// Test environment for Wifi HIDL HAL. +class WifiHidlEnvironment_1_3 : public WifiHidlEnvironment { + public: + // get the test environment singleton + static WifiHidlEnvironment_1_3* Instance() { + static WifiHidlEnvironment_1_3* instance = new WifiHidlEnvironment_1_3; + return instance; + } + + virtual void registerTestServices() override { + registerTestService<android::hardware::wifi::V1_3::IWifi>(); + } + + private: + WifiHidlEnvironment_1_3() {} +}; + +WifiHidlEnvironment_1_3* gEnv = WifiHidlEnvironment_1_3::Instance(); + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp new file mode 100644 index 0000000000..d980fcb310 --- /dev/null +++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp @@ -0,0 +1,118 @@ +/* + * 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 <android/hardware/wifi/1.3/IWifiChip.h> + +#include <VtsHalHidlTargetTestBase.h> + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::wifi::V1_0::ChipModeId; +using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_3::IWifiChip; + +namespace { +constexpr IWifiChip::LatencyMode kLatencyModeNormal = + IWifiChip::LatencyMode::NORMAL; + +constexpr IWifiChip::LatencyMode kLatencyModeLow = IWifiChip::LatencyMode::LOW; +}; // namespace + +/** + * Fixture to use for all Wifi chip HIDL interface tests. + */ +class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + wifi_chip_ = IWifiChip::castFrom(getWifiChip()); + ASSERT_NE(nullptr, wifi_chip_.get()); + } + + virtual void TearDown() override { stopWifi(); } + + protected: + // Helper function to configure the Chip in one of the supported modes. + // Most of the non-mode-configuration-related methods require chip + // to be first configured. + ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) { + ChipModeId mode_id; + EXPECT_EQ(expectSuccess, + configureChipToSupportIfaceType(wifi_chip_, type, &mode_id)); + return mode_id; + } + + uint32_t configureChipForStaIfaceAndGetCapabilities() { + ChipModeId mode_id; + EXPECT_TRUE(configureChipToSupportIfaceType(wifi_chip_, IfaceType::STA, + &mode_id)); + const auto& status_and_caps = + HIDL_INVOKE(wifi_chip_, getCapabilities_1_3); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code); + return status_and_caps.second; + } + + sp<IWifiChip> wifi_chip_; +}; + +/* + * SetLatencyMode_normal + * This test case tests the setLatencyMode() API with + * Latency mode NORMAL + */ +TEST_F(WifiChipHidlTest, SetLatencyMode_normal) { + uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); + const auto& status = + HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeNormal); + if (caps & (IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE)) { + EXPECT_EQ(WifiStatusCode::SUCCESS, status.code); + } else { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code); + } +} + +/* + * SetLatencyMode_low + * This test case tests the setLatencyMode() API with Latency mode LOW + */ +TEST_F(WifiChipHidlTest, SetLatencyMode_low) { + uint32_t caps = configureChipForStaIfaceAndGetCapabilities(); + const auto& status = + HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeLow); + if (caps & (IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE)) { + EXPECT_EQ(WifiStatusCode::SUCCESS, status.code); + } else { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code); + } +} + +/* + * GetCapabilities_1_3 + */ +TEST_F(WifiChipHidlTest, GetCapabilities_1_3) { + configureChipForIfaceType(IfaceType::STA, true); + const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities_1_3); + if (status_and_caps.first.code != WifiStatusCode::SUCCESS) { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, + status_and_caps.first.code); + return; + } + EXPECT_NE(0u, status_and_caps.second); +} diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp new file mode 100644 index 0000000000..71e90acb93 --- /dev/null +++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Staache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <numeric> +#include <vector> + +#include <android-base/logging.h> + +#include <android/hardware/wifi/1.3/IWifiStaIface.h> + +#include <VtsHalHidlTargetTestBase.h> + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_3::IWifiStaIface; + +/** + * Fixture to use for all STA Iface HIDL interface tests. + */ +class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface()); + ASSERT_NE(nullptr, wifi_sta_iface_.get()); + } + + virtual void TearDown() override { stopWifi(); } + + protected: + bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) { + const auto& status_and_caps = + HIDL_INVOKE(wifi_sta_iface_, getCapabilities); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code); + return (status_and_caps.second & cap_mask) != 0; + } + + sp<IWifiStaIface> wifi_sta_iface_; +}; + +/* + * GetFactoryMacAddress: + * Ensures that calls to get factory MAC address will retrieve a non-zero MAC + * and return a success status code. + */ +TEST_F(WifiStaIfaceHidlTest, GetFactoryMacAddress) { + const auto& status_and_mac = + HIDL_INVOKE(wifi_sta_iface_, getFactoryMacAddress); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code); + const int num_elements = sizeof(status_and_mac.second) / sizeof(uint8_t); + EXPECT_EQ(6, num_elements); + for (int i = 0; i < num_elements; i++) { + EXPECT_NE(0, status_and_mac.second[i]); + } +} + +/* + * GetLinkLayerStats_1_3 + * Ensures that calls to get link layer stats V1_3 will retrieve a non-empty + * StaLinkLayerStats after link layer stats collection is enabled. + */ +TEST_F(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) { + if (!isCapabilitySupported( + IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) { + // No-op if link layer stats is not supported. + return; + } + + // Enable link layer stats collection. + EXPECT_EQ(WifiStatusCode::SUCCESS, + HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true) + .code); + // Retrieve link layer stats. + const auto& status_and_stats = + HIDL_INVOKE(wifi_sta_iface_, getLinkLayerStats_1_3); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code); + EXPECT_GT(status_and_stats.second.timeStampInMs, 0u); + // Disable link layer stats collection. + EXPECT_EQ( + WifiStatusCode::SUCCESS, + HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code); +} diff --git a/wifi/hostapd/1.0/vts/OWNERS b/wifi/hostapd/1.0/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/hostapd/1.0/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/hostapd/1.0/vts/functional/Android.bp b/wifi/hostapd/1.0/vts/functional/Android.bp index 79c5183886..93867d28ad 100644 --- a/wifi/hostapd/1.0/vts/functional/Android.bp +++ b/wifi/hostapd/1.0/vts/functional/Android.bp @@ -24,6 +24,7 @@ cc_library_static { static_libs: [ "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", "android.hardware.wifi@1.0", "libcrypto", "libgmock", @@ -43,6 +44,7 @@ cc_test { "VtsHalWifiV1_0TargetTestUtil", "VtsHalWifiHostapdV1_0TargetTestUtil", "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", "android.hardware.wifi@1.0", "libcrypto", "libgmock", diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp index 504f4c8d2b..fa780f9a5c 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp @@ -138,9 +138,11 @@ TEST(HostapdHidlTestNoFixture, Create) { * Access point creation should pass. */ TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(), - getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -148,9 +150,11 @@ TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) { * Access point creation should pass. */ TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(), - getOpenNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithAcs(), getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -158,9 +162,11 @@ TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) { * Access point creation should pass. */ TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, - getIfaceParamsWithoutAcs(), getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -168,9 +174,12 @@ TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) { * Access point creation should pass. */ TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, - getIfaceParamsWithoutAcs(), getOpenNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(), + getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -178,12 +187,14 @@ TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { * Access point creation & removal should pass. */ TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(), - getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); - status = - HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -191,12 +202,14 @@ TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) { * Access point creation & removal should pass. */ TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) { - auto status = HIDL_INVOKE(hostapd_, addAccessPoint, - getIfaceParamsWithoutAcs(), getPskNwParams()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); - status = - HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); - EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -204,10 +217,12 @@ TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) { * Access point creation should fail. */ TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) { - auto status = - HIDL_INVOKE(hostapd_, addAccessPoint, - getIfaceParamsWithInvalidChannel(), getPskNwParams()); - EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint, + getIfaceParamsWithInvalidChannel(), getPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + } } /** @@ -215,10 +230,12 @@ TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) { * Access point creation should fail. */ TEST_F(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) { - auto status = - HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(), - getInvalidPskNwParams()); - EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + if (!is_1_1(hostapd_)) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(), + getInvalidPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); + } } /* diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp index e5ba8efa90..22dbb528c3 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp @@ -130,6 +130,12 @@ void startHostapdAndWaitForHidlService() { ASSERT_TRUE(notification_listener->waitForHidlService(200, service_name)); } +bool is_1_1(const sp<IHostapd>& hostapd) { + sp<::android::hardware::wifi::hostapd::V1_1::IHostapd> hostapd_1_1 = + ::android::hardware::wifi::hostapd::V1_1::IHostapd::castFrom(hostapd); + return hostapd_1_1.get() != nullptr; +} + sp<IHostapd> getHostapd() { return ::testing::VtsHalHidlTargetTestBase::getService<IHostapd>( gEnv->getServiceName<IHostapd>()); diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h index 1b92477329..8e2f1a34d1 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h @@ -18,6 +18,7 @@ #define HOSTAPD_HIDL_TEST_UTILS_H #include <android/hardware/wifi/hostapd/1.0/IHostapd.h> +#include <android/hardware/wifi/hostapd/1.1/IHostapd.h> #include <VtsHalHidlTargetTestEnvBase.h> @@ -34,6 +35,8 @@ void startHostapdAndWaitForHidlService(); // These helper functions should be modified to return vectors if we support // multiple instances. android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd> getHostapd(); +bool is_1_1(const android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd>& + hostapd); class WifiHostapdHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { diff --git a/wifi/hostapd/1.1/Android.bp b/wifi/hostapd/1.1/Android.bp new file mode 100644 index 0000000000..d4170b678a --- /dev/null +++ b/wifi/hostapd/1.1/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.wifi.hostapd@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "IHostapd.hal", + "IHostapdCallback.hal", + ], + interfaces: [ + "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.supplicant@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} + diff --git a/wifi/hostapd/1.1/IHostapd.hal b/wifi/hostapd/1.1/IHostapd.hal new file mode 100644 index 0000000000..c144f6a03e --- /dev/null +++ b/wifi/hostapd/1.1/IHostapd.hal @@ -0,0 +1,103 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.hostapd@1.1; + +import @1.0::IHostapd; +import @1.0::HostapdStatus; + +import IHostapdCallback; + +/** + * Top-level object for managing SoftAPs. + */ +interface IHostapd extends @1.0::IHostapd { + /** + * Parameters to specify the channel range for ACS. + */ + struct AcsChannelRange { + /** + * Channel number (IEEE 802.11) at the start of the range. + */ + uint32_t start; + /** + * Channel number (IEEE 802.11) at the end of the range. + */ + uint32_t end; + }; + + /** + * Parameters to control the channel selection for the interface. + */ + struct ChannelParams { + /** + * This option can be used to specify the channels selected by ACS. + * If this is an empty list, all channels allowed in selected HW mode + * are specified implicitly. + * Note: channels may be overridden by firmware. + * Note: this option is ignored if ACS is disabled. + */ + vec<AcsChannelRange> acsChannelRanges; + }; + + /** + * Parameters to use for setting up the access point interface. + */ + struct IfaceParams { + /** + * Baseline information as defined in HAL 1.0. + */ + @1.0::IHostapd.IfaceParams V1_0; + /** Additional Channel params for the interface */ + ChannelParams channelParams; + }; + + /** + * Adds a new access point for hostapd to control. + * + * This should trigger the setup of an access point with the specified + * interface and network params. + * + * @param ifaceParams AccessPoint Params for the access point. + * @param nwParams Network Params for the access point. + * @return status Status of the operation. + * Possible status codes: + * |HostapdStatusCode.SUCCESS|, + * |HostapdStatusCode.FAILURE_ARGS_INVALID|, + * |HostapdStatusCode.FAILURE_UNKNOWN|, + * |HostapdStatusCode.FAILURE_IFACE_EXISTS| + */ + addAccessPoint_1_1(IfaceParams ifaceParams, NetworkParams nwParams) + generates(HostapdStatus status); + + /** + * Register for callbacks from the hostapd service. + * + * These callbacks are invoked for global events that are not specific + * to any interface or network. Registration of multiple callback + * objects is supported. These objects must be deleted when the corresponding + * client process is dead. + * + * @param callback An instance of the |IHostapdCallback| HIDL interface + * object. + * @return status Status of the operation. + * Possible status codes: + * |HostapdStatusCode.SUCCESS|, + * |HostapdStatusCode.FAILURE_UNKNOWN| + */ + registerCallback(IHostapdCallback callback) + generates (HostapdStatus status); +}; diff --git a/audio/common/2.0/default/HidlUtils.h b/wifi/hostapd/1.1/IHostapdCallback.hal index 24543b1617..1d314fe91e 100644 --- a/audio/common/2.0/default/HidlUtils.h +++ b/wifi/hostapd/1.1/IHostapdCallback.hal @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright 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. @@ -14,13 +14,17 @@ * limitations under the License. */ -#ifndef android_hardware_audio_V2_0_Hidl_Utils_H_ -#define android_hardware_audio_V2_0_Hidl_Utils_H_ +package android.hardware.wifi.hostapd@1.1; -#include <android/hardware/audio/common/2.0/types.h> - -#define AUDIO_HAL_VERSION V2_0 -#include <common/all-versions/default/HidlUtils.h> -#undef AUDIO_HAL_VERSION - -#endif // android_hardware_audio_V2_0_Hidl_Utils_H_ +/** + * Top-level object for managing SoftAPs. + */ +interface IHostapdCallback { + /** + * Invoked when an asynchronous failure is encountered in one of the access + * points added via |IHostapd.addAccessPoint|. + * + * @param ifaceName Name of the interface. + */ + oneway onFailure(string ifaceName); +}; diff --git a/wifi/hostapd/1.1/vts/OWNERS b/wifi/hostapd/1.1/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/hostapd/1.1/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/hostapd/1.1/vts/functional/Android.bp b/wifi/hostapd/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..bbf5246cee --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/Android.bp @@ -0,0 +1,58 @@ +// +// 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. +// + +cc_library_static { + name: "VtsHalWifiHostapdV1_1TargetTestUtil", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["hostapd_hidl_test_utils_1_1.cpp"], + export_include_dirs: [ + "." + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiHostapdV1_0TargetTestUtil", + "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", + "android.hardware.wifi@1.0", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], +} + +cc_test { + name: "VtsHalWifiHostapdV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiHostapdV1_1TargetTest.cpp", + "hostapd_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiHostapdV1_0TargetTestUtil", + "VtsHalWifiHostapdV1_1TargetTestUtil", + "android.hardware.wifi.hostapd@1.0", + "android.hardware.wifi.hostapd@1.1", + "android.hardware.wifi@1.0", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], + test_suites: ["general-tests"], +} + diff --git a/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp b/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp new file mode 100644 index 0000000000..6916db2ca7 --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp @@ -0,0 +1,51 @@ +/* + * 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/hardware/wifi/1.0/IWifi.h> + +#include "hostapd_hidl_test_utils.h" +#include "hostapd_hidl_test_utils_1_1.h" + +class WifiHostapdHidlEnvironment_1_1 : public WifiHostapdHidlEnvironment { + public: + // get the test environment singleton + static WifiHostapdHidlEnvironment_1_1* Instance() { + static WifiHostapdHidlEnvironment_1_1* instance = + new WifiHostapdHidlEnvironment_1_1; + return instance; + } + + virtual void registerTestServices() override { + registerTestService<::android::hardware::wifi::V1_0::IWifi>(); + registerTestService<android::hardware::wifi::hostapd::V1_0::IHostapd>(); + registerTestService<android::hardware::wifi::hostapd::V1_1::IHostapd>(); + } + + private: + WifiHostapdHidlEnvironment_1_1() {} +}; + +WifiHostapdHidlEnvironment* gEnv = WifiHostapdHidlEnvironment_1_1::Instance(); + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp new file mode 100644 index 0000000000..439a62403d --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp @@ -0,0 +1,278 @@ +/* + * 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 <cutils/properties.h> + +#include <VtsHalHidlTargetTestBase.h> + +#include <android/hardware/wifi/hostapd/1.1/IHostapd.h> + +#include "hostapd_hidl_call_util.h" +#include "hostapd_hidl_test_utils.h" +#include "hostapd_hidl_test_utils_1_1.h" + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::wifi::hostapd::V1_0::HostapdStatus; +using ::android::hardware::wifi::hostapd::V1_0::HostapdStatusCode; +using ::android::hardware::wifi::hostapd::V1_1::IHostapd; +using ::android::hardware::wifi::hostapd::V1_1::IHostapdCallback; + +namespace { +constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1', + '2', '3', '4', '5'}; +constexpr char kNwPassphrase[] = "test12345"; +constexpr int kIfaceChannel = 6; +constexpr int kIfaceInvalidChannel = 567; +} // namespace + +class HostapdHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + startHostapdAndWaitForHidlService(); + hostapd_ = getHostapd_1_1(); + ASSERT_NE(hostapd_.get(), nullptr); + } + + virtual void TearDown() override { stopHostapd(); } + + protected: + std::string getPrimaryWlanIfaceName() { + std::array<char, PROPERTY_VALUE_MAX> buffer; + property_get("wifi.interface", buffer.data(), "wlan0"); + return buffer.data(); + } + + IHostapd::IfaceParams getIfaceParamsWithAcs() { + ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams + iface_params; + IHostapd::IfaceParams iface_params_1_1; + + iface_params.ifaceName = getPrimaryWlanIfaceName(); + iface_params.hwModeParams.enable80211N = true; + iface_params.hwModeParams.enable80211AC = false; + iface_params.channelParams.enableAcs = true; + iface_params.channelParams.acsShouldExcludeDfs = true; + iface_params.channelParams.channel = 0; + iface_params.channelParams.band = IHostapd::Band::BAND_ANY; + iface_params_1_1.V1_0 = iface_params; + return iface_params_1_1; + } + + IHostapd::IfaceParams getIfaceParamsWithAcsAndChannelRange() { + IHostapd::IfaceParams iface_params_1_1 = getIfaceParamsWithAcs(); + IHostapd::ChannelParams channelParams; + IHostapd::AcsChannelRange acsChannelRange; + acsChannelRange.start = 1; + acsChannelRange.end = 11; + std::vector<IHostapd::AcsChannelRange> vec_acsChannelRange; + vec_acsChannelRange.push_back(acsChannelRange); + channelParams.acsChannelRanges = vec_acsChannelRange; + iface_params_1_1.channelParams = channelParams; + return iface_params_1_1; + } + + IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidChannelRange() { + IHostapd::IfaceParams iface_params_1_1 = + getIfaceParamsWithAcsAndChannelRange(); + iface_params_1_1.channelParams.acsChannelRanges[0].start = 222; + iface_params_1_1.channelParams.acsChannelRanges[0].end = 999; + return iface_params_1_1; + } + + IHostapd::IfaceParams getIfaceParamsWithoutAcs() { + ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams + iface_params; + IHostapd::IfaceParams iface_params_1_1; + + iface_params.ifaceName = getPrimaryWlanIfaceName(); + iface_params.hwModeParams.enable80211N = true; + iface_params.hwModeParams.enable80211AC = false; + iface_params.channelParams.enableAcs = false; + iface_params.channelParams.acsShouldExcludeDfs = false; + iface_params.channelParams.channel = kIfaceChannel; + iface_params.channelParams.band = IHostapd::Band::BAND_2_4_GHZ; + iface_params_1_1.V1_0 = iface_params; + return iface_params_1_1; + } + + IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() { + IHostapd::IfaceParams iface_params_1_1 = getIfaceParamsWithoutAcs(); + iface_params_1_1.V1_0.channelParams.channel = kIfaceInvalidChannel; + return iface_params_1_1; + } + + IHostapd::NetworkParams getPskNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::WPA2; + nw_params.pskPassphrase = kNwPassphrase; + return nw_params; + } + + IHostapd::NetworkParams getInvalidPskNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::WPA2; + return nw_params; + } + + IHostapd::NetworkParams getOpenNwParams() { + IHostapd::NetworkParams nw_params; + nw_params.ssid = + std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid)); + nw_params.isHidden = false; + nw_params.encryptionType = IHostapd::EncryptionType::NONE; + return nw_params; + } + + // IHostapd object used for all tests in this fixture. + sp<IHostapd> hostapd_; +}; + +class IfaceCallback : public IHostapdCallback { + Return<void> onFailure( + const hidl_string& /* Name of the interface */) override { + return Void(); + } +}; + +/* + * RegisterCallback + */ +TEST_F(HostapdHidlTest, registerCallback) { + hostapd_->registerCallback( + new IfaceCallback(), [](const HostapdStatus& status) { + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + }); +} + +/** + * Adds an access point with PSK network config & ACS enabled. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with PSK network config, ACS enabled & channel Range. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcsAndChannelRange(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid channel range. + * Access point creation should fail. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcsAndInvalidChannelRange(), + getPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with Open network config & ACS enabled. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcs(), getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with PSK network config & ACS disabled. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with Open network config & ACS disabled. + * Access point creation should pass. + */ +TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithoutAcs(), getOpenNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds & then removes an access point with PSK network config & ACS enabled. + * Access point creation & removal should pass. + */ +TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds & then removes an access point with PSK network config & ACS disabled. + * Access point creation & removal should pass. + */ +TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) { + auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithoutAcs(), getPskNwParams()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); + status = + HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName()); + EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid channel. + * Access point creation should fail. + */ +TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_1, + getIfaceParamsWithInvalidChannel(), getPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} + +/** + * Adds an access point with invalid PSK network config. + * Access point creation should fail. + */ +TEST_F(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) { + auto status = + HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(), + getInvalidPskNwParams()); + EXPECT_NE(HostapdStatusCode::SUCCESS, status.code); +} diff --git a/audio/core/4.0/default/include/core/4.0/default/Util.h b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp index ce31e6f7f2..8bb72a19f1 100644 --- a/audio/core/4.0/default/include/core/4.0/default/Util.h +++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * 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. @@ -14,13 +14,13 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_AUDIO_V4_0_UTIL_H -#define ANDROID_HARDWARE_AUDIO_V4_0_UTIL_H +#include <VtsHalHidlTargetTestBase.h> +#include <android-base/logging.h> -#include <android/hardware/audio/4.0/types.h> +#include "hostapd_hidl_test_utils.h" +#include "hostapd_hidl_test_utils_1_1.h" -#define AUDIO_HAL_VERSION V4_0 -#include <core/all-versions/default/Util.h> -#undef AUDIO_HAL_VERSION +using ::android::sp; +using ::android::hardware::wifi::hostapd::V1_1::IHostapd; -#endif // ANDROID_HARDWARE_AUDIO_V4_0_UTIL_H +sp<IHostapd> getHostapd_1_1() { return IHostapd::castFrom(getHostapd()); } diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h new file mode 100644 index 0000000000..c43ddfa207 --- /dev/null +++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test_utils_1_1.h @@ -0,0 +1,30 @@ +/* + * 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 HOSTAPD_HIDL_TEST_UTILS_1_1_H +#define HOSTAPD_HIDL_TEST_UTILS_1_1_H + +#include <android/hardware/wifi/hostapd/1.1/IHostapd.h> + +#include <VtsHalHidlTargetTestEnvBase.h> + +// Helper functions to obtain references to the various HIDL interface objects. +// Note: We only have a single instance of each of these objects currently. +// These helper functions should be modified to return vectors if we support +// multiple instances. +android::sp<android::hardware::wifi::hostapd::V1_1::IHostapd> getHostapd_1_1(); + +#endif /* HOSTAPD_HIDL_TEST_UTILS_1_1_H */ diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp index de53fa2e7e..bdccac1919 100644 --- a/wifi/supplicant/1.0/vts/functional/Android.bp +++ b/wifi/supplicant/1.0/vts/functional/Android.bp @@ -39,7 +39,6 @@ cc_test { srcs: [ "VtsHalWifiSupplicantV1_0TargetTest.cpp", "supplicant_hidl_test.cpp", - "supplicant_p2p_iface_hidl_test.cpp", "supplicant_sta_iface_hidl_test.cpp", "supplicant_sta_network_hidl_test.cpp", ], @@ -56,3 +55,23 @@ cc_test { ], test_suites: ["general-tests"], } + +cc_test { + name: "VtsHalWifiSupplicantP2pV1_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiSupplicantV1_0TargetTest.cpp", + "supplicant_p2p_iface_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_0TargetTestUtil", + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi.supplicant@1.1", + "android.hardware.wifi@1.0", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], +} diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp index adf2a85ab5..6ca0546cf6 100644 --- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp +++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp @@ -44,7 +44,10 @@ int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(gEnv); ::testing::InitGoogleTest(&argc, argv); gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; + int status = gEnv->initFromOptions(argc, argv); + if (status == 0) { + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + } return status; } diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp index c6ac03ce64..436b88b816 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp +++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp @@ -30,6 +30,8 @@ using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; using ::android::hardware::wifi::supplicant::V1_0::IfaceType; +extern WifiSupplicantHidlEnvironment* gEnv; + class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { @@ -72,10 +74,13 @@ TEST_F(SupplicantHidlTest, ListInterfaces) { std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) { return iface.type == IfaceType::STA; })); - EXPECT_NE(ifaces.end(), - std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) { - return iface.type == IfaceType::P2P; - })); + if (gEnv->isP2pOn) { + EXPECT_NE( + ifaces.end(), + std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) { + return iface.type == IfaceType::P2P; + })); + } } /* @@ -178,8 +183,10 @@ TEST_F(SupplicantHidlTest, SetConcurrencyPriority) { IfaceType::STA, [](const SupplicantStatus& status) { EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); }); - supplicant_->setConcurrencyPriority( - IfaceType::P2P, [](const SupplicantStatus& status) { - EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); - }); + if (gEnv->isP2pOn) { + supplicant_->setConcurrencyPriority( + IfaceType::P2P, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + } } diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp index bdedfba258..47c3056000 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp +++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp @@ -225,7 +225,9 @@ sp<ISupplicant> getSupplicant() { // For 1.1 supplicant, we need to add interfaces at initialization. if (is_1_1(supplicant)) { addSupplicantStaIface_1_1(supplicant); - addSupplicantP2pIface_1_1(supplicant); + if (gEnv->isP2pOn) { + addSupplicantP2pIface_1_1(supplicant); + } } return supplicant; } diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h index d4a768fb5b..21a1ae62d0 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h +++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h @@ -23,6 +23,8 @@ #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h> #include <android/hardware/wifi/supplicant/1.1/ISupplicant.h> +#include <getopt.h> + #include <VtsHalHidlTargetTestEnvBase.h> // Used to stop the android wifi framework before every test. @@ -50,11 +52,48 @@ bool turnOnExcessiveLogging(); class WifiSupplicantHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: + protected: virtual void HidlSetUp() override { stopSupplicant(); } virtual void HidlTearDown() override { startSupplicantAndWaitForHidlService(); } + + public: + // Whether P2P feature is supported on the device. + bool isP2pOn = true; + + void usage(char* me, char* arg) { + fprintf(stderr, + "unrecognized option: %s\n\n" + "usage: %s <gtest options> <test options>\n\n" + "test options are:\n\n" + "-P, --p2p_on: Whether P2P feature is supported\n", + arg, me); + } + + int initFromOptions(int argc, char** argv) { + static struct option options[] = {{"p2p_off", no_argument, 0, 'P'}, + {0, 0, 0, 0}}; + + int c; + while ((c = getopt_long(argc, argv, "P", options, NULL)) >= 0) { + switch (c) { + case 'P': + isP2pOn = false; + break; + default: + usage(argv[0], argv[optind]); + return 2; + } + } + + if (optind < argc) { + usage(argv[0], argv[optind]); + return 2; + } + + return 0; + } }; #endif /* SUPPLICANT_HIDL_TEST_UTILS_H */ diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp index 3d24fc3eee..9063a3ba4c 100644 --- a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp +++ b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp @@ -30,8 +30,11 @@ class WifiSupplicantHidlEnvironment_1_1 : public WifiSupplicantHidlEnvironment { return instance; } virtual void registerTestServices() override { + registerTestService<::android::hardware::wifi::V1_0::IWifi>(); registerTestService<::android::hardware::wifi::V1_1::IWifi>(); registerTestService< + ::android::hardware::wifi::supplicant::V1_0::ISupplicant>(); + registerTestService< ::android::hardware::wifi::supplicant::V1_1::ISupplicant>(); } @@ -46,7 +49,10 @@ int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(gEnv); ::testing::InitGoogleTest(&argc, argv); gEnv->init(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; + int status = gEnv->initFromOptions(argc, argv); + if (status == 0) { + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + } return status; } diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp index 7e773d611e..28f980cf85 100644 --- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp +++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp @@ -33,6 +33,8 @@ using ::android::hardware::wifi::supplicant::V1_0::IfaceType; using ::android::hardware::wifi::supplicant::V1_1::ISupplicant; using ::android::sp; +extern WifiSupplicantHidlEnvironment* gEnv; + class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { @@ -81,6 +83,7 @@ TEST_F(SupplicantHidlTest, AddStaInterface) { * AddP2pInterface */ TEST_F(SupplicantHidlTest, AddP2pInterface) { + if (!gEnv->isP2pOn) return; ISupplicant::IfaceInfo iface_info; iface_info.name = getP2pIfaceName(); iface_info.type = IfaceType::P2P; @@ -120,6 +123,7 @@ TEST_F(SupplicantHidlTest, RemoveStaInterface) { * RemoveP2pInterface */ TEST_F(SupplicantHidlTest, RemoveP2pInterface) { + if (!gEnv->isP2pOn) return; ISupplicant::IfaceInfo iface_info; iface_info.name = getP2pIfaceName(); iface_info.type = IfaceType::P2P; diff --git a/wifi/supplicant/1.2/Android.bp b/wifi/supplicant/1.2/Android.bp new file mode 100644 index 0000000000..18e1cca7e1 --- /dev/null +++ b/wifi/supplicant/1.2/Android.bp @@ -0,0 +1,31 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.wifi.supplicant@1.2", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "ISupplicant.hal", + "ISupplicantP2pIface.hal", + "ISupplicantStaIface.hal", + "ISupplicantStaIfaceCallback.hal", + "ISupplicantStaNetwork.hal", + "types.hal", + ], + interfaces: [ + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi.supplicant@1.1", + "android.hidl.base@1.0", + ], + types: [ + "DppAkm", + "DppNetRole", + "DppSuccessCode", + "DppProgressCode", + "DppFailureCode", + ], + gen_java: true, +} + diff --git a/audio/core/2.0/default/Device.cpp b/wifi/supplicant/1.2/ISupplicant.hal index b67203d50e..b0ec65db53 100644 --- a/audio/core/2.0/default/Device.cpp +++ b/wifi/supplicant/1.2/ISupplicant.hal @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright 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. @@ -14,15 +14,17 @@ * limitations under the License. */ -#define LOG_TAG "DeviceHAL" +package android.hardware.wifi.supplicant@1.2; -#include "core/2.0/default/Device.h" -#include <HidlUtils.h> -#include "core/2.0/default/Conversions.h" -#include "core/2.0/default/StreamIn.h" -#include "core/2.0/default/StreamOut.h" -#include "core/2.0/default/Util.h" +import @1.1::ISupplicant; -#define AUDIO_HAL_VERSION V2_0 -#include <core/all-versions/default/Device.impl.h> -#undef AUDIO_HAL_VERSION +/** + * Interface exposed by the supplicant HIDL service registered + * with the hardware service manager. + * This is the root level object for any the supplicant interactions. + * To use 1.2 features you must cast specific interfaces returned from the + * 1.1 HAL. For example V1_1::ISupplicant::addIface() adds V1_1::ISupplicantIface, + * which can be cast to V1_2::ISupplicantStaIface. + */ +interface ISupplicant extends @1.1::ISupplicant { +}; diff --git a/wifi/supplicant/1.2/ISupplicantP2pIface.hal b/wifi/supplicant/1.2/ISupplicantP2pIface.hal new file mode 100644 index 0000000000..d58f46bfb8 --- /dev/null +++ b/wifi/supplicant/1.2/ISupplicantP2pIface.hal @@ -0,0 +1,83 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.2; + +import @1.0::ISupplicantP2pIface; +import @1.0::MacAddress; +import @1.0::Ssid; +import @1.0::SupplicantStatus; + +/** + * Interface exposed by the supplicant for each P2P mode network + * interface (e.g p2p0) it controls. + * To use 1.2 features you must cast specific interfaces returned from the + * 1.2 HAL. For example V1_2::ISupplicant::addIface() adds V1_2::ISupplicantIface, + * which can be cast to V1_2::ISupplicantP2pIface. + */ +interface ISupplicantP2pIface extends @1.0::ISupplicantP2pIface { + /** + * Set up a P2P group owner or join a group as a group client + * with the specified configuration. + * + * If joinExistingGroup is false, this device sets up a P2P group owner manually (i.e., + * without group owner negotiation with a specific peer) with the specified SSID, + * passphrase, persistent mode, and frequency/band. + * + * If joinExistingGroup is true, this device acts as a group client and joins the group + * whose network name and group owner's MAC address matches the specified SSID + * and peer address without WPS process. If peerAddress is 00:00:00:00:00:00, the first found + * group whose network name matches the specified SSID is joined. + * + * @param ssid The SSID of this group. + * @param pskPassphrase The passphrase of this group. + * @param persistent Used to request a persistent group to be formed, + * only applied for the group owner. + * @param freq The required frequency or band for this group. + * only applied for the group owner. + * The following values are supported: + * 0: automatic channel selection, + * 2: for 2.4GHz channels + * 5: for 5GHz channels + * specific frequency, i.e., 2412, 5500, etc. + * If an invalid band or unsupported frequency are specified, it fails. + * @param peerAddress the group owner's MAC address, only applied for the group client. + * If the MAC is "00:00:00:00:00:00", the device must try to find a peer + * whose network name matches the specified SSID. + * @param joinExistingGroup if true, join a group as a group client; otherwise, + * create a group as a group owner. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_IFACE_INVALID| + */ + addGroup_1_2(Ssid ssid, string pskPassphrase, bool persistent, + uint32_t freq, MacAddress peerAddress, bool joinExistingGroup) + generates (SupplicantStatus status); + + /** + * Set MAC randomization enabled/disabled. + * + * @param enable true to enable, false to disable. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_IFACE_INVALID| + */ + setMacRandomization(bool enable) generates (SupplicantStatus status); +}; diff --git a/wifi/supplicant/1.2/ISupplicantStaIface.hal b/wifi/supplicant/1.2/ISupplicantStaIface.hal new file mode 100644 index 0000000000..9152a647a3 --- /dev/null +++ b/wifi/supplicant/1.2/ISupplicantStaIface.hal @@ -0,0 +1,140 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.2; + +import @1.0::SupplicantStatus; +import @1.1::ISupplicantStaIface; +import @1.2::ISupplicantStaIfaceCallback; +import @1.2::ISupplicantStaNetwork; + +/** + * Interface exposed by the supplicant for each station mode network + * interface (e.g wlan0) it controls. + */ +interface ISupplicantStaIface extends @1.1::ISupplicantStaIface { + /** + * Register for callbacks from this interface. + * + * These callbacks are invoked for events that are specific to this interface. + * Registration of multiple callback objects is supported. These objects must + * be automatically deleted when the corresponding client process is dead or + * if this interface is removed. + * + * @param callback An instance of the |ISupplicantStaIfaceCallback| HIDL + * interface object. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_IFACE_INVALID| + */ + registerCallback_1_2(ISupplicantStaIfaceCallback callback) + generates (SupplicantStatus status); + + /** + * Get Key management capabilities of the device + * + * @return status Status of the operation, and a bitmap of key management mask. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + getKeyMgmtCapabilities() + generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask); + + /** + * Add a DPP peer URI. URI is acquired externally, e.g. by scanning a QR code + * + * @param uri Peer's DPP URI. + * @return status Status of the operation, and an ID for the URI. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + addDppPeerUri(string uri) + generates (SupplicantStatus status, uint32_t id); + + /** + * Remove a DPP peer URI. + * + * @param id The ID of the URI, as returned by |addDppPeerUri|. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + removeDppUri(uint32_t id) + generates (SupplicantStatus status); + + /** + * Start DPP in Configurator-Initiator mode. + * + * @param peerBootstrapId Peer device's URI ID. + * @param ownBootstrapId Local device's URI ID (0 for none, optional). + * @param ssid Network SSID to send to peer (SAE/PSK mode). + * @param password Network password to send to peer (SAE/PSK mode). + * @param psk Network PSK to send to peer (PSK mode only). Either password or psk should be set. + * @param netRole Role to configure the peer, |DppNetRole.DPP_NET_ROLE_STA| or + * |DppNetRole.DPP_NET_ROLE_AP|. + * @param securityAkm Security AKM to use (See DppAkm). + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + startDppConfiguratorInitiator(uint32_t peerBootstrapId, + uint32_t ownBootstrapId, string ssid, string password, + string psk, DppNetRole netRole, DppAkm securityAkm) + generates (SupplicantStatus status); + + /** + * Start DPP in Enrollee-Initiator mode. + * + * @param peerBootstrapId Peer device's URI ID. + * @param ownBootstrapId Local device's URI ID (0 for none, optional). + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + startDppEnrolleeInitiator(uint32_t peerBootstrapId, + uint32_t ownBootstrapId) + generates (SupplicantStatus status); + + /** + * Stop DPP Initiator operation. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + stopDppInitiator() + generates (SupplicantStatus status); +}; diff --git a/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.hal new file mode 100644 index 0000000000..5d5cccfb4a --- /dev/null +++ b/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.hal @@ -0,0 +1,51 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.2; + +import @1.1::ISupplicantStaIfaceCallback; +import @1.0::Ssid; + +/** + * Callback Interface exposed by the supplicant service + * for each station mode interface (ISupplicantStaIface). + * + * Clients need to host an instance of this HIDL interface object and + * pass a reference of the object to the supplicant via the + * corresponding |ISupplicantStaIface.registerCallback_1_2| method. + */ +interface ISupplicantStaIfaceCallback extends @1.1::ISupplicantStaIfaceCallback { + /** + * Indicates DPP configuration received success event (Enrolee mode). + */ + oneway onDppSuccessConfigReceived(Ssid ssid, string password, uint8_t[32] psk, + DppAkm securityAkm); + + /** + * Indicates DPP configuration sent success event (Configurator mode). + */ + oneway onDppSuccess(DppSuccessCode code); + + /** + * Indicates a DPP progress event. + */ + oneway onDppProgress(DppProgressCode code); + + /** + * Indicates a DPP failure event. + */ + oneway onDppFailure(DppFailureCode code); +}; diff --git a/wifi/supplicant/1.2/ISupplicantStaNetwork.hal b/wifi/supplicant/1.2/ISupplicantStaNetwork.hal new file mode 100644 index 0000000000..7c3da6f4f9 --- /dev/null +++ b/wifi/supplicant/1.2/ISupplicantStaNetwork.hal @@ -0,0 +1,268 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.2; + +import @1.0::ISupplicantStaNetworkCallback; +import @1.0::ISupplicantStaNetwork; +import @1.0::SupplicantStatus; +import @1.1::ISupplicantStaNetwork; + +/** + * Interface exposed by the supplicant for each station mode network + * configuration it controls. + */ +interface ISupplicantStaNetwork extends @1.1::ISupplicantStaNetwork { + /** Possble mask of values for KeyMgmt param. */ + enum KeyMgmtMask : @1.0::ISupplicantStaNetwork.KeyMgmtMask { + /** WPA using EAP authentication with stronger SHA256-based algorithms */ + WPA_EAP_SHA256 = 1 << 7, + + /** WPA pre-shared key with stronger SHA256-based algorithms */ + WPA_PSK_SHA256 = 1 << 8, + + /** WPA3-Personal SAE Key management */ + SAE = 1 << 10, + + /** WPA3-Enterprise Suite-B Key management */ + SUITE_B_192 = 1 << 17, + + /** Enhacned Open (OWE) Key management */ + OWE = 1 << 22, + + /** Easy Connect (DPP) Key management */ + DPP = 1 << 23, + }; + + /** Possble mask of values for PairwiseCipher param. */ + enum PairwiseCipherMask : @1.0::ISupplicantStaNetwork.PairwiseCipherMask { + /** GCMP-256 Pairwise Cipher */ + GCMP_256 = 1 << 8, + }; + + /** Possble mask of values for GroupCipher param. */ + enum GroupCipherMask : @1.0::ISupplicantStaNetwork.GroupCipherMask { + /** GCMP-256 Group Cipher */ + GCMP_256 = 1 << 8, + }; + + /** Possble mask of values for GroupMgmtCipher param. */ + enum GroupMgmtCipherMask : uint32_t { + /** BIP_GMAC-128 Group Management Cipher */ + BIP_GMAC_128 = 1 << 11, + + /** BIP_GMAC-256 Group Management Cipher */ + BIP_GMAC_256 = 1 << 12, + + /** BIP_CMAC-256 Group Management Cipher */ + BIP_CMAC_256 = 1 << 13, + }; + + /** + * Set key management mask for the network. + * + * @param keyMgmtMask value to set. + * Combination of |KeyMgmtMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setKeyMgmt_1_2(bitfield<KeyMgmtMask> keyMgmtMask) generates (SupplicantStatus status); + + /** + * Get the key mgmt mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + * @return keyMgmtMask Combination of |KeyMgmtMask| values. + */ + getKeyMgmt_1_2() + generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask); + + /** + * Set pairwise cipher mask for the network. + * + * @param pairwiseCipherMask value to set. + * Combination of |PairwiseCipherMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setPairwiseCipher_1_2(bitfield<PairwiseCipherMask> pairwiseCipherMask) + generates (SupplicantStatus status); + + /** + * Get the pairwise cipher mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values. + */ + getPairwiseCipher_1_2() + generates (SupplicantStatus status, + bitfield<PairwiseCipherMask> pairwiseCipherMask); + + /** + * Set group cipher mask for the network. + * + * @param groupCipherMask value to set. + * Combination of |GroupCipherMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setGroupCipher_1_2(bitfield<GroupCipherMask> groupCipherMask) + generates (SupplicantStatus status); + + /** + * Get the group cipher mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + * @return groupCipherMask Combination of |GroupCipherMask| values. + */ + getGroupCipher_1_2() + generates (SupplicantStatus status, + bitfield<GroupCipherMask> groupCipherMask); + + /** + * Set group management cipher mask for the network. + * + * @param groupMgmtCipherMask value to set. + * Combination of |GroupMgmtCipherMask| values. + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setGroupMgmtCipher(bitfield<GroupMgmtCipherMask> groupMgmtCipherMask) + generates (SupplicantStatus status); + + /** + * Get the group management cipher mask set for the network. + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + * @return groupMgmtCipherMask Combination of |GroupMgmtCipherMask| values. + */ + getGroupMgmtCipher() + generates (SupplicantStatus status, + bitfield<GroupMgmtCipherMask> groupMgmtCipherMask); + + /** + * Enable TLS Suite-B in EAP Phase1 + * + * @param enable Set to true to enable TLS Suite-B in EAP phase1 + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + enableTlsSuiteBEapPhase1Param(bool enable) + generates (SupplicantStatus status); + + /** + * Set EAP OpenSSL Suite-B-192 ciphers for WPA3-Enterprise + * Supported option: + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + enableSuiteBEapOpenSslCiphers() + generates (SupplicantStatus status); + + /** + * Get SAE password for WPA3-Personal + * + * @return status Status of the operation, and a string. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + getSaePassword() + generates (SupplicantStatus status, string saePassword); + + /** + * Get SAE password ID for WPA3-Personal + * + * @return status Status of the operation, and a string. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + getSaePasswordId() + generates (SupplicantStatus status, string saePasswordId); + + /** + * Set SAE password for WPA3-Personal + * + * @param saePassword string with the above option + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setSaePassword(string saePassword) + generates (SupplicantStatus status); + + /** + * Set SAE password ID for WPA3-Personal + * + * @param sae_password_id string with the above option + * + * @return status Status of the operation. + * Possible status codes: + * |SupplicantStatusCode.SUCCESS|, + * |SupplicantStatusCode.FAILURE_ARGS_INVALID|, + * |SupplicantStatusCode.FAILURE_UNKNOWN|, + * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| + */ + setSaePasswordId(string saePasswordId) + generates (SupplicantStatus status); +}; diff --git a/wifi/supplicant/1.2/types.hal b/wifi/supplicant/1.2/types.hal new file mode 100644 index 0000000000..eaf2546b25 --- /dev/null +++ b/wifi/supplicant/1.2/types.hal @@ -0,0 +1,64 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi.supplicant@1.2; + +/** + * DppAkm: The various AKMs that can be provisioned using DPP. + */ +enum DppAkm : uint32_t { + PSK, + PSK_SAE, + SAE, + DPP, +}; + +/** + * DppNetRole: The network role that the configurator offers the enrollee. + */ +enum DppNetRole: uint32_t { + STA, + AP, +}; + +/** + * DppSuccessCode: Success codes for DPP (Easy Connect) + */ +enum DppSuccessCode : uint32_t { + CONFIGURATION_SENT, +}; + +/** + * DppProgressCode: Progress codes for DPP (Easy Connect) + */ +enum DppProgressCode : uint32_t { + AUTHENTICATION_SUCCESS, + RESPONSE_PENDING, +}; + +/** + * DppFailureCode: Error codes for DPP (Easy Connect) + */ +enum DppFailureCode : uint32_t { + INVALID_URI, + AUTHENTICATION, + NOT_COMPATIBLE, + CONFIGURATION, + BUSY, + TIMEOUT, + FAILURE, + NOT_SUPPORTED, +}; diff --git a/wifi/supplicant/1.2/vts/OWNERS b/wifi/supplicant/1.2/vts/OWNERS new file mode 100644 index 0000000000..8bfb14882c --- /dev/null +++ b/wifi/supplicant/1.2/vts/OWNERS @@ -0,0 +1,2 @@ +rpius@google.com +etancohen@google.com diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp new file mode 100644 index 0000000000..1b970e1ce6 --- /dev/null +++ b/wifi/supplicant/1.2/vts/functional/Android.bp @@ -0,0 +1,88 @@ +// +// 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. +// + +cc_library_static { + name: "VtsHalWifiSupplicantV1_2TargetTestUtil", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["supplicant_hidl_test_utils_1_2.cpp"], + export_include_dirs: [ + "." + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_1TargetTestUtil", + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi.supplicant@1.1", + "android.hardware.wifi.supplicant@1.2", + "android.hardware.wifi@1.0", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], +} + +cc_test { + name: "VtsHalWifiSupplicantV1_2TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiSupplicantV1_2TargetTest.cpp", + "supplicant_sta_iface_hidl_test.cpp", + "supplicant_sta_network_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_1TargetTestUtil", + "VtsHalWifiSupplicantV1_2TargetTestUtil", + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi.supplicant@1.1", + "android.hardware.wifi.supplicant@1.2", + "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], + test_suites: ["general-tests"], +} + +cc_test { + name: "VtsHalWifiSupplicantP2pV1_2TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalWifiSupplicantV1_2TargetTest.cpp", + "supplicant_p2p_iface_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_0TargetTestUtil", + "VtsHalWifiSupplicantV1_1TargetTestUtil", + "VtsHalWifiSupplicantV1_2TargetTestUtil", + "android.hardware.wifi.supplicant@1.0", + "android.hardware.wifi.supplicant@1.1", + "android.hardware.wifi.supplicant@1.2", + "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "libcrypto", + "libgmock", + "libwifi-system", + "libwifi-system-iface", + ], +} + diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp new file mode 100644 index 0000000000..267fa67364 --- /dev/null +++ b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp @@ -0,0 +1,60 @@ +/* + * 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/hardware/wifi/1.1/IWifi.h> +#include <android/hardware/wifi/supplicant/1.2/ISupplicant.h> + +#include "supplicant_hidl_test_utils.h" +#include "wifi_hidl_test_utils.h" + +class WifiSupplicantHidlEnvironment_1_2 : public WifiSupplicantHidlEnvironment { + public: + // get the test environment singleton + static WifiSupplicantHidlEnvironment_1_2* Instance() { + static WifiSupplicantHidlEnvironment_1_2* instance = + new WifiSupplicantHidlEnvironment_1_2; + return instance; + } + virtual void registerTestServices() override { + registerTestService<::android::hardware::wifi::V1_0::IWifi>(); + registerTestService<::android::hardware::wifi::V1_1::IWifi>(); + registerTestService< + ::android::hardware::wifi::supplicant::V1_0::ISupplicant>(); + registerTestService< + ::android::hardware::wifi::supplicant::V1_1::ISupplicant>(); + registerTestService< + ::android::hardware::wifi::supplicant::V1_2::ISupplicant>(); + } + + private: + WifiSupplicantHidlEnvironment_1_2() {} +}; + +WifiSupplicantHidlEnvironment* gEnv = + WifiSupplicantHidlEnvironment_1_2::Instance(); + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + gEnv->init(&argc, argv); + int status = gEnv->initFromOptions(argc, argv); + if (status == 0) { + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + } + return status; +} diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp new file mode 100644 index 0000000000..f270bff673 --- /dev/null +++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp @@ -0,0 +1,43 @@ +/* + * 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 <VtsHalHidlTargetTestBase.h> +#include <android-base/logging.h> + +#include "supplicant_hidl_test_utils.h" +#include "supplicant_hidl_test_utils_1_2.h" + +using ::android::sp; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicant; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork; + +sp<ISupplicant> getSupplicant_1_2() { + return ISupplicant::castFrom(getSupplicant()); +} + +sp<ISupplicantStaIface> getSupplicantStaIface_1_2() { + return ISupplicantStaIface::castFrom(getSupplicantStaIface()); +} + +sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_2() { + return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork()); +} + +sp<ISupplicantP2pIface> getSupplicantP2pIface_1_2() { + return ISupplicantP2pIface::castFrom(getSupplicantP2pIface()); +} diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h new file mode 100644 index 0000000000..8a7ccc5dac --- /dev/null +++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h @@ -0,0 +1,37 @@ +/* + * 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 SUPPLICANT_HIDL_TEST_UTILS_1_2_H +#define SUPPLICANT_HIDL_TEST_UTILS_1_2_H + +#include <android/hardware/wifi/supplicant/1.2/ISupplicant.h> +#include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h> +#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h> +#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h> + +android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant> +getSupplicant_1_2(); + +android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface> +getSupplicantStaIface_1_2(); + +android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork> +createSupplicantStaNetwork_1_2(); + +android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface> +getSupplicantP2pIface_1_2(); + +#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_2_H */ diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp new file mode 100644 index 0000000000..9249045483 --- /dev/null +++ b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp @@ -0,0 +1,151 @@ +/* + * 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 <VtsHalHidlTargetTestBase.h> + +#include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h> + +#include "supplicant_hidl_test_utils.h" +#include "supplicant_hidl_test_utils_1_2.h" + +using ::android::sp; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface; + +namespace { +constexpr uint8_t kTestSsid[] = {'D', 'I', 'R', 'E', 'C', 'T', '-', 'x', + 'y', '-', 'H', 'E', 'L', 'L', 'O'}; +constexpr char kTestPassphrase[] = "P2pWorld1234"; +constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0}; +} // namespace + +class SupplicantP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + startSupplicantAndWaitForHidlService(); + EXPECT_TRUE(turnOnExcessiveLogging()); + p2p_iface_ = getSupplicantP2pIface_1_2(); + ASSERT_NE(p2p_iface_.get(), nullptr); + } + + virtual void TearDown() override { stopSupplicant(); } + + protected: + // ISupplicantP2pIface object used for all tests in this fixture. + sp<ISupplicantP2pIface> p2p_iface_; +}; + +/* + * Verify that AddGroup_1_2 could create a group successfully. + */ +TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_Success) { + std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid)); + std::string passphrase = kTestPassphrase; + int freq = 5; + std::array<uint8_t, 6> zero_mac_addr; + memcpy(zero_mac_addr.data(), kTestZeroMacAddr, zero_mac_addr.size()); + bool persistent = false; + int is_join = false; + + p2p_iface_->addGroup_1_2(ssid, passphrase, persistent, freq, zero_mac_addr, + is_join, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, + status.code); + }); +} + +/* + * Verify that AddGroup_1_2 fails due to invalid SSID. + */ +TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidSsid) { + std::vector<uint8_t> ssid; + std::string passphrase = kTestPassphrase; + int freq = 5; + std::array<uint8_t, 6> zero_mac_addr; + memcpy(zero_mac_addr.data(), kTestZeroMacAddr, zero_mac_addr.size()); + bool persistent = false; + int is_join = false; + + p2p_iface_->addGroup_1_2( + ssid, passphrase, persistent, freq, zero_mac_addr, is_join, + [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::FAILURE_ARGS_INVALID, status.code); + }); +} + +/* + * Verify that AddGroup_1_2 fails due to invalid passphrase. + */ +TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidPassphrase) { + std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid)); + std::string passphrase = "1234"; + int freq = 5; + std::array<uint8_t, 6> zero_mac_addr; + memcpy(zero_mac_addr.data(), kTestZeroMacAddr, zero_mac_addr.size()); + bool persistent = false; + int is_join = false; + + p2p_iface_->addGroup_1_2( + ssid, passphrase, persistent, freq, zero_mac_addr, is_join, + [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::FAILURE_ARGS_INVALID, status.code); + }); +} + +/* + * Verify that AddGroup_1_2 fails due to invalid frequency. + */ +TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidFrequency) { + std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid)); + std::string passphrase = kTestPassphrase; + int freq = 9999; + std::array<uint8_t, 6> zero_mac_addr; + memcpy(zero_mac_addr.data(), kTestZeroMacAddr, zero_mac_addr.size()); + bool persistent = false; + int is_join = false; + + p2p_iface_->addGroup_1_2( + ssid, passphrase, persistent, freq, zero_mac_addr, is_join, + [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code); + }); +} + +/* + * Verify that setMacRandomization successes. + */ +TEST_F(SupplicantP2pIfaceHidlTest, EnableMacRandomization) { + p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // enable twice + p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + p2p_iface_->setMacRandomization(false, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // disable twice + p2p_iface_->setMacRandomization(false, [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp new file mode 100644 index 0000000000..4425281b75 --- /dev/null +++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp @@ -0,0 +1,418 @@ +/* + * 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 <VtsHalHidlTargetTestBase.h> +#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h> +#include <android/hardware/wifi/supplicant/1.0/types.h> +#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.h> +#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h> +#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h> +#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h> +#include <android/hardware/wifi/supplicant/1.2/types.h> +#include <hidl/HidlSupport.h> +#include <hidl/Status.h> + +#include "supplicant_hidl_test_utils.h" +#include "supplicant_hidl_test_utils_1_2.h" + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_2::DppAkm; +using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode; +using ::android::hardware::wifi::supplicant::V1_2::DppNetRole; +using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode; +using ::android::hardware::wifi::supplicant::V1_2::DppSuccessCode; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIfaceCallback; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork; + +#define TIMEOUT_PERIOD 60 +class IfaceDppCallback; + +class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + startSupplicantAndWaitForHidlService(); + EXPECT_TRUE(turnOnExcessiveLogging()); + sta_iface_ = getSupplicantStaIface_1_2(); + ASSERT_NE(sta_iface_.get(), nullptr); + count_ = 0; + } + + virtual void TearDown() override { stopSupplicant(); } + + enum DppCallbackType { + ANY_CALLBACK = -2, + INVALID = -1, + + EVENT_SUCCESS = 0, + EVENT_SUCCESS_CONFIG_RECEIVED, + EVENT_PROGRESS, + EVENT_FAILURE, + }; + + DppCallbackType dppCallbackType; + uint32_t code; + + /* Used as a mechanism to inform the test about data/event callback */ + inline void notify() { + std::unique_lock<std::mutex> lock(mtx_); + count_++; + cv_.notify_one(); + } + + /* Test code calls this function to wait for data/event callback */ + inline std::cv_status wait(DppCallbackType waitForCallbackType) { + std::unique_lock<std::mutex> lock(mtx_); + EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a + // non-void-returning method + auto now = std::chrono::system_clock::now(); + std::cv_status status = + cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); + return status; + } + + private: + // synchronization objects + std::mutex mtx_; + std::condition_variable cv_; + int count_; + + protected: + // ISupplicantStaIface object used for all tests in this fixture. + sp<ISupplicantStaIface> sta_iface_; + bool isDppSupported() { + uint32_t keyMgmtMask = 0; + + // We need to first get the key management capabilities from the device. + // If DPP is not supported, we just pass the test. + sta_iface_->getKeyMgmtCapabilities( + [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + + keyMgmtMask = keyMgmtMaskInternal; + }); + + if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) { + // DPP not supported + return false; + } + + return true; + } +}; + +class IfaceCallback : public ISupplicantStaIfaceCallback { + Return<void> onNetworkAdded(uint32_t /* id */) override { return Void(); } + Return<void> onNetworkRemoved(uint32_t /* id */) override { return Void(); } + Return<void> onStateChanged( + ISupplicantStaIfaceCallback::State /* newState */, + const hidl_array<uint8_t, 6>& /*bssid */, uint32_t /* id */, + const hidl_vec<uint8_t>& /* ssid */) override { + return Void(); + } + Return<void> onAnqpQueryDone( + const hidl_array<uint8_t, 6>& /* bssid */, + const ISupplicantStaIfaceCallback::AnqpData& /* data */, + const ISupplicantStaIfaceCallback::Hs20AnqpData& /* hs20Data */) + override { + return Void(); + } + virtual Return<void> onHs20IconQueryDone( + const hidl_array<uint8_t, 6>& /* bssid */, + const hidl_string& /* fileName */, + const hidl_vec<uint8_t>& /* data */) override { + return Void(); + } + virtual Return<void> onHs20SubscriptionRemediation( + const hidl_array<uint8_t, 6>& /* bssid */, + ISupplicantStaIfaceCallback::OsuMethod /* osuMethod */, + const hidl_string& /* url*/) override { + return Void(); + } + Return<void> onHs20DeauthImminentNotice( + const hidl_array<uint8_t, 6>& /* bssid */, uint32_t /* reasonCode */, + uint32_t /* reAuthDelayInSec */, + const hidl_string& /* url */) override { + return Void(); + } + Return<void> onDisconnected(const hidl_array<uint8_t, 6>& /* bssid */, + bool /* locallyGenerated */, + ISupplicantStaIfaceCallback::ReasonCode + /* reasonCode */) override { + return Void(); + } + Return<void> onAssociationRejected( + const hidl_array<uint8_t, 6>& /* bssid */, + ISupplicantStaIfaceCallback::StatusCode /* statusCode */, + bool /*timedOut */) override { + return Void(); + } + Return<void> onAuthenticationTimeout( + const hidl_array<uint8_t, 6>& /* bssid */) override { + return Void(); + } + Return<void> onBssidChanged( + ISupplicantStaIfaceCallback::BssidChangeReason /* reason */, + const hidl_array<uint8_t, 6>& /* bssid */) override { + return Void(); + } + Return<void> onEapFailure() override { return Void(); } + Return<void> onEapFailure_1_1( + ISupplicantStaIfaceCallback::EapErrorCode /* eapErrorCode */) override { + return Void(); + } + Return<void> onWpsEventSuccess() override { return Void(); } + Return<void> onWpsEventFail( + const hidl_array<uint8_t, 6>& /* bssid */, + ISupplicantStaIfaceCallback::WpsConfigError /* configError */, + ISupplicantStaIfaceCallback::WpsErrorIndication /* errorInd */) + override { + return Void(); + } + Return<void> onWpsEventPbcOverlap() override { return Void(); } + Return<void> onExtRadioWorkStart(uint32_t /* id */) override { + return Void(); + } + Return<void> onExtRadioWorkTimeout(uint32_t /* id*/) override { + return Void(); + } + Return<void> onDppSuccessConfigReceived( + const hidl_vec<uint8_t>& /* ssid */, const hidl_string& /* password */, + const hidl_array<uint8_t, 32>& /* psk */, + DppAkm /* securityAkm */) override { + return Void(); + } + Return<void> onDppSuccess(DppSuccessCode /* code */) override { + return Void(); + } + Return<void> onDppProgress(DppProgressCode /* code */) override { + return Void(); + } + Return<void> onDppFailure(DppFailureCode /* code */) override { + return Void(); + } +}; + +class IfaceDppCallback : public IfaceCallback { + SupplicantStaIfaceHidlTest& parent_; + + Return<void> onDppSuccessConfigReceived( + const hidl_vec<uint8_t>& /* ssid */, const hidl_string& /* password */, + const hidl_array<uint8_t, 32>& /* psk */, + DppAkm /* securityAkm */) override { + parent_.code = 0; + parent_.dppCallbackType = SupplicantStaIfaceHidlTest::DppCallbackType:: + EVENT_SUCCESS_CONFIG_RECEIVED; + parent_.notify(); + return Void(); + } + Return<void> onDppSuccess(DppSuccessCode code) override { + parent_.code = (uint32_t)code; + parent_.dppCallbackType = + SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_SUCCESS; + parent_.notify(); + return Void(); + } + Return<void> onDppProgress(DppProgressCode code) override { + parent_.code = (uint32_t)code; + parent_.dppCallbackType = + SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_PROGRESS; + parent_.notify(); + return Void(); + } + Return<void> onDppFailure(DppFailureCode code) override { + parent_.code = (uint32_t)code; + parent_.dppCallbackType = + SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE; + parent_.notify(); + return Void(); + } + + public: + IfaceDppCallback(SupplicantStaIfaceHidlTest& parent) : parent_(parent){}; +}; + +/* + * RegisterCallback_1_2 + */ +TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) { + sta_iface_->registerCallback_1_2( + new IfaceCallback(), [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} + +/* + * GetKeyMgmtCapabilities + */ +TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) { + sta_iface_->getKeyMgmtCapabilities( + [&](const SupplicantStatus& status, uint32_t keyMgmtMask) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + + // Even though capabilities vary, these two are always set in HAL + // v1.2 + EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE); + EXPECT_TRUE(keyMgmtMask & + ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X); + }); +} + +/* + * AddDppPeerUriAndRomveUri + */ +TEST_F(SupplicantStaIfaceHidlTest, AddDppPeerUriAndRomveUri) { + // We need to first get the key management capabilities from the device. + // If DPP is not supported, we just pass the test. + if (!isDppSupported()) { + // DPP not supported + return; + } + + hidl_string uri = + "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj" + "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;"; + uint32_t peer_id = 0; + + // Add a peer URI + sta_iface_->addDppPeerUri( + uri, [&](const SupplicantStatus& status, uint32_t id) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_NE(0, id); + EXPECT_NE(-1, id); + + peer_id = id; + }); + + // ...and then remove it. + sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} + +/* + * StartDppEnrolleeInitiator + */ +TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) { + // We need to first get the key management capabilities from the device. + // If DPP is not supported, we just pass the test. + if (!isDppSupported()) { + // DPP not supported + return; + } + + hidl_string uri = + "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj" + "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;"; + uint32_t peer_id = 0; + + // Register callbacks + sta_iface_->registerCallback_1_2( + new IfaceDppCallback(*this), [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // Add a peer URI + sta_iface_->addDppPeerUri( + uri, [&](const SupplicantStatus& status, uint32_t id) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_NE(0, id); + EXPECT_NE(-1, id); + + peer_id = id; + }); + + // Start DPP as Enrollee-Initiator. Since this operation requires two + // devices, we start the operation and expect a timeout. + sta_iface_->startDppEnrolleeInitiator( + peer_id, 0, [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // Wait for the timeout callback + ASSERT_EQ(std::cv_status::no_timeout, + wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE)); + ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE, + dppCallbackType); + + // ...and then remove the peer URI. + sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} + +/* + * StartDppConfiguratorInitiator + */ +TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) { + // We need to first get the key management capabilities from the device. + // If DPP is not supported, we just pass the test. + if (!isDppSupported()) { + // DPP not supported + return; + } + + hidl_string uri = + "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj" + "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;"; + uint32_t peer_id = 0; + + // Register callbacks + sta_iface_->registerCallback_1_2( + new IfaceDppCallback(*this), [](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // Add a peer URI + sta_iface_->addDppPeerUri( + uri, [&](const SupplicantStatus& status, uint32_t id) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_NE(0, id); + EXPECT_NE(-1, id); + + peer_id = id; + }); + + std::string ssid = + "6D795F746573745F73736964"; // 'my_test_ssid' encoded in hex + std::string password = "746F70736563726574"; // 'topsecret' encoded in hex + + // Start DPP as Configurator-Initiator. Since this operation requires two + // devices, we start the operation and expect a timeout. + sta_iface_->startDppConfiguratorInitiator( + peer_id, 0, ssid, password, NULL, DppNetRole::STA, DppAkm::PSK, + [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + // Wait for the timeout callback + ASSERT_EQ(std::cv_status::no_timeout, + wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE)); + ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE, + dppCallbackType); + + // ...and then remove the peer URI. + sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp new file mode 100644 index 0000000000..ed421d73d7 --- /dev/null +++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp @@ -0,0 +1,192 @@ +/* + * 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 <VtsHalHidlTargetTestBase.h> +#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h> + +#include "supplicant_hidl_test_utils.h" +#include "supplicant_hidl_test_utils_1_2.h" + +using ::android::sp; +using ::android::hardware::hidl_vec; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus; +using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork; +// namespace { +// constexpr uint8_t kTestIdentity[] = {0x45, 0x67, 0x98, 0x67, 0x56}; +// constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26}; +//} // namespace + +class SupplicantStaNetworkHidlTest + : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + startSupplicantAndWaitForHidlService(); + EXPECT_TRUE(turnOnExcessiveLogging()); + sta_network_ = createSupplicantStaNetwork_1_2(); + ASSERT_NE(sta_network_.get(), nullptr); + } + + virtual void TearDown() override { stopSupplicant(); } + + protected: + // ISupplicantStaNetwork object used for all tests in this fixture. + sp<ISupplicantStaNetwork> sta_network_; +}; + +/* + * SetGetSaePassword + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePassword) { + std::string password = "topsecret"; + + sta_network_->setSaePassword(password, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->getSaePassword( + [&password](const SupplicantStatus &status, std::string passwordOut) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(passwordOut.compare(password), 0); + }); +} + +/* + * SetGetSaePasswordId + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePasswordId) { + std::string passwordId = "id1"; + + sta_network_->setSaePasswordId( + passwordId, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->getSaePasswordId([&passwordId](const SupplicantStatus &status, + std::string passwordIdOut) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(passwordIdOut.compare(passwordId), 0); + }); +} + +/* + * SetGetGroupMgmtCipher + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupMgmtCipher) { + uint32_t groupMgmtCipher = + (uint32_t)ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_256; + + sta_network_->setGroupMgmtCipher( + groupMgmtCipher, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->getGroupMgmtCipher( + [&groupMgmtCipher](const SupplicantStatus &status, + uint32_t groupMgmtCipherOut) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(groupMgmtCipherOut, groupMgmtCipher); + }); +} + +/* + * SetGetKeyMgmt_1_2 + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) { + uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::SAE; + + sta_network_->setKeyMgmt_1_2(keyMgmt, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->getKeyMgmt_1_2( + [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(keyMgmtOut, keyMgmt); + }); +} + +/* + * SetGetGroupCipher_1_2 + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) { + uint32_t groupCipher = + (uint32_t)ISupplicantStaNetwork::GroupCipherMask::GCMP_256; + + sta_network_->setGroupCipher_1_2( + groupCipher, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->getGroupCipher_1_2( + [&groupCipher](const SupplicantStatus &status, + uint32_t groupCipherOut) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(groupCipherOut, groupCipher); + }); +} + +/* + * SetGetPairwiseCipher_1_2 + */ +TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) { + uint32_t pairwiseCipher = + (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256; + + sta_network_->setPairwiseCipher_1_2( + pairwiseCipher, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->getPairwiseCipher_1_2( + [&pairwiseCipher](const SupplicantStatus &status, + uint32_t pairwiseCipherOut) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + EXPECT_EQ(pairwiseCipherOut, pairwiseCipher); + }); +} + +/* + * EnableSuiteBEapOpenSslCiphers + */ +TEST_F(SupplicantStaNetworkHidlTest, EnableSuiteBEapOpenSslCiphers) { + sta_network_->enableSuiteBEapOpenSslCiphers( + [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->enableSuiteBEapOpenSslCiphers( + [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} + +/* + * EnableTlsSuiteBEapPhase1Param + */ +TEST_F(SupplicantStaNetworkHidlTest, EnableTlsSuiteBEapPhase1Param) { + sta_network_->enableTlsSuiteBEapPhase1Param( + true, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); + + sta_network_->enableTlsSuiteBEapPhase1Param( + false, [](const SupplicantStatus &status) { + EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code); + }); +} |
