diff --git a/CleanSpec.mk b/CleanSpec.mk index 531e44ec8e..edde1cbd33 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -66,3 +66,17 @@ $(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) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@1.0*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.0*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.0*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.configstore@1.2-service.rc) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.configstore@1.2-service) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/seccomp_policy/configstore.policy) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/apex/com.android.media.swcodec/lib64/android.hardware.configstore@1.2.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/vndk-Q/android.hardware.configstore@1.2.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/android.hardware.configstore@1.2.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-Q/android.hardware.configstore@1.2.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.configstore@1.2.so) diff --git a/audio/5.0/IStreamIn.hal b/audio/5.0/IStreamIn.hal index b042960b17..e15b0347f5 100644 --- a/audio/5.0/IStreamIn.hal +++ b/audio/5.0/IStreamIn.hal @@ -169,6 +169,10 @@ interface IStreamIn extends IStream { /** * Specifies the logical microphone (for processing). * + * If the feature is not supported an error should be returned + * If multiple microphones are present, this should be treated as a preference + * for their combined direction. + * * Optional method * * @param Direction constant @@ -180,6 +184,10 @@ interface IStreamIn extends IStream { /** * Specifies the zoom factor for the selected microphone (for processing). * + * If the feature is not supported an error should be returned + * If multiple microphones are present, this should be treated as a preference + * for their combined field dimension. + * * Optional method * * @param the desired field dimension of microphone capture. Range is from -1 (wide angle), diff --git a/audio/5.0/config/api/current.txt b/audio/5.0/config/api/current.txt index b8dcb43fb0..c66578183a 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,10 @@ 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_APTX_TWSP; + 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 +131,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 +198,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 getEncodedFormats(); method public audio.policy.configuration.V5_0.Gains getGains(); method public java.util.List getProfile(); method public audio.policy.configuration.V5_0.Role getRole(); @@ -194,6 +206,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); 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..2e1a7223cb 100644 --- a/audio/5.0/config/audio_policy_configuration.xsd +++ b/audio/5.0/config/audio_policy_configuration.xsd @@ -42,7 +42,7 @@ - + @@ -277,6 +277,8 @@ + + @@ -364,6 +366,15 @@ + + + + + + + + + @@ -461,6 +472,8 @@ + @@ -595,7 +608,7 @@ - + @@ -603,7 +616,7 @@ - + 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 -| |-- 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 +|-- ... | -|-- core <== code relative to the core API -| |-- 2.0 <== 2.0 core API code (except .hal, see audio/2.0) -| | |-- default -| | `-- vts +|-- common <== code common to audio core and effect API +| |-- 2.0 <== HIDL API of V2 | |-- 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 +| `-- all_versions <== code common to all version of both core and effect API +| |-- default <== implementation shared code between core and effect impl +| |-- test <== utilities used by tests +| `-- util <== utilities used by both implementation and tests +| +|-- 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/5.0/types.hal b/audio/common/5.0/types.hal index 8f8a888b33..33a8d622c1 100644 --- a/audio/common/5.0/types.hal +++ b/audio/common/5.0/types.hal @@ -146,6 +146,7 @@ enum AudioSource : int32_t { */ ECHO_REFERENCE = 1997, FM_TUNER = 1998, + HOTWORD = 1999, }; typedef int32_t AudioSession; @@ -240,6 +241,7 @@ enum AudioFormat : uint32_t { APTX_ADAPTIVE = 0x27000000UL, LHDC = 0x28000000UL, LHDC_LL = 0x29000000UL, + APTX_TWSP = 0x2A000000UL, /** Deprecated */ MAIN_MASK = 0xFF000000UL, @@ -329,7 +331,13 @@ enum FixedChannelCount : int32_t { /** * A channel mask per se only defines the presence or absence of a channel, not - * the order. See AUDIO_INTERLEAVE_* for the platform convention of order. + * the order. + * + * The channel order convention is that channels are interleaved in order from + * least significant channel mask bit to most significant channel mask bit, + * with unused bits skipped. For example for stereo, LEFT would be first, + * followed by RIGHT. + * Any exceptions to this convention are noted at the appropriate API. * * AudioChannelMask is an opaque type and its internal layout should not be * assumed as it may change in the future. Instead, always use functions @@ -416,9 +424,9 @@ enum AudioChannelMask : uint32_t { OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY), - OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT | + OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT), - OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT | + OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY), OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | @@ -517,7 +525,23 @@ enum AudioChannelMask : uint32_t { INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1), INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1), INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1), - INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1) + INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1), + INDEX_MASK_9 = INDEX_HDR | ((1 << 9) - 1), + INDEX_MASK_10 = INDEX_HDR | ((1 << 10) - 1), + INDEX_MASK_11 = INDEX_HDR | ((1 << 11) - 1), + INDEX_MASK_12 = INDEX_HDR | ((1 << 12) - 1), + INDEX_MASK_13 = INDEX_HDR | ((1 << 13) - 1), + INDEX_MASK_14 = INDEX_HDR | ((1 << 14) - 1), + INDEX_MASK_15 = INDEX_HDR | ((1 << 15) - 1), + INDEX_MASK_16 = INDEX_HDR | ((1 << 16) - 1), + INDEX_MASK_17 = INDEX_HDR | ((1 << 17) - 1), + INDEX_MASK_18 = INDEX_HDR | ((1 << 18) - 1), + INDEX_MASK_19 = INDEX_HDR | ((1 << 19) - 1), + INDEX_MASK_20 = INDEX_HDR | ((1 << 20) - 1), + INDEX_MASK_21 = INDEX_HDR | ((1 << 21) - 1), + INDEX_MASK_22 = INDEX_HDR | ((1 << 22) - 1), + INDEX_MASK_23 = INDEX_HDR | ((1 << 23) - 1), + INDEX_MASK_24 = INDEX_HDR | ((1 << 24) - 1), }; /** 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 similarity index 88% rename from audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h rename to 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 #include -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(halConfig.channel_mask); + config->channelMask = EnumBitfield(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(halConfig.mode); - config->channelMask = mkEnumConverter(halConfig.channel_mask); + config->mode = EnumBitfield(halConfig.mode); + config->channelMask = EnumBitfield(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(halGain.mode); - gain->channelMask = mkEnumConverter(halGain.channel_mask); + gain->mode = EnumBitfield(halGain.mode); + gain->channelMask = EnumBitfield(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(halOffload.channel_mask); + offload->channelMask = EnumBitfield(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(halConfig.config_mask); + config->configMask = EnumBitfield(halConfig.config_mask); config->sampleRateHz = halConfig.sample_rate; - config->channelMask = mkEnumConverter(halConfig.channel_mask); + config->channelMask = EnumBitfield(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(config.ext.mix.useCase.source); - } else if (config.role == AudioPortRole::SINK) { halConfig->ext.mix.usecase.stream = static_cast(config.ext.mix.useCase.stream); + } else if (config.role == AudioPortRole::SINK) { + halConfig->ext.mix.usecase.source = + static_cast(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(halPort.channel_masks[i]); + port->channelMasks[i] = EnumBitfield(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 similarity index 79% rename from audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.h rename to 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 #include -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 similarity index 100% rename from audio/common/2.0/default/OWNERS rename to audio/common/all-versions/default/OWNERS diff --git a/audio/common/4.0/default/VersionUtils.h b/audio/common/all-versions/default/VersionUtils.h similarity index 57% rename from audio/common/4.0/default/VersionUtils.h rename to 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 +#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 AudioDeviceBitfield; -typedef hidl_bitfield AudioChannelBitfield; -typedef hidl_bitfield AudioOutputFlagBitfield; -typedef hidl_bitfield 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 AudioDeviceBitfield; +typedef hidl_bitfield AudioChannelBitfield; +typedef hidl_bitfield AudioOutputFlagBitfield; +typedef hidl_bitfield 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 5ef440f171..b57a1ae3d9 100644 --- a/audio/common/all-versions/default/service/Android.mk +++ b/audio/common/all-versions/default/service/Android.mk @@ -31,22 +31,28 @@ 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.bluetooth.audio@2.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 c45f885650..8a7b2ea09d 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -18,36 +18,52 @@ #include #include +#include #include #include +#include #include #include #include #include +#include #include +#include #include #include +#include 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(value) * 1024); + } configureRpcThreadpool(16, true /*callerWillJoin*/); - bool fail = registerPassthroughServiceImplementation() != OK && + bool fail = registerPassthroughServiceImplementation() != OK && + registerPassthroughServiceImplementation() != OK && registerPassthroughServiceImplementation() != 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() != OK && + fail = registerPassthroughServiceImplementation() != OK && + registerPassthroughServiceImplementation() != OK && registerPassthroughServiceImplementation() != 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() != OK && + fail = registerPassthroughServiceImplementation() != OK && + registerPassthroughServiceImplementation() != OK && registerPassthroughServiceImplementation() != 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::audio::V2_0::IBluetoothAudioProvidersFactory>() != OK; 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 << "\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(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/effect/2.0/default/VisualizerEffect.h b/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h similarity index 51% rename from audio/effect/2.0/default/VisualizerEffect.h rename to audio/common/all-versions/util/include/common/all-versions/HidlSupport.h index 940f15de9b..b514a43a85 100644 --- a/audio/effect/2.0/default/VisualizerEffect.h +++ b/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h @@ -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,15 +14,21 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H +#ifndef android_hardware_audio_common_HidlSupport_H_ +#define android_hardware_audio_common_HidlSupport_H_ -#include -#include "Effect.h" +#include +#include -#define AUDIO_HAL_VERSION V2_0 -#include -#undef AUDIO_HAL_VERSION +namespace android::hardware::audio::common::utils { -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H +template +bool isValidHidlEnum(Enum e) { + hidl_enum_range values; + return std::find(values.begin(), values.end(), e) != values.end(); +} + +} // namespace android::hardware::audio::common::utils + +#endif // android_hardware_audio_common_HidlSupport_H_ 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) + +#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: . */ +#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_ */ +#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 EnumConverter { +/** Converting between a bitfield or itself. */ +template +class EnumBitfield { public: - static_assert(std::is_enum::value || std::is_enum::value, - "Source or destination should be an enum"); + using Bitfield = ::android::hardware::hidl_bitfield; - explicit EnumConverter(Source source) : mSource(source) {} + EnumBitfield(const EnumBitfield&) = default; + explicit EnumBitfield(Enum value) : mValue(value) {} + explicit EnumBitfield(Bitfield value) : EnumBitfield(static_cast(value)) {} - operator Destination() const { return static_cast(mSource); } + EnumBitfield& operator=(const EnumBitfield&) = default; + EnumBitfield& operator=(Enum value) { return *this = EnumBitfield{value}; } + EnumBitfield& operator=(Bitfield value) { return *this = EnumBitfield{value}; } - template ::value>> - operator ::android::hardware::hidl_bitfield() { - return static_cast>(mSource); - } + operator Enum() const { return mValue; } + operator Bitfield() const { return static_cast(mValue); } private: - const Source mSource; + Enum mValue; }; -template -auto mkEnumConverter(Source source) { - return EnumConverter{source}; -} -/** Allows converting an enum to its bitfield or itself. */ +/** ATD way to create a EnumBitfield. */ template -EnumConverter mkBitfield(Enum value) { - return EnumConverter{value}; +EnumBitfield mkEnumBitfield(Enum value) { + return EnumBitfield{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 -#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 -#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 -#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 -#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 -#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 -#undef AUDIO_HAL_VERSION 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 - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 - -#include "Device.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 - -#include "ParametersUtil.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 - -#include "Device.h" -#include "Stream.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 - -#include "Device.h" -#include "Stream.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H 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 -#include - -#include "utility/ValidateXml.h" - -TEST(CheckConfig, audioPolicyConfigurationValidation) { - RecordProperty("description", - "Verify that the audio policy configuration file " - "is valid according to the schema"); - - std::vector 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 -#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 -#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 -#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 -#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 -#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 -#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 -#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 -#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 -#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 - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#include "ParametersUtil.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#include "Device.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#include "ParametersUtil.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#include "Device.h" -#include "Stream.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#include "Device.h" -#include "Stream.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#undef AUDIO_HAL_VERSION - -#endif // ANDROID_HARDWARE_AUDIO_V4_0_STREAMOUT_H diff --git a/audio/core/4.0/vts/OWNERS b/audio/core/4.0/vts/OWNERS deleted file mode 100644 index 8711a9ff6a..0000000000 --- a/audio/core/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/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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#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(); } -}; - -// 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( - environment->getServiceName("default")); - } - ASSERT_TRUE(devicesFactory != nullptr); - } - - protected: - // Cache the devicesFactory retrieval to speed up each test by ~0.5s - static sp devicesFactory; -}; -sp 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 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 baseDevice; - ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice))); - ASSERT_OK(result); - ASSERT_TRUE(baseDevice != nullptr); - - Return> primaryDevice = IPrimaryDevice::castFrom(baseDevice); - ASSERT_TRUE(primaryDevice.isOk()); - ASSERT_TRUE(sp(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 device; -}; -sp 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 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 - void testAccessors(const string& propertyName, const Initial expectedInitial, - list valuesToTest, Setter setter, Getter getter, - const vector& 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; - -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("master mute", Initial{false}, {true}, &IDevice::setMasterMute, - &IDevice::getMasterMute); - // TODO: check that the master volume is really muted -} - -using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { - doc::test("Test the master volume if supported"); - testAccessors( - "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, - {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits::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 getRequiredSupportPlaybackAudioConfig() { - return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, - {8000, 11025, 16000, 22050, 32000, 44100}, - {AudioFormat::PCM_16_BIT}); - } - - static const vector getRecommendedSupportPlaybackAudioConfig() { - return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, - {24000, 48000}, {AudioFormat::PCM_16_BIT}); - } - - static const vector getSupportedPlaybackAudioConfig() { - // TODO: retrieve audio config supported by the platform - // as declared in the policy configuration - return {}; - } - - static const vector getRequiredSupportCaptureAudioConfig() { - return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100}, - {AudioFormat::PCM_16_BIT}); - } - static const vector getRecommendedSupportCaptureAudioConfig() { - return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000}, - {AudioFormat::PCM_16_BIT}); - } - static const vector getSupportedCaptureAudioConfig() { - // TODO: retrieve audio config supported by the platform - // as declared in the policy configuration - return {}; - } - - private: - static const vector combineAudioConfig(vector channelMasks, - vector sampleRates, - vector formats) { - vector 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& 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 { - 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 context; - hidl_vec keys; - hidl_vec 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 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::NONE); - const SinkMetadata initialMetadata = {{{AudioSource::MIC, 1 /* gain */}}}; - EventFlag* efGroup; - for (auto microphone : microphones) { - if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) { - continue; - } - sp 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 activeMicrophones; - Result readRes; - typedef MessageQueue CommandMQ; - typedef MessageQueue DataMQ; - std::unique_ptr commandMQ; - std::unique_ptr 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(MessageQueueFlagBits::NOT_FULL)); - uint32_t efState = 0; - efGroup->wait(static_cast(MessageQueueFlagBits::NOT_EMPTY), &efState); - if (efState & static_cast(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 -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 OpenStreamTest : public AudioConfigPrimaryTest, - public ::testing::WithParamInterface { - protected: - template - 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 closeStream() { - open = false; - return stream->close(); - } - - private: - void TearDown() override { - if (open) { - ASSERT_OK(stream->close()); - } - } - - protected: - AudioConfig audioConfig; - DeviceAddress address = {}; - sp stream; - bool open = false; -}; - -////////////////////////////// openOutputStream ////////////////////////////// - -class OutputStreamTest : public OpenStreamTest { - 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::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 { - 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::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 -static R extract(Return 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 -static void testCapabilityGetter(const string& name, IStream* stream, - CapablityGetter capablityGetter, - Return (IStream::*getter)(), - Return (IStream::*setter)(Property), - bool currentMustBeSupported = true) { - hidl_vec 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& rates) { - Result res; - EXPECT_OK(stream->getSupportedSampleRates(extract(stream->getFormat()), returnIn(res, rates))); - return res; -} - -Result getSupportedChannelMasks(IStream* stream, - hidl_vec>& channels) { - Result res; - EXPECT_OK( - stream->getSupportedChannelMasks(extract(stream->getFormat()), returnIn(res, channels))); - return res; -} - -Result getSupportedFormats(IStream* stream, hidl_vec& 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 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 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 keys, - initializer_list expectedResults) { - hidl_vec context; - hidl_vec 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::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(float)> setGain) { - for (float value : (float[]){-INFINITY, -1.0, 1.0 + std::numeric_limits::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(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::max()); -} - -TEST_P(InputStreamTest, PrepareForReadingCheckOverflow) { - doc::test( - "Preparing a stream for reading with a overflowing sized buffer should " - "fail"); - auto uintMax = std::numeric_limits::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 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::max()); -} - -TEST_P(OutputStreamTest, PrepareForWritingCheckOverflow) { - doc::test( - "Preparing a stream for writing with a overflowing sized buffer should " - "fail"); - auto uintMax = std::numeric_limits::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 -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 onWriteReady() override { return {}; } - Return onDrainReady() override { return {}; } - Return 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 usageRange; - hidl_enum_range 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("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true}, - &IPrimaryDevice::setBtScoNrecEnabled, - &IPrimaryDevice::getBtScoNrecEnabled); -} - -TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { - doc::test("Query and set the SCO whideband state"); - testAccessors("BtScoWideband", Initial{false, OPTIONAL}, {true}, - &IPrimaryDevice::setBtScoWidebandEnabled, - &IPrimaryDevice::getBtScoWidebandEnabled); -} - -TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) { - doc::test("Query and set the BT HFP state"); - testAccessors("BtHfpEnabled", Initial{false, OPTIONAL}, {true}, - &IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled); -} - -using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { - doc::test("Query and set the TTY mode state"); - testAccessors("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("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 -#include - -#include "utility/ValidateXml.h" - -TEST(CheckConfig, audioPolicyConfigurationValidation) { - RecordProperty("description", - "Verify that the audio policy configuration file " - "is valid according to the schema"); - - std::vector 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 similarity index 96% rename from audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h rename to 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 +#include "core/default/Conversions.h" #include @@ -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 similarity index 78% rename from audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h rename to 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 +#define LOG_TAG "DeviceHAL" + +#include "core/default/Device.h" +#include +#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 -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& 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 Device::initCheck() { return analyzeStatus("init_check", mDevice->init_check(mDevice)); } @@ -129,12 +137,11 @@ Return Device::getInputBufferSize(const AudioConfig& config, getInputBuffe return Void(); } -Return 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> 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 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 Device::openInputStream(int32_t ioHandle, const DeviceAddress& device, - const AudioConfig& config, AudioInputFlagBitfield flags, - AudioSource source, openInputStream_cb _hidl_cb) { +std::tuple> 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 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 Device::openOutputStream(int32_t ioHandle, const DeviceAddress& device, + const AudioConfig& config, AudioOutputFlagBitfield flags, + 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); + _hidl_cb(result, streamOut, suggestedConfig); + return Void(); +} + +Return 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 Device::openOutputStream(int32_t ioHandle, const DeviceAddress& device, + const AudioConfig& config, AudioOutputFlagBitfield flags, + const SourceMetadata& sourceMetadata, + openOutputStream_cb _hidl_cb) { + AudioConfig 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 Device::openInputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioInputFlagBitfield flags, const SinkMetadata& sinkMetadata, @@ -199,11 +237,18 @@ Return 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 Device::supportsAudioPatches() { return version() >= AUDIO_DEVICE_API_VERSION_3_0; @@ -260,13 +305,13 @@ Return Device::setAudioPortConfig(const AudioPortConfig& config) { return Result::NOT_SUPPORTED; } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return 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 Device::getHwAvSync(getHwAvSync_cb _hidl_cb) { int halHwAvSync; Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync); @@ -279,7 +324,7 @@ Return Device::setScreenState(bool turnedOn) { return setParam(AudioParameter::keyScreenState, turnedOn); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return Device::getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) { getParametersImpl({}, keys, _hidl_cb); return Void(); @@ -288,7 +333,7 @@ Return Device::getParameters(const hidl_vec& keys, getParamet Return Device::setParameters(const hidl_vec& parameters) { return setParametersImpl({} /* context */, parameters); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return Device::getParameters(const hidl_vec& context, const hidl_vec& keys, getParameters_cb _hidl_cb) { getParametersImpl(context, keys, _hidl_cb); @@ -300,7 +345,7 @@ Return Device::setParameters(const hidl_vec& context, } #endif -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return Device::debugDump(const hidl_handle& fd) { return debug(fd, {}); } @@ -313,7 +358,7 @@ Return Device::debug(const hidl_handle& fd, const hidl_vec& / return Void(); } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return Device::getMicrophones(getMicrophones_cb _hidl_cb) { Result retval = Result::NOT_SUPPORTED; size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT; @@ -339,7 +384,7 @@ Return 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 similarity index 89% rename from audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h rename to 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 +#define LOG_TAG "DevicesFactoryHAL" + +#include "core/default/DevicesFactory.h" +#include "core/default/Device.h" +#include "core/default/PrimaryDevice.h" #include @@ -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 DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) { switch (device) { case IDevicesFactory::Device::PRIMARY: @@ -43,8 +47,7 @@ Return 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 DevicesFactory::openDevice(const hidl_string& moduleName, openDevice_cb _hidl_cb) { if (moduleName == AUDIO_HARDWARE_MODULE_ID_PRIMARY) { return openDevice(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 similarity index 100% rename from audio/common/4.0/default/OWNERS rename to 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 similarity index 96% rename from audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.impl.h rename to 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 -#include +#include "core/default/ParametersUtil.h" +#include "core/default/Conversions.h" +#include "core/default/Util.h" + #include 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 similarity index 95% rename from audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.impl.h rename to 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 +#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 #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 PrimaryDevice::initCheck() { return mDevice->initCheck(); } @@ -64,7 +67,7 @@ Return PrimaryDevice::getInputBufferSize(const AudioConfig& config, return mDevice->getInputBufferSize(config, _hidl_cb); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return PrimaryDevice::openOutputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioOutputFlagBitfield flags, @@ -77,7 +80,7 @@ Return 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 PrimaryDevice::openOutputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioOutputFlagBitfield flags, @@ -120,7 +123,7 @@ Return PrimaryDevice::setScreenState(bool turnedOn) { return mDevice->setScreenState(turnedOn); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return PrimaryDevice::getHwAvSync() { return mDevice->getHwAvSync(); } @@ -137,7 +140,7 @@ Return PrimaryDevice::setParameters(const hidl_vec& para Return PrimaryDevice::debugDump(const hidl_handle& fd) { return mDevice->debugDump(fd); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return PrimaryDevice::getHwAvSync(getHwAvSync_cb _hidl_cb) { return mDevice->getHwAvSync(_hidl_cb); } @@ -158,7 +161,7 @@ Return 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 PrimaryDevice::setVoiceVolume(float volume) { if (!isGainNormalized(volume)) { ALOGW("Can not set a voice volume (%f) outside [0,1]", volume); @@ -271,7 +274,7 @@ Return PrimaryDevice::setHacEnabled(bool enabled) { return mDevice->setParam(AUDIO_PARAMETER_KEY_HAC, enabled); } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return PrimaryDevice::setBtScoHeadsetDebugName(const hidl_string& name) { return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_HEADSET_NAME, name.c_str()); } @@ -307,7 +310,7 @@ Return PrimaryDevice::debug(const hidl_handle& fd, const hidl_vec +#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 @@ -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& 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 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 Stream::getSampleRate() { return mStream->get_sample_rate(mStream); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return Stream::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { return getSupportedSampleRates(getFormat(), _hidl_cb); } @@ -107,9 +111,9 @@ Return 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 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 Stream::setHwAvSync(uint32_t hwAvSync) { return setParam(AudioParameter::keyStreamHwAvSync, static_cast(hwAvSync)); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return Stream::getDevice() { int device = 0; Result retval = getParam(AudioParameter::keyRouting, &device); @@ -242,7 +246,7 @@ Return 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 Stream::getDevices(getDevices_cb _hidl_cb) { int device = 0; Result retval = getParam(AudioParameter::keyRouting, &device); @@ -314,14 +318,14 @@ Return Stream::debug(const hidl_handle& fd, const hidl_vec& / return Void(); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return 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 similarity index 87% rename from audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h rename to audio/core/all-versions/default/StreamIn.cpp index 64c85ab5fc..d316f83617 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,12 @@ * limitations under the License. */ -#include +#define LOG_TAG "StreamInHAL" + +#include "core/default/StreamIn.h" +#include "core/default/Conversions.h" +#include "core/default/Util.h" +#include "common/all-versions/HidlSupport.h" //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_AUDIO @@ -23,18 +28,14 @@ #include #include #include - -using ::android::hardware::audio::AUDIO_HAL_VERSION::MessageQueueFlagBits; -#include "Conversions.h" +#include 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 +163,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 StreamIn::getFrameSize() { return audio_stream_in_frame_size(mStream); } @@ -179,7 +180,7 @@ Return StreamIn::getSampleRate() { return mStreamCommon->getSampleRate(); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { return mStreamCommon->getSupportedChannelMasks(_hidl_cb); } @@ -241,7 +242,7 @@ Return StreamIn::setHwAvSync(uint32_t hwAvSync) { return mStreamCommon->setHwAvSync(hwAvSync); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return StreamIn::setConnectedState(const DeviceAddress& address, bool connected) { return mStreamCommon->setConnectedState(address, connected); } @@ -265,7 +266,7 @@ Return StreamIn::setParameters(const hidl_vec& parameter Return StreamIn::debugDump(const hidl_handle& fd) { return mStreamCommon->debugDump(fd); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return StreamIn::getDevices(getDevices_cb _hidl_cb) { return mStreamCommon->getDevices(_hidl_cb); } @@ -313,7 +314,7 @@ Return 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 StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) { int halSource; Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource); @@ -342,7 +343,6 @@ Return 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 +448,7 @@ Return StreamIn::debug(const hidl_handle& fd, const hidl_vec& return mStreamCommon->debug(fd, options); } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) { if (mStream->update_sink_metadata == nullptr) { return Void(); // not supported by the HAL @@ -456,11 +456,23 @@ Return StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) { std::vector halTracks; halTracks.reserve(sinkMetadata.tracks.size()); for (auto& metadata : sinkMetadata.tracks) { - halTracks.push_back( - {.source = static_cast(metadata.source), .gain = metadata.gain}); + record_track_metadata halTrackMetadata = { + .source = static_cast(metadata.source), .gain = metadata.gain}; +#if MAJOR_VERSION >= 5 + if (metadata.destination.getDiscriminator() == + RecordTrackMetadata::Destination::hidl_discriminator::device) { + halTrackMetadata.dest_device = + static_cast(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 +498,37 @@ Return StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) { } #endif +#if MAJOR_VERSION >= 5 +Return StreamIn::setMicrophoneDirection(MicrophoneDirection direction) { + if (mStream->set_microphone_direction == nullptr) { + return Result::NOT_SUPPORTED; + } + if (!common::utils::isValidHidlEnum(direction)) { + ALOGE("%s: Invalid direction %d", __func__, direction); + return Result::INVALID_ARGUMENTS; + } + return Stream::analyzeStatus( + "set_microphone_direction", + mStream->set_microphone_direction( + mStream, static_cast(direction))); +} + +Return StreamIn::setMicrophoneFieldDimension(float zoom) { + if (mStream->set_microphone_field_dimension == nullptr) { + return Result::NOT_SUPPORTED; + } + if (std::isnan(zoom) || zoom < -1 || zoom > 1) { + ALOGE("%s: Invalid zoom %f", __func__, zoom); + return Result::INVALID_ARGUMENTS; + } + 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 similarity index 97% rename from audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h rename to 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 +#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 StreamOut::getFrameSize() { return audio_stream_out_frame_size(mStream); } @@ -182,7 +183,7 @@ Return StreamOut::getSampleRate() { return mStreamCommon->getSampleRate(); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { return mStreamCommon->getSupportedChannelMasks(_hidl_cb); } @@ -244,7 +245,7 @@ Return StreamOut::setHwAvSync(uint32_t hwAvSync) { return mStreamCommon->setHwAvSync(hwAvSync); } -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return StreamOut::setConnectedState(const DeviceAddress& address, bool connected) { return mStreamCommon->setConnectedState(address, connected); } @@ -269,7 +270,7 @@ Return StreamOut::setParameters(const hidl_vec& paramete Return StreamOut::debugDump(const hidl_handle& fd) { return mStreamCommon->debugDump(fd); } -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return StreamOut::getDevices(getDevices_cb _hidl_cb) { return mStreamCommon->getDevices(_hidl_cb); } @@ -301,7 +302,7 @@ Return 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 StreamOut::getLatency() { return mStream->get_latency(mStream); } @@ -326,7 +327,6 @@ Return 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 StreamOut::debug(const hidl_handle& fd, const hidl_vec return mStreamCommon->debug(fd, options); } -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) { if (mStream->update_source_metadata == nullptr) { return Void(); // not supported by the HAL @@ -560,7 +560,8 @@ Return 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 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 similarity index 69% rename from audio/core/all-versions/default/include/core/all-versions/default/Conversions.h rename to 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 +#ifndef ANDROID_HARDWARE_AUDIO_CONVERSIONS_H_ +#define ANDROID_HARDWARE_AUDIO_CONVERSIONS_H_ + +#include PATH(android/hardware/audio/FILE_VERSION/types.h) #include @@ -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 similarity index 72% rename from audio/core/all-versions/default/include/core/all-versions/default/Device.h rename to 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 +#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 @@ -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 initCheck() override; Return setMasterVolume(float volume) override; Return getMasterVolume(getMasterVolume_cb _hidl_cb) override; @@ -75,15 +62,22 @@ struct Device : public IDevice, public ParametersUtil { Return getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) override; - // V2 openInputStream is called by V4 input stream thus present in both versions - Return 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> openOutputStreamImpl(int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlagBitfield flags, + AudioConfig* suggestedConfig); + std::tuple> openInputStreamImpl( + int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, + AudioInputFlagBitfield flags, AudioSource source, AudioConfig* suggestedConfig); +#if MAJOR_VERSION == 2 Return 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 openInputStream(int32_t ioHandle, const DeviceAddress& device, + const AudioConfig& config, AudioInputFlagBitfield flags, + AudioSource source, openInputStream_cb _hidl_cb) override; +#elif MAJOR_VERSION >= 4 Return 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 setScreenState(bool turnedOn) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return getHwAvSync() override; Return getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) override; Return setParameters(const hidl_vec& parameters) override; Return debugDump(const hidl_handle& fd) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return getHwAvSync(getHwAvSync_cb _hidl_cb) override; Return getParameters(const hidl_vec& context, const hidl_vec& keys, @@ -124,7 +118,8 @@ struct Device : public IDevice, public ParametersUtil { Return debug(const hidl_handle& fd, const hidl_vec& options) override; // Utility methods for extending interfaces. - Result analyzeStatus(const char* funcName, int status); + Result analyzeStatus(const char* funcName, int status, + const std::vector& 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 similarity index 79% rename from audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.h rename to 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 +#ifndef ANDROID_HARDWARE_AUDIO_DEVICESFACTORY_H +#define ANDROID_HARDWARE_AUDIO_DEVICESFACTORY_H + +#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h) #include @@ -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 openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) override; -#endif -#ifdef AUDIO_HAL_VERSION_4_0 +#elif MAJOR_VERSION >= 4 Return openDevice(const hidl_string& device, openDevice_cb _hidl_cb) override; Return 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 similarity index 82% rename from audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.h rename to 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 +#ifndef ANDROID_HARDWARE_AUDIO_PARAMETERS_UTIL_H_ +#define ANDROID_HARDWARE_AUDIO_PARAMETERS_UTIL_H_ + +#include PATH(android/hardware/audio/FILE_VERSION/types.h) #include #include @@ -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 similarity index 78% rename from audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.h rename to 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 +#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 @@ -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 initCheck() override; Return setMasterVolume(float volume) override; Return getMasterVolume(getMasterVolume_cb _hidl_cb) override; @@ -62,7 +55,7 @@ struct PrimaryDevice : public IPrimaryDevice { Return 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 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 openInputStream(int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, AudioInputFlagBitfield flags, const SinkMetadata& sinkMetadata, @@ -87,13 +80,13 @@ struct PrimaryDevice : public IPrimaryDevice { Return setScreenState(bool turnedOn) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return getHwAvSync() override; Return getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) override; Return setParameters(const hidl_vec& parameters) override; Return debugDump(const hidl_handle& fd) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return getHwAvSync(getHwAvSync_cb _hidl_cb) override; Return getParameters(const hidl_vec& context, const hidl_vec& keys, @@ -106,7 +99,7 @@ struct PrimaryDevice : public IPrimaryDevice { Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IPrimaryDevice follow. + // Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow. Return setVoiceVolume(float volume) override; Return setMode(AudioMode mode) override; Return getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) override; @@ -118,7 +111,7 @@ struct PrimaryDevice : public IPrimaryDevice { Return getHacEnabled(getHacEnabled_cb _hidl_cb) override; Return setHacEnabled(bool enabled) override; -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return setBtScoHeadsetDebugName(const hidl_string& name) override; Return getBtHfpEnabled(getBtHfpEnabled_cb _hidl_cb) override; Return 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 similarity index 88% rename from audio/core/all-versions/default/include/core/all-versions/default/Stream.h rename to 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 +#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 @@ -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 getFrameSize() override; Return getFrameCount() override; Return getBufferSize() override; Return getSampleRate() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; Return getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; #endif @@ -76,14 +76,14 @@ struct Stream : public IStream, public ParametersUtil { Return addEffect(uint64_t effectId) override; Return removeEffect(uint64_t effectId) override; Return standby() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return getDevice() override; Return setDevice(const DeviceAddress& address) override; Return getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) override; Return setParameters(const hidl_vec& parameters) override; Return setConnectedState(const DeviceAddress& address, bool connected) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return getDevices(getDevices_cb _hidl_cb) override; Return setDevices(const hidl_vec& devices) override; Return getParameters(const hidl_vec& context, @@ -100,7 +100,7 @@ struct Stream : public IStream, public ParametersUtil { Return close() override; Return debug(const hidl_handle& fd, const hidl_vec& options) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return debugDump(const hidl_handle& fd) override; #endif @@ -171,7 +171,7 @@ Return StreamMmap::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 StreamMmap::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 similarity index 82% rename from audio/core/all-versions/default/include/core/all-versions/default/StreamIn.h rename to 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 +#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 #include @@ -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 CommandMQ; @@ -53,12 +52,12 @@ struct StreamIn : public IStreamIn { StreamIn(const sp& 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 getFrameSize() override; Return getFrameCount() override; Return getBufferSize() override; Return getSampleRate() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; Return getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; #endif @@ -74,14 +73,14 @@ struct StreamIn : public IStreamIn { Return addEffect(uint64_t effectId) override; Return removeEffect(uint64_t effectId) override; Return standby() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return getDevice() override; Return setDevice(const DeviceAddress& address) override; Return getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) override; Return setParameters(const hidl_vec& parameters) override; Return setConnectedState(const DeviceAddress& address, bool connected) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return getDevices(getDevices_cb _hidl_cb) override; Return setDevices(const hidl_vec& devices) override; Return getParameters(const hidl_vec& context, @@ -94,11 +93,11 @@ struct StreamIn : public IStreamIn { Return close() override; Return debug(const hidl_handle& fd, const hidl_vec& options) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return 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 getAudioSource(getAudioSource_cb _hidl_cb) override; Return setGain(float gain) override; Return prepareForReading(uint32_t frameSize, uint32_t framesCount, @@ -109,11 +108,14 @@ struct StreamIn : public IStreamIn { Return stop() override; Return createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; Return getMmapPosition(getMmapPosition_cb _hidl_cb) override; -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return updateSinkMetadata(const SinkMetadata& sinkMetadata) override; Return getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) override; #endif - +#if MAJOR_VERSION >= 5 + Return setMicrophoneDirection(MicrophoneDirection direction) override; + Return 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 similarity index 82% rename from audio/core/all-versions/default/include/core/all-versions/default/StreamOut.h rename to 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 +#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 #include @@ -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 CommandMQ; @@ -55,12 +52,12 @@ struct StreamOut : public IStreamOut { StreamOut(const sp& 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 getFrameSize() override; Return getFrameCount() override; Return getBufferSize() override; Return getSampleRate() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; Return getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; #endif @@ -76,14 +73,14 @@ struct StreamOut : public IStreamOut { Return addEffect(uint64_t effectId) override; Return removeEffect(uint64_t effectId) override; Return standby() override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return getDevice() override; Return setDevice(const DeviceAddress& address) override; Return getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) override; Return setParameters(const hidl_vec& parameters) override; Return setConnectedState(const DeviceAddress& address, bool connected) override; -#elif defined(AUDIO_HAL_VERSION_4_0) +#elif MAJOR_VERSION >= 4 Return getDevices(getDevices_cb _hidl_cb) override; Return setDevices(const hidl_vec& devices) override; Return getParameters(const hidl_vec& context, @@ -96,11 +93,11 @@ struct StreamOut : public IStreamOut { Return close() override; Return debug(const hidl_handle& fd, const hidl_vec& options) override; -#ifdef AUDIO_HAL_VERSION_2_0 +#if MAJOR_VERSION == 2 Return 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 getLatency() override; Return setVolume(float left, float right) override; Return prepareForWriting(uint32_t frameSize, uint32_t framesCount, @@ -120,7 +117,7 @@ struct StreamOut : public IStreamOut { Return stop() override; Return createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; Return getMmapPosition(getMmapPosition_cb _hidl_cb) override; -#ifdef AUDIO_HAL_VERSION_4_0 +#if MAJOR_VERSION >= 4 Return updateSourceMetadata(const SourceMetadata& sourceMetadata) override; Return 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 similarity index 82% rename from audio/core/all-versions/default/include/core/all-versions/default/Util.h rename to 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 +#ifndef ANDROID_HARDWARE_AUDIO_UTIL_H +#define ANDROID_HARDWARE_AUDIO_UTIL_H + +#include PATH(android/hardware/audio/FILE_VERSION/types.h) #include #include @@ -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/2.0/vts/OWNERS b/audio/core/all-versions/vts/OWNERS similarity index 79% rename from audio/core/2.0/vts/OWNERS rename to audio/core/all-versions/vts/OWNERS index 8711a9ff6a..0ea4666443 100644 --- a/audio/core/2.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 + +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 + static auto get(T t, hidl_vec keys, ReturnIn returnIn) { + return t->getParameters(keys, returnIn); + } + template + static auto set(T t, hidl_vec 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 + static Result convertToResult(const Vec& vec) { + return vec.size() == 0 ? Result::NOT_SUPPORTED : Result::OK; + } + + static Result sampleRates(IStream* stream, hidl_vec& rates) { + EXPECT_OK(stream->getSupportedSampleRates(returnIn(rates))); + return convertToResult(rates); + } + + static Result channelMasks(IStream* stream, hidl_vec& channels) { + EXPECT_OK(stream->getSupportedChannelMasks(returnIn(channels))); + return convertToResult(channels); + } + + static Result formats(IStream* stream, hidl_vec& capabilities) { + EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities))); + // TODO: this should be an optional function + return Result::OK; + } +}; + +template +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 baseDevice; + ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice))); + ASSERT_OK(result); + ASSERT_TRUE(baseDevice != nullptr); + + Return> primaryDevice = IPrimaryDevice::castFrom(baseDevice); + ASSERT_TRUE(primaryDevice.isOk()); + ASSERT_TRUE(sp(primaryDevice) != nullptr); + } // Destroy local IDevice proxy + waitForDeviceDestruction(); +} + +////////////////////////////////////////////////////////////////////////////// +/////////////////////////// get(Active)Microphones /////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { + doc::test("Make sure getMicrophones always succeeds"); + hidl_vec 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::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 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 activeMicrophones; + Result readRes; + typedef MessageQueue CommandMQ; + typedef MessageQueue DataMQ; + std::unique_ptr commandMQ; + std::unique_ptr 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(MessageQueueFlagBits::NOT_FULL)); + uint32_t efState = 0; + efGroup->wait(static_cast(MessageQueueFlagBits::NOT_EMPTY), &efState); + if (efState & static_cast(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 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 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 usageRange; + hidl_enum_range 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("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 + +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 + static auto get(T t, hidl_vec keys, ReturnIn returnIn) { + hidl_vec context; + return t->getParameters(context, keys, returnIn); + } + template + static auto set(T t, hidl_vec values) { + hidl_vec 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& rates) { + Result res; + EXPECT_OK(stream->getSupportedSampleRates(getFormat(stream), returnIn(res, rates))); + return res; + } + + static Result channelMasks(IStream* stream, + hidl_vec>& channels) { + Result res; + EXPECT_OK(stream->getSupportedChannelMasks(getFormat(stream), returnIn(res, channels))); + return res; + } + + static Result formats(IStream* stream, hidl_vec& capabilities) { + EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities))); + // TODO: this should be an optional function + return Result::OK; + } +}; + +template +auto dump(T t, hidl_handle handle) { + return t->debug(handle, {/* options */}); +} diff --git a/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp new file mode 100644 index 0000000000..bdb17cdc3c --- /dev/null +++ b/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp @@ -0,0 +1,55 @@ +/* + * 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 + +// pull in all the <= 4.0 tests +#include "4.0/AudioPrimaryHidlHalTest.cpp" + +TEST_P(InputStreamTest, SetMicrophoneDirection) { + doc::test("Make sure setMicrophoneDirection correctly handles valid & invalid arguments"); + + // MicrophoneDirection dir = MicrophoneDirection::FRONT; + for (MicrophoneDirection dir : android::hardware::hidl_enum_range()) { + ASSERT_RESULT(okOrNotSupported, stream->setMicrophoneDirection(dir)); + } + + // Bogus values + for (auto dir : {42, -1, 4}) { + ASSERT_RESULT(invalidArgsOrNotSupported, + stream->setMicrophoneDirection(MicrophoneDirection(dir))); + } +} + +TEST_P(InputStreamTest, SetMicrophoneFieldDimension) { + doc::test("Make sure setMicrophoneFieldDimension correctly handles valid & invalid arguments"); + + // Valid zoom values -1.0 -> 1.0 + float incr = 0.1f; + for (float val = -1.0f; val <= 1.0; val += incr) { + ASSERT_RESULT(okOrNotSupported, stream->setMicrophoneFieldDimension(val)); + } + + // Bogus values + for (float val = 1.0f + incr; val <= 10.0f; val += incr) { + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(val)); + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-val)); + } + // Some extremes + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(NAN)); + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-NAN)); + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(INFINITY)); + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-INFINITY)); +} 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..88fdb5a1dd --- /dev/null +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -0,0 +1,84 @@ +// +// 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", + "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: [ + "5.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 similarity index 75% rename from audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp rename to audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index a08a2d62bb..7f8b6a0646 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 #include @@ -22,71 +22,86 @@ #include #include #include +#include #include #include #include #include +#include + #include #include -#include -#include -#include -#include -#include +#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 +#include +#include + +#include #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: @@ -102,12 +117,103 @@ class HidlTest : public ::testing::VtsHalHidlTargetTestBase { Result res; }; +////////////////////////////////////////////////////////////////////////////// +////////////////////////// Audio policy configuration //////////////////////// +////////////////////////////////////////////////////////////////////////////// + +static const std::vector 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 defaultOutputDevice; +}; + +class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { + public: + PolicyConfig() + : AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices, + defaultOutputDevice) { + 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 getPrimaryModule() const { return mPrimaryModule; } + + private: + status_t mStatus = NO_INIT; + std::string mFilePath; + sp mPrimaryModule = nullptr; +}; + +// Cached policy config after parsing for faster test startup +const PolicyConfig& getCachedPolicyConfig() { + static std::unique_ptr policyConfig = [] { + auto config = std::make_unique(); + 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 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 +233,20 @@ class AudioHidlTest : public HidlTest { sp 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 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 +262,32 @@ class AudioPrimaryHidlTest : public AudioHidlTest { ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base if (device == nullptr) { - IDevicesFactory::Result result; - sp 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 device; + + private: + void initPrimaryDevice() { + Result result; +#if MAJOR_VERSION == 2 + sp 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 AudioPrimaryHidlTest::device; @@ -186,53 +307,59 @@ TEST_F(AudioPrimaryHidlTest, Init) { template class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { protected: - /** Test a property getter and setter. */ - template - void testAccessors(const string& propertyName, const vector& valuesToTest, - Setter setter, Getter getter, const vector& invalidValues = {}) { - Property initialValue; // Save initial value to restore it at the end - // of the test - ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue))); - ASSERT_OK(res); + 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 + void testAccessors(const string& propertyName, const Initial expectedInitial, + list valuesToTest, Setter setter, Getter getter, + const vector& 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)); - 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 - void testOptionalAccessors(const string& propertyName, const vector& valuesToTest, - Setter setter, Getter getter, - const vector& 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 +367,22 @@ using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; 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("master mute", Initial{false}, {true}, &IDevice::setMasterMute, + &IDevice::getMasterMute); // TODO: check that the master volume is really muted } using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { doc::test("Test the master volume if supported"); - testOptionalAccessors( - "master volume", {0, 0.5, 1}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, + testAccessors( + "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits::epsilon()}); // TODO: check that the master volume is really changed } @@ -295,6 +420,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 getRequiredSupportPlaybackAudioConfig() { return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, @@ -314,10 +454,12 @@ class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { } static const vector getRequiredSupportCaptureAudioConfig() { + if (!primaryHasMic()) return {}; return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100}, {AudioFormat::PCM_16_BIT}); } static const vector getRecommendedSupportCaptureAudioConfig() { + if (!primaryHasMic()) return {}; return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000}, {AudioFormat::PCM_16_BIT}); } @@ -337,7 +479,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 +500,10 @@ static string generateTestName(const testing::TestParamInfo& 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 +575,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 +585,13 @@ TEST_F(AudioPrimaryHidlTest, setScreenState) { TEST_F(AudioPrimaryHidlTest, getParameters) { doc::test("Check that the hal can set and get parameters"); + hidl_vec context; hidl_vec keys; hidl_vec 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 +634,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 +708,26 @@ class OutputStreamTest : public OpenStreamTest { 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 +756,21 @@ class InputStreamTest : public OpenStreamTest { 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 +841,26 @@ TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it wa template static void testCapabilityGetter(const string& name, IStream* stream, - CapabilityGetter capablityGetter, + CapabilityGetter capabilityGetter, Return (IStream::*getter)(), Return (IStream::*setter)(Property), bool currentMustBeSupported = true) { hidl_vec 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 +878,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 +887,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({}); AudioFormat format; stream->getAudioProperties(returnIn(sampleRateHz, mask, format)); @@ -784,33 +912,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 keys, initializer_list expectedResults) { hidl_vec 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 +940,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 +975,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 +988,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 +1094,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 +1213,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 +1261,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 +1331,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("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("BtScoWideband", Initial{false, OPTIONAL}, {true}, + &IPrimaryDevice::setBtScoWidebandEnabled, + &IPrimaryDevice::getBtScoWidebandEnabled); } -using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; +using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; 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( + "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("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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 - -#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 -#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 - -#include "AudioBufferManager.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include - -#include -#define AUDIO_HAL_VERSION V2_0 -#include -#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 - -#include "EnvironmentalReverbEffect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 - -#include - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V2_0 -#include -#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 -#undef AUDIO_HAL_VERSION 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 -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -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(); } -}; - -// The main test class for Audio Effects Factory HIDL HAL. -class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - void SetUp() override { - effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService( - AudioEffectsFactoryHidlEnvironment::Instance()->getServiceName()); - ASSERT_NE(effectsFactory, nullptr); - } - - void TearDown() override { effectsFactory.clear(); } - - protected: - static void description(const std::string& description) { - RecordProperty("description", description); - } - - sp effectsFactory; -}; - -TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { - description("Verify that EnumerateEffects returns at least one effect"); - Result retval = Result::NOT_INITIALIZED; - size_t effectCount = 0; - Return ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec& 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 ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec& 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 effect; - ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp& 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 allDescriptors; - Return ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec& 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 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{{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{{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(); - ASSERT_NE(nullptr, effectsFactory.get()); - - findAndCreateEffect(getEffectType()); - ASSERT_NE(nullptr, effect.get()); - - Return 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 effectsFactory; - sp effect; -}; - -void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) { - Uuid effectUuid; - findEffectInstance(type, &effectUuid); - Return ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp& 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 ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec& 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 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(currentConfig.outputCfg.channels))); - *channelCount = audio_channel_count_from_out_mask( - static_cast(currentConfig.outputCfg.channels)); -} - -TEST_F(AudioEffectHidlTest, Close) { - description("Verify that an effect can be closed"); - Return 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 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 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 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 ret = - effect->getConfigReverse([&](Result, const EffectConfig&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { - description("Verify that GetSupportedAuxChannelsConfigs does not crash"); - Return ret = effect->getSupportedAuxChannelsConfigs( - 0, [&](Result, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) { - description("Verify that GetAuxChannelsConfig does not crash"); - Return ret = effect->getAuxChannelsConfig( - [&](Result, const EffectAuxChannelsConfig&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) { - description("Verify that SetAuxChannelsConfig does not crash"); - Return 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 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 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 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 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 volumes; - volumes.resize(channelCount); - for (uint32_t i = 0; i < channelCount; ++i) { - volumes[i] = 0; - } - Result retval = Result::NOT_INITIALIZED; - Return ret = effect->setAndGetVolume( - volumes, [&](Result r, const hidl_vec&) { 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 volumes; - volumes.resize(channelCount); - for (uint32_t i = 0; i < channelCount; ++i) { - volumes[i] = 0; - } - Return 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 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 ret = - effect->setConfigReverse(EffectConfig(), nullptr, nullptr); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetInputDevice) { - description("Verify that SetInputDevice does not crash"); - Return ret = effect->setInputDevice(AudioDevice::IN_BUILTIN_MIC); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetAudioSource) { - description("Verify that SetAudioSource does not crash"); - Return 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(AudioHandleConsts::AUDIO_IO_HANDLE_NONE); - Return 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 ret = effect->prepareForProcessing( - [&](Result r, const MQDescriptorSync&) { retval = r; }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); -} - -TEST_F(AudioEffectHidlTest, SetProcessBuffers) { - description("Verify that SetProcessBuffers works for an effect"); - sp ashmem = IAllocator::getService("ashmem"); - ASSERT_NE(nullptr, ashmem.get()); - bool success = false; - AudioBuffer buffer; - Return 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 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 ret = effect->command(0, hidl_vec(), 0, - [&](int32_t, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetParameter) { - description("Verify that SetParameter does not crash"); - Return ret = - effect->setParameter(hidl_vec(), hidl_vec()); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetParameter) { - description("Verify that GetParameter does not crash"); - Return ret = effect->getParameter( - hidl_vec(), 0, [&](Result, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) { - description("Verify that GetSupportedConfigsForFeature does not crash"); - Return ret = effect->getSupportedConfigsForFeature( - 0, 0, 0, [&](Result, uint32_t, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) { - description("Verify that GetCurrentConfigForFeature does not crash"); - Return ret = effect->getCurrentConfigForFeature( - 0, 0, [&](Result, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) { - description("Verify that SetCurrentConfigForFeature does not crash"); - Return ret = - effect->setCurrentConfigForFeature(0, hidl_vec()); - 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 equalizer; -}; - -void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) { - Result retval = Result::NOT_INITIALIZED; - Return 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 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 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 ret = equalizer->getPresetNames( - [&](Result r, const hidl_vec& 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 ret = equalizer->setBandLevel(i, levels[j]); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Result retval = Result::NOT_INITIALIZED; - int16_t actualLevel; - Return 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 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 ret = equalizer->setCurrentPreset(i); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Result retval = Result::NOT_INITIALIZED; - uint16_t actualPreset = 0xffff; - Return 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 ret = equalizer->setAllProperties(props); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Return 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 enhancer; -}; - -TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { - description( - "Verify that manipulating the target gain works for Loudness Enhancer " - "effect"); - const int32_t gain = 100; - Return ret = enhancer->setTargetGain(gain); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - int32_t actualGain = 0; - Result retval; - Return 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 similarity index 99% rename from audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd rename to 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 @@ + 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 -#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 - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#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 -#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 - -#include "AudioBufferManager.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include - -#include -#define AUDIO_HAL_VERSION V4_0 -#include -#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 - -#include "EnvironmentalReverbEffect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 -#include - -#include - -#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 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 -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -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(); } -}; - -// The main test class for Audio Effects Factory HIDL HAL. -class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { - public: - void SetUp() override { - effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService( - AudioEffectsFactoryHidlEnvironment::Instance()->getServiceName()); - ASSERT_NE(effectsFactory, nullptr); - } - - void TearDown() override { effectsFactory.clear(); } - - protected: - static void description(const std::string& description) { - RecordProperty("description", description); - } - - sp effectsFactory; -}; - -TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { - description("Verify that EnumerateEffects returns at least one effect"); - Result retval = Result::NOT_INITIALIZED; - size_t effectCount = 0; - Return ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec& 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 ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec& 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 effect; - ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp& 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 allDescriptors; - Return ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec& 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 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{{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{{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(); - ASSERT_NE(nullptr, effectsFactory.get()); - - findAndCreateEffect(getEffectType()); - ASSERT_NE(nullptr, effect.get()); - - Return 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 effectsFactory; - sp effect; -}; - -void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) { - Uuid effectUuid; - findEffectInstance(type, &effectUuid); - Return ret = effectsFactory->createEffect( - effectUuid, 1 /*session*/, 1 /*ioHandle*/, - [&](Result r, const sp& 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 ret = effectsFactory->getAllDescriptors( - [&](Result r, const hidl_vec& 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 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(currentConfig.outputCfg.channels))); - *channelCount = audio_channel_count_from_out_mask( - static_cast(currentConfig.outputCfg.channels)); -} - -TEST_F(AudioEffectHidlTest, Close) { - description("Verify that an effect can be closed"); - Return 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 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 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 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 ret = - effect->getConfigReverse([&](Result, const EffectConfig&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { - description("Verify that GetSupportedAuxChannelsConfigs does not crash"); - Return ret = effect->getSupportedAuxChannelsConfigs( - 0, [&](Result, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) { - description("Verify that GetAuxChannelsConfig does not crash"); - Return ret = effect->getAuxChannelsConfig( - [&](Result, const EffectAuxChannelsConfig&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) { - description("Verify that SetAuxChannelsConfig does not crash"); - Return 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 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 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 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 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 volumes; - volumes.resize(channelCount); - for (uint32_t i = 0; i < channelCount; ++i) { - volumes[i] = 0; - } - Result retval = Result::NOT_INITIALIZED; - Return ret = effect->setAndGetVolume( - volumes, [&](Result r, const hidl_vec&) { 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 volumes; - volumes.resize(channelCount); - for (uint32_t i = 0; i < channelCount; ++i) { - volumes[i] = 0; - } - Return 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 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 ret = - effect->setConfigReverse(EffectConfig(), nullptr, nullptr); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetInputDevice) { - description("Verify that SetInputDevice does not crash"); - Return ret = effect->setInputDevice(mkBitfield(AudioDevice::IN_BUILTIN_MIC)); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetAudioSource) { - description("Verify that SetAudioSource does not crash"); - Return 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(AudioHandleConsts::AUDIO_IO_HANDLE_NONE); - Return 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 ret = effect->prepareForProcessing( - [&](Result r, const MQDescriptorSync&) { retval = r; }); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, retval); -} - -TEST_F(AudioEffectHidlTest, SetProcessBuffers) { - description("Verify that SetProcessBuffers works for an effect"); - sp ashmem = IAllocator::getService("ashmem"); - ASSERT_NE(nullptr, ashmem.get()); - bool success = false; - AudioBuffer buffer; - Return 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 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 ret = effect->command(0, hidl_vec(), 0, - [&](int32_t, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetParameter) { - description("Verify that SetParameter does not crash"); - Return ret = - effect->setParameter(hidl_vec(), hidl_vec()); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetParameter) { - description("Verify that GetParameter does not crash"); - Return ret = effect->getParameter( - hidl_vec(), 0, [&](Result, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) { - description("Verify that GetSupportedConfigsForFeature does not crash"); - Return ret = effect->getSupportedConfigsForFeature( - 0, 0, 0, [&](Result, uint32_t, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) { - description("Verify that GetCurrentConfigForFeature does not crash"); - Return ret = effect->getCurrentConfigForFeature( - 0, 0, [&](Result, const hidl_vec&) {}); - EXPECT_TRUE(ret.isOk()); -} - -TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) { - description("Verify that SetCurrentConfigForFeature does not crash"); - Return ret = - effect->setCurrentConfigForFeature(0, hidl_vec()); - 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 equalizer; -}; - -void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) { - Result retval = Result::NOT_INITIALIZED; - Return 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 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 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 ret = equalizer->getPresetNames( - [&](Result r, const hidl_vec& 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 ret = equalizer->setBandLevel(i, levels[j]); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Result retval = Result::NOT_INITIALIZED; - int16_t actualLevel; - Return 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 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 ret = equalizer->setCurrentPreset(i); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Result retval = Result::NOT_INITIALIZED; - uint16_t actualPreset = 0xffff; - Return 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 ret = equalizer->setAllProperties(props); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - Return 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 enhancer; -}; - -TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { - description( - "Verify that manipulating the target gain works for Loudness Enhancer " - "effect"); - const int32_t gain = 100; - Return ret = enhancer->setTargetGain(gain); - EXPECT_TRUE(ret.isOk()); - EXPECT_EQ(Result::OK, ret); - int32_t actualGain = 0; - Result retval; - Return 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/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..ef467c9a54 --- /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 getStream(); + } + + public static class AudioEffectsConf.Preprocess { + ctor public AudioEffectsConf.Preprocess(); + method public java.util.List 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 getEffectProxy_optional(); + method public java.util.List getEffect_optional(); + } + + public class LibrariesType { + ctor public LibrariesType(); + method public java.util.List 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 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 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 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 similarity index 91% rename from audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.impl.h rename to audio/effect/all-versions/default/AcousticEchoCancelerEffect.cpp index 8ad80a22a0..137ea246f6 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 +#define LOG_TAG "AEC_Effect_HAL" + +#include "AcousticEchoCancelerEffect.h" #include #include @@ -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 AcousticEchoCancelerEffect::init() { return mEffect->init(); } @@ -163,7 +165,12 @@ Return AcousticEchoCancelerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAcousticEchoCancelerEffect +Return AcousticEchoCancelerEffect::debug(const hidl_handle& fd, + const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IAcousticEchoCancelerEffect // follow. Return AcousticEchoCancelerEffect::setEchoDelay(uint32_t echoDelayMs) { return mEffect->setParam(AEC_PARAM_ECHO_DELAY, echoDelayMs); @@ -174,7 +181,7 @@ Return 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 similarity index 83% rename from audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.h rename to audio/effect/all-versions/default/AcousticEchoCancelerEffect.h index 852cb3fd15..971f64de80 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -83,9 +88,10 @@ struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; // Methods from - // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAcousticEchoCancelerEffect follow. + // ::android::hardware::audio::effect::CPP_VERSION::IAcousticEchoCancelerEffect follow. Return setEchoDelay(uint32_t echoDelayMs) override; Return getEchoDelay(getEchoDelay_cb _hidl_cb) override; @@ -96,8 +102,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 similarity index 94% rename from audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.impl.h rename to 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 +#include "AudioBufferManager.h" #include @@ -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 similarity index 75% rename from audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.h rename to 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 +#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 @@ -24,14 +27,14 @@ #include #include -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 { bool wrap(const AudioBuffer& buffer, sp* 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 { }; } // 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 similarity index 93% rename from audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.impl.h rename to audio/effect/all-versions/default/AutomaticGainControlEffect.cpp index e2e751e86b..655a4cd0b1 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 +#define LOG_TAG "AGC_Effect_HAL" + +#include "AutomaticGainControlEffect.h" #include @@ -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 AutomaticGainControlEffect::init() { return mEffect->init(); } @@ -176,7 +178,12 @@ Return AutomaticGainControlEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAutomaticGainControlEffect +Return AutomaticGainControlEffect::debug(const hidl_handle& fd, + const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IAutomaticGainControlEffect // follow. Return AutomaticGainControlEffect::setTargetLevel(int16_t targetLevelMb) { return mEffect->setParam(AGC_PARAM_TARGET_LEVEL, targetLevelMb); @@ -219,7 +226,7 @@ Return 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 similarity index 86% rename from audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.h rename to audio/effect/all-versions/default/AutomaticGainControlEffect.h index 5ac43eb9bc..67e260aa20 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -85,9 +90,10 @@ struct AutomaticGainControlEffect : public IAutomaticGainControlEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; // Methods from - // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAutomaticGainControlEffect follow. + // ::android::hardware::audio::effect::CPP_VERSION::IAutomaticGainControlEffect follow. Return setTargetLevel(int16_t targetLevelMb) override; Return getTargetLevel(getTargetLevel_cb _hidl_cb) override; Return setCompGain(int16_t compGainMb) override; @@ -110,8 +116,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 similarity index 92% rename from audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.impl.h rename to audio/effect/all-versions/default/BassBoostEffect.cpp index 7bcb4a3497..04fd48615a 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 +#define LOG_TAG "BassBoost_HAL" + +#include "BassBoostEffect.h" #include #include @@ -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 BassBoostEffect::init() { return mEffect->init(); } @@ -159,7 +161,11 @@ Return BassBoostEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IBassBoostEffect follow. +Return BassBoostEffect::debug(const hidl_handle& fd, const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IBassBoostEffect follow. Return BassBoostEffect::isStrengthSupported(isStrengthSupported_cb _hidl_cb) { return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH_SUPPORTED, _hidl_cb); } @@ -173,7 +179,7 @@ Return 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 similarity index 84% rename from audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.h rename to audio/effect/all-versions/default/BassBoostEffect.h index 29173ddebe..b89bb2212f 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 +#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 + +#include "Effect.h" #include @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -83,8 +90,9 @@ struct BassBoostEffect : public IBassBoostEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IBassBoostEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IBassBoostEffect follow. Return isStrengthSupported(isStrengthSupported_cb _hidl_cb) override; Return setStrength(uint16_t strength) override; Return getStrength(getStrength_cb _hidl_cb) override; @@ -96,8 +104,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 similarity index 82% rename from audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h rename to 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 +#include "Conversions.h" +#include "HidlUtils.h" #include #include #include -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(halDescriptor.flags); + descriptor->flags = EnumBitfield(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 similarity index 71% rename from audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.h rename to 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 +#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 @@ -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 similarity index 92% rename from audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.impl.h rename to audio/effect/all-versions/default/DownmixEffect.cpp index abef10ea09..c001a5f4dc 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 +#define LOG_TAG "Downmix_HAL" + +#include "DownmixEffect.h" #include #include @@ -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 DownmixEffect::init() { return mEffect->init(); } @@ -159,7 +161,11 @@ Return DownmixEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IDownmixEffect follow. +Return DownmixEffect::debug(const hidl_handle& fd, const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IDownmixEffect follow. Return DownmixEffect::setType(IDownmixEffect::Type preset) { return mEffect->setParam(DOWNMIX_PARAM_TYPE, static_cast(preset)); } @@ -172,7 +178,7 @@ Return 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 similarity index 84% rename from audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.h rename to audio/effect/all-versions/default/DownmixEffect.h index 3e3aa78477..40e462ea41 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -83,8 +88,9 @@ struct DownmixEffect : public IDownmixEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IDownmixEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IDownmixEffect follow. Return setType(IDownmixEffect::Type preset) override; Return getType(getType_cb _hidl_cb) override; @@ -95,8 +101,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 similarity index 97% rename from audio/effect/all-versions/default/include/effect/all-versions/default/Effect.impl.h rename to audio/effect/all-versions/default/Effect.cpp index 61c9805663..3c0d8788ab 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 +#include + +#define LOG_TAG "EffectHAL" +#define ATRACE_TAG ATRACE_TAG_AUDIO + +#include "Conversions.h" +#include "Effect.h" +#include "common/all-versions/default/EffectMap.h" #include @@ -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 Effect::init() { return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT"); } @@ -706,8 +710,16 @@ Return Effect::close() { return Result::OK; } +Return Effect::debug(const hidl_handle& fd, const hidl_vec& /* options */) { + if (fd.getNativeHandle() != nullptr && fd->numFds == 1) { + uint32_t cmdData = fd->data[0]; + (void)sendCommand(EFFECT_CMD_DUMP, "DUMP", sizeof(cmdData), &cmdData); + } + return Void(); +} + } // 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 similarity index 89% rename from audio/effect/all-versions/default/include/effect/all-versions/default/Effect.h rename to audio/effect/all-versions/default/Effect.h index b546e0eb32..3d99a0e42f 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 +#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 #include @@ -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 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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -107,6 +101,7 @@ struct Effect : public IEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; // Utility methods for extending interfaces. template @@ -234,8 +229,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 similarity index 87% rename from audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h rename to 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 +#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 #include @@ -30,15 +46,15 @@ #include #include -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 EffectsFactory::dispatchEffectInstanceCreation(const effect_descriptor_t& halDescriptor, effect_handle_t handle) { @@ -69,7 +85,7 @@ sp 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 EffectsFactory::getAllDescriptors(getAllDescriptors_cb _hidl_cb) { Result retval(Result::OK); hidl_vec result; @@ -184,12 +200,12 @@ Return 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 similarity index 70% rename from audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.h rename to 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 +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_EFFECTSFACTORY_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_EFFECTSFACTORY_H + +#include + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h) + +#include #include #include @@ -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 getAllDescriptors(getAllDescriptors_cb _hidl_cb) override; Return getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) override; Return createEffect(const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb) override; - Return debugDump(const hidl_handle& fd); //< in V2_0::IEffectsFactory only, alias of debug + Return debugDump( + const hidl_handle& fd); //< in CPP_VERSION::IEffectsFactory only, alias of debug Return debug(const hidl_handle& fd, const hidl_vec& 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 similarity index 95% rename from audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.impl.h rename to audio/effect/all-versions/default/EnvironmentalReverbEffect.cpp index 39a4092e8c..78122d4b79 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 +#define LOG_TAG "EnvReverb_HAL" +#include + +#include "EnvironmentalReverbEffect.h" #include @@ -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 EnvironmentalReverbEffect::init() { return mEffect->init(); } @@ -190,7 +193,12 @@ Return EnvironmentalReverbEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEnvironmentalReverbEffect +Return EnvironmentalReverbEffect::debug(const hidl_handle& fd, + const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEnvironmentalReverbEffect // follow. Return EnvironmentalReverbEffect::setBypass(bool bypass) { return mEffect->setParam(REVERB_PARAM_BYPASS, bypass); @@ -297,7 +305,7 @@ Return 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 similarity index 82% rename from audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.h rename to audio/effect/all-versions/default/EnvironmentalReverbEffect.h index d2f8cc3a84..bb422d46bc 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 +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_ENVIRONMENTALREVERBEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_ENVIRONMENTALREVERBEFFECT_H + +#include + +#include PATH(android/hardware/audio/effect/FILE_VERSION/IEnvironmentalReverbEffect.h) + +#include "Effect.h" #include @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -95,9 +92,10 @@ struct EnvironmentalReverbEffect : public IEnvironmentalReverbEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; // Methods from - // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEnvironmentalReverbEffect follow. + // ::android::hardware::audio::effect::CPP_VERSION::IEnvironmentalReverbEffect follow. Return setBypass(bool bypass) override; Return getBypass(getBypass_cb _hidl_cb) override; Return setRoomLevel(int16_t roomLevel) override; @@ -136,8 +134,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 similarity index 95% rename from audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.impl.h rename to audio/effect/all-versions/default/EqualizerEffect.cpp index db6bed8d2e..1b983ec5eb 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 +#define LOG_TAG "Equalizer_HAL" + +#include "EqualizerEffect.h" #include @@ -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 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 EqualizerEffect::init() { return mEffect->init(); } @@ -182,7 +184,11 @@ Return EqualizerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEqualizerEffect follow. +Return EqualizerEffect::debug(const hidl_handle& fd, const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEqualizerEffect follow. Return EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb) { return mEffect->getIntegerParam(EQ_PARAM_NUM_BANDS, _hidl_cb); } @@ -285,7 +291,7 @@ Return 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 similarity index 81% rename from audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.h rename to audio/effect/all-versions/default/EqualizerEffect.h index de520521fa..b1cbefd1f6 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -97,8 +92,9 @@ struct EqualizerEffect : public IEqualizerEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEqualizerEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEqualizerEffect follow. Return getNumBands(getNumBands_cb _hidl_cb) override; Return getLevelRange(getLevelRange_cb _hidl_cb) override; Return setBandLevel(uint16_t band, int16_t level) override; @@ -124,8 +120,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 similarity index 92% rename from audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.impl.h rename to audio/effect/all-versions/default/LoudnessEnhancerEffect.cpp index 88210e954b..ebd519766e 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 +#define LOG_TAG "LoudnessEnhancer_HAL" + +#include "LoudnessEnhancerEffect.h" #include @@ -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 LoudnessEnhancerEffect::init() { return mEffect->init(); } @@ -162,7 +164,12 @@ Return LoudnessEnhancerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::ILoudnessEnhancerEffect +Return LoudnessEnhancerEffect::debug(const hidl_handle& fd, + const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::ILoudnessEnhancerEffect // follow. Return LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb) { return mEffect->setParam(LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB, targetGainMb); @@ -182,7 +189,7 @@ Return 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 similarity index 77% rename from audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.h rename to audio/effect/all-versions/default/LoudnessEnhancerEffect.h index b59b077e76..8baf12839d 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -93,8 +88,9 @@ struct LoudnessEnhancerEffect : public ILoudnessEnhancerEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::ILoudnessEnhancerEffect + // Methods from ::android::hardware::audio::effect::CPP_VERSION::ILoudnessEnhancerEffect // follow. Return setTargetGain(int32_t targetGainMb) override; Return getTargetGain(getTargetGain_cb _hidl_cb) override; @@ -106,8 +102,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 similarity index 93% rename from audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.impl.h rename to audio/effect/all-versions/default/NoiseSuppressionEffect.cpp index f32399c51c..d01bbe5e94 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 +#define LOG_TAG "NS_Effect_HAL" + +#include "NoiseSuppressionEffect.h" #include @@ -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(properties.type); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow. +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow. Return NoiseSuppressionEffect::init() { return mEffect->init(); } @@ -171,7 +173,12 @@ Return NoiseSuppressionEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::INoiseSuppressionEffect +Return NoiseSuppressionEffect::debug(const hidl_handle& fd, + const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::INoiseSuppressionEffect // follow. Return NoiseSuppressionEffect::setSuppressionLevel(INoiseSuppressionEffect::Level level) { return mEffect->setParam(NS_PARAM_LEVEL, static_cast(level)); @@ -212,7 +219,7 @@ Return 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 similarity index 79% rename from audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.h rename to audio/effect/all-versions/default/NoiseSuppressionEffect.h index af1635b717..c49bf7bd6c 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -95,8 +90,9 @@ struct NoiseSuppressionEffect : public INoiseSuppressionEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::INoiseSuppressionEffect + // Methods from ::android::hardware::audio::effect::CPP_VERSION::INoiseSuppressionEffect // follow. Return setSuppressionLevel(INoiseSuppressionEffect::Level level) override; Return getSuppressionLevel(getSuppressionLevel_cb _hidl_cb) override; @@ -118,8 +114,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 similarity index 100% rename from audio/core/2.0/default/OWNERS rename to 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 similarity index 92% rename from audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.impl.h rename to audio/effect/all-versions/default/PresetReverbEffect.cpp index eab68fb703..4a2a3a42a9 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 +#define LOG_TAG "PresetReverb_HAL" + +#include "PresetReverbEffect.h" #include #include @@ -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 PresetReverbEffect::init() { return mEffect->init(); } @@ -159,7 +161,12 @@ Return PresetReverbEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IPresetReverbEffect follow. +Return PresetReverbEffect::debug(const hidl_handle& fd, + const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IPresetReverbEffect follow. Return PresetReverbEffect::setPreset(IPresetReverbEffect::Preset preset) { return mEffect->setParam(REVERB_PARAM_PRESET, static_cast(preset)); } @@ -172,7 +179,7 @@ Return 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 similarity index 77% rename from audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.h rename to audio/effect/all-versions/default/PresetReverbEffect.h index 1a91ab49b2..58a6829a83 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -93,8 +88,9 @@ struct PresetReverbEffect : public IPresetReverbEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IPresetReverbEffect + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IPresetReverbEffect // follow. Return setPreset(IPresetReverbEffect::Preset preset) override; Return getPreset(getPreset_cb _hidl_cb) override; @@ -106,8 +102,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 similarity index 94% rename from audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.impl.h rename to audio/effect/all-versions/default/VirtualizerEffect.cpp index 23b09a89dd..1b69a9033c 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 +#define LOG_TAG "Virtualizer_HAL" + +#include "VirtualizerEffect.h" #include @@ -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 VirtualizerEffect::init() { return mEffect->init(); } @@ -171,7 +173,11 @@ Return VirtualizerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVirtualizerEffect follow. +Return VirtualizerEffect::debug(const hidl_handle& fd, const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IVirtualizerEffect follow. Return VirtualizerEffect::isStrengthSupported() { bool halSupported = false; mEffect->getParam(VIRTUALIZER_PARAM_STRENGTH_SUPPORTED, halSupported); @@ -224,7 +230,7 @@ Return 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 similarity index 76% rename from audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.h rename to audio/effect/all-versions/default/VirtualizerEffect.h index c0d5a0034d..c630b2e353 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -95,8 +89,9 @@ struct VirtualizerEffect : public IVirtualizerEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVirtualizerEffect + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IVirtualizerEffect // follow. Return isStrengthSupported() override; Return setStrength(uint16_t strength) override; @@ -116,8 +111,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 similarity index 94% rename from audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.impl.h rename to audio/effect/all-versions/default/VisualizerEffect.cpp index 9f2195b5cb..ae533bf946 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 +#define LOG_TAG "Visualizer_HAL" + +#include "VisualizerEffect.h" #include #include @@ -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 VisualizerEffect::init() { return mEffect->init(); } @@ -160,7 +162,11 @@ Return VisualizerEffect::close() { return mEffect->close(); } -// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVisualizerEffect follow. +Return VisualizerEffect::debug(const hidl_handle& fd, const hidl_vec& options) { + return mEffect->debug(fd, options); +} + +// Methods from ::android::hardware::audio::effect::CPP_VERSION::IVisualizerEffect follow. Return VisualizerEffect::setCaptureSize(uint16_t captureSize) { Result retval = mEffect->setParam(VISUALIZER_PARAM_CAPTURE_SIZE, captureSize); if (retval == Result::OK) { @@ -247,7 +253,7 @@ Return 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 similarity index 79% rename from audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.h rename to audio/effect/all-versions/default/VisualizerEffect.h index 114d3b7ae5..315f84452a 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 +#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 @@ -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 init() override; Return setConfig( const EffectConfig& config, const sp& inputBufferProvider, @@ -93,8 +88,9 @@ struct VisualizerEffect : public IVisualizerEffect { Return setCurrentConfigForFeature(uint32_t featureId, const hidl_vec& configData) override; Return close() override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; - // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVisualizerEffect follow. + // Methods from ::android::hardware::audio::effect::CPP_VERSION::IVisualizerEffect follow. Return setCaptureSize(uint16_t captureSize) override; Return getCaptureSize(getCaptureSize_cb _hidl_cb) override; Return setScalingMode(IVisualizerEffect::ScalingMode scalingMode) override; @@ -115,8 +111,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 similarity index 79% rename from audio/effect/2.0/vts/OWNERS rename to 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/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp new file mode 100644 index 0000000000..cccb5c86aa --- /dev/null +++ b/audio/effect/all-versions/vts/functional/Android.bp @@ -0,0 +1,78 @@ +// +// 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. +// + +cc_defaults { + name: "VtsHalAudioEffectTargetTest_default", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "VtsHalAudioEffectTargetTest.cpp", + "ValidateAudioEffectsConfiguration.cpp" + ], + static_libs: [ + "android.hardware.audio.common.test.utility", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libeffectsconfig", + "libxml2", + ], + header_libs: [ + "android.hardware.audio.common.util@all-versions", + ], + 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 similarity index 68% rename from audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp rename to 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 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 +#include + +#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 +#include + +#include + +#include +#include + +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(); } +}; + +// The main test class for Audio Effects Factory HIDL HAL. +class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + void SetUp() override { + effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService( + AudioEffectsFactoryHidlEnvironment::Instance()->getServiceName()); + ASSERT_NE(effectsFactory, nullptr); + } + + void TearDown() override { effectsFactory.clear(); } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp effectsFactory; +}; + +TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { + description("Verify that EnumerateEffects returns at least one effect"); + Result retval = Result::NOT_INITIALIZED; + size_t effectCount = 0; + Return ret = + effectsFactory->getAllDescriptors([&](Result r, const hidl_vec& 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 ret = + effectsFactory->getAllDescriptors([&](Result r, const hidl_vec& 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 effect; + ret = effectsFactory->createEffect( + effectUuid, 1 /*session*/, 1 /*ioHandle*/, + [&](Result r, const sp& 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 allDescriptors; + Return ret = + effectsFactory->getAllDescriptors([&](Result r, const hidl_vec& 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 ret = effectsFactory->debugDump(hidl_handle()); +#elif MAJOR_VERSION >= 4 + Return 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{{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{{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(); + ASSERT_NE(nullptr, effectsFactory.get()); + + findAndCreateEffect(getEffectType()); + ASSERT_NE(nullptr, effect.get()); + + Return 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 effectsFactory; + sp effect; +}; + +void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) { + Uuid effectUuid; + findEffectInstance(type, &effectUuid); + Return ret = effectsFactory->createEffect( + effectUuid, 1 /*session*/, 1 /*ioHandle*/, + [&](Result r, const sp& 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 ret = + effectsFactory->getAllDescriptors([&](Result r, const hidl_vec& 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 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(currentConfig.outputCfg.channels))); + *channelCount = audio_channel_count_from_out_mask( + static_cast(currentConfig.outputCfg.channels)); +} + +TEST_F(AudioEffectHidlTest, Close) { + description("Verify that an effect can be closed"); + Return 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 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 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 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 ret = effect->getConfigReverse([&](Result, const EffectConfig&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { + description("Verify that GetSupportedAuxChannelsConfigs does not crash"); + Return ret = effect->getSupportedAuxChannelsConfigs( + 0, [&](Result, const hidl_vec&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) { + description("Verify that GetAuxChannelsConfig does not crash"); + Return ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) { + description("Verify that SetAuxChannelsConfig does not crash"); + Return 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 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 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 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 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 volumes; + volumes.resize(channelCount); + for (uint32_t i = 0; i < channelCount; ++i) { + volumes[i] = 0; + } + Result retval = Result::NOT_INITIALIZED; + Return ret = + effect->setAndGetVolume(volumes, [&](Result r, const hidl_vec&) { 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 volumes; + volumes.resize(channelCount); + for (uint32_t i = 0; i < channelCount; ++i) { + volumes[i] = 0; + } + Return 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 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 ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetInputDevice) { + description("Verify that SetInputDevice does not crash"); + Return ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC)); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetAudioSource) { + description("Verify that SetAudioSource does not crash"); + Return 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(AudioHandleConsts::AUDIO_IO_HANDLE_NONE); + Return 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 ret = effect->prepareForProcessing( + [&](Result r, const MQDescriptorSync&) { retval = r; }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); +} + +TEST_F(AudioEffectHidlTest, SetProcessBuffers) { + description("Verify that SetProcessBuffers works for an effect"); + sp ashmem = IAllocator::getService("ashmem"); + ASSERT_NE(nullptr, ashmem.get()); + bool success = false; + AudioBuffer buffer; + Return 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 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 ret = + effect->command(0, hidl_vec(), 0, [&](int32_t, const hidl_vec&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetParameter) { + description("Verify that SetParameter does not crash"); + Return ret = effect->setParameter(hidl_vec(), hidl_vec()); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetParameter) { + description("Verify that GetParameter does not crash"); + Return ret = + effect->getParameter(hidl_vec(), 0, [&](Result, const hidl_vec&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) { + description("Verify that GetSupportedConfigsForFeature does not crash"); + Return ret = effect->getSupportedConfigsForFeature( + 0, 0, 0, [&](Result, uint32_t, const hidl_vec&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) { + description("Verify that GetCurrentConfigForFeature does not crash"); + Return ret = + effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec&) {}); + EXPECT_TRUE(ret.isOk()); +} + +TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) { + description("Verify that SetCurrentConfigForFeature does not crash"); + Return ret = effect->setCurrentConfigForFeature(0, hidl_vec()); + 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 equalizer; +}; + +void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) { + Result retval = Result::NOT_INITIALIZED; + Return 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 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 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 ret = equalizer->getPresetNames([&](Result r, const hidl_vec& 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 ret = equalizer->setBandLevel(i, levels[j]); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Result retval = Result::NOT_INITIALIZED; + int16_t actualLevel; + Return 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 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 ret = equalizer->setCurrentPreset(i); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Result retval = Result::NOT_INITIALIZED; + uint16_t actualPreset = 0xffff; + Return 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 ret = equalizer->setAllProperties(props); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Return 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 enhancer; +}; + +TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { + description( + "Verify that manipulating the target gain works for Loudness Enhancer " + "effect"); + const int32_t gain = 100; + Return ret = enhancer->setTargetGain(gain); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + int32_t actualGain = 0; + Result retval; + Return 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..3cf4489e9a --- /dev/null +++ b/automotive/OWNERS @@ -0,0 +1,4 @@ +randolphs@google.com +pirozzoj@google.com +twasilczyk@google.com +pfg@google.com diff --git a/automotive/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal index e1193d030c..ee51e7e994 100644 --- a/automotive/evs/1.0/IEvsEnumerator.hal +++ b/automotive/evs/1.0/IEvsEnumerator.hal @@ -57,7 +57,8 @@ interface IEvsEnumerator { * * There can be at most one EVS display object for the system and this function * requests access to it. If the EVS display is not available or is already in use, - * a null pointer is returned. + * the old instance shall be closed and give the new caller exclusive + * access. * When done using the display, the caller may release it by calling closeDisplay(). * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the * resources may not be released right away due to asynchronos behavior in the hardware binder. diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.cpp b/automotive/evs/1.0/vts/functional/FormatConvert.cpp index 1e8929d6b7..3d82d32cac 100644 --- a/automotive/evs/1.0/vts/functional/FormatConvert.cpp +++ b/automotive/evs/1.0/vts/functional/FormatConvert.cpp @@ -38,7 +38,8 @@ static inline float clamp(float v, float min, float max) { } -static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) { +static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin, + bool bgrxFormat = false) { // Don't use this if you want to see the best performance. :) // Better to do this in a pixel shader if we really have to, but on actual // embedded hardware we expect to be able to texture directly from the YUV data @@ -52,16 +53,24 @@ static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f); unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f); - return (R ) | - (G << 8) | - (B << 16) | - 0xFF000000; // Fill the alpha channel with ones + if (!bgrxFormat) { + return (R ) | + (G << 8) | + (B << 16) | + 0xFF000000; // Fill the alpha channel with ones + } else { + return (R << 16) | + (G << 8) | + (B ) | + 0xFF000000; // Fill the alpha channel with ones + } } void copyNV21toRGB32(unsigned width, unsigned height, uint8_t* src, - uint32_t* dst, unsigned dstStridePixels) + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved // U/V array. It assumes an even width and height for the overall image, and a horizontal @@ -84,7 +93,7 @@ void copyNV21toRGB32(unsigned width, unsigned height, for (unsigned c = 0; c < width; c++) { unsigned uCol = (c & ~1); // uCol is always even and repeats 1:2 with Y values unsigned vCol = uCol | 1; // vCol is always odd - rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]); + rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol], bgrxFormat); } } } @@ -92,7 +101,8 @@ void copyNV21toRGB32(unsigned width, unsigned height, void copyYV12toRGB32(unsigned width, unsigned height, uint8_t* src, - uint32_t* dst, unsigned dstStridePixels) + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image, @@ -118,7 +128,7 @@ void copyYV12toRGB32(unsigned width, unsigned height, uint32_t* rowDest = dst + r*dstStridePixels; for (unsigned c = 0; c < width; c++) { - rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]); + rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c], bgrxFormat); } } } @@ -126,7 +136,8 @@ void copyYV12toRGB32(unsigned width, unsigned height, void copyYUYVtoRGB32(unsigned width, unsigned height, uint8_t* src, unsigned srcStridePixels, - uint32_t* dst, unsigned dstStridePixels) + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat) { uint32_t* srcWords = (uint32_t*)src; @@ -144,8 +155,8 @@ void copyYUYVtoRGB32(unsigned width, unsigned height, uint8_t V = (srcPixel >> 24) & 0xFF; // On the RGB output, we're writing one pixel at a time - *(dst+0) = yuvToRgbx(Y1, U, V); - *(dst+1) = yuvToRgbx(Y2, U, V); + *(dst+0) = yuvToRgbx(Y1, U, V, bgrxFormat); + *(dst+1) = yuvToRgbx(Y2, U, V, bgrxFormat); dst += 2; } @@ -156,6 +167,30 @@ void copyYUYVtoRGB32(unsigned width, unsigned height, } +void copyNV21toBGR32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels) +{ + return copyNV21toRGB32(width, height, src, dst, dstStridePixels, true); +} + + +void copyYV12toBGR32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels) +{ + return copyYV12toRGB32(width, height, src, dst, dstStridePixels, true); +} + + +void copyYUYVtoBGR32(unsigned width, unsigned height, + uint8_t* src, unsigned srcStridePixels, + uint32_t* dst, unsigned dstStridePixels) +{ + return copyYUYVtoRGB32(width, height, src, srcStridePixels, dst, dstStridePixels, true); +} + + void copyMatchedInterleavedFormats(unsigned width, unsigned height, void* src, unsigned srcStridePixels, void* dst, unsigned dstStridePixels, diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.h b/automotive/evs/1.0/vts/functional/FormatConvert.h index 3ff1eec12d..4a94f996d0 100644 --- a/automotive/evs/1.0/vts/functional/FormatConvert.h +++ b/automotive/evs/1.0/vts/functional/FormatConvert.h @@ -21,30 +21,44 @@ #include -// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx values. -// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved +// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx +// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved // U/V array. It assumes an even width and height for the overall image, and a horizontal // stride that is an even multiple of 16 bytes for both the Y and UV arrays. void copyNV21toRGB32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat = false); + +void copyNV21toBGR32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst, unsigned dstStridePixels); -// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx values. +// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values. // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image, // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U, // and V arrays. void copyYV12toRGB32(unsigned width, unsigned height, + uint8_t* src, + uint32_t* dst, unsigned dstStridePixels, + bool bgrxFormat = false); + +void copyYV12toBGR32(unsigned width, unsigned height, uint8_t* src, uint32_t* dst, unsigned dstStridePixels); - -// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx values. -// The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved +// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx +// values. The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved // U/V array. It assumes an even width and height for the overall image, and a horizontal // stride that is an even multiple of 16 bytes for both the Y and UV arrays. void copyYUYVtoRGB32(unsigned width, unsigned height, + uint8_t* src, unsigned srcStrideBytes, + uint32_t* dst, unsigned dstStrideBytes, + bool bgrxFormat = false); + +void copyYUYVtoBGR32(unsigned width, unsigned height, uint8_t* src, unsigned srcStrideBytes, uint32_t* dst, unsigned dstStrideBytes); diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.cpp b/automotive/evs/1.0/vts/functional/FrameHandler.cpp index a69f72be49..bc3790f385 100644 --- a/automotive/evs/1.0/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.0/vts/functional/FrameHandler.cpp @@ -137,6 +137,10 @@ Return FrameHandler::deliverFrame(const BufferDesc& bufferArg) { // Signal that the last frame has been received and the stream is stopped timeToStop = true; } else { + // Store a dimension of a received frame. + mFrameWidth = bufferArg.width; + mFrameHeight = bufferArg.height; + // If we were given an opened display at construction time, then send the received // image back down the camera. if (mDisplay.get()) { @@ -231,16 +235,12 @@ bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer, uint8_t* srcPixels = nullptr; src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels); - // Lock our target buffer for writing (should be RGBA8888 format) + // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format) uint32_t* tgtPixels = nullptr; tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels); if (srcPixels && tgtPixels) { - if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) { - // We always expect 32 bit RGB for the display output for now. Is there a need for 565? - ALOGE("Diplay buffer is always expected to be 32bit RGBA"); - success = false; - } else { + if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) { if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21 copyNV21toRGB32(width, height, srcPixels, @@ -258,7 +258,36 @@ bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer, srcPixels, srcBuffer.stride, tgtPixels, tgtBuffer.stride, tgtBuffer.pixelSize); + } else { + ALOGE("Camera buffer format is not supported"); + success = false; } + } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) { + if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21 + copyNV21toBGR32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); + } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12 + copyYV12toBGR32(width, height, + srcPixels, + tgtPixels, tgtBuffer.stride); + } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV + copyYUYVtoBGR32(width, height, + srcPixels, srcBuffer.stride, + tgtPixels, tgtBuffer.stride); + } else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA + copyMatchedInterleavedFormats(width, height, + srcPixels, srcBuffer.stride, + tgtPixels, tgtBuffer.stride, + tgtBuffer.pixelSize); + } else { + ALOGE("Camera buffer format is not supported"); + success = false; + } + } else { + // We always expect 32 bit RGB for the display output for now. Is there a need for 565? + ALOGE("Diplay buffer is always expected to be 32bit RGBA"); + success = false; } } else { ALOGE("Failed to lock buffer contents for contents transfer"); @@ -274,3 +303,13 @@ bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer, return success; } + +void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) { + if (width) { + *width = mFrameWidth; + } + + if (height) { + *height = mFrameHeight; + } +} diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.h b/automotive/evs/1.0/vts/functional/FrameHandler.h index 17a39803fa..3f6103d8ac 100644 --- a/automotive/evs/1.0/vts/functional/FrameHandler.h +++ b/automotive/evs/1.0/vts/functional/FrameHandler.h @@ -61,6 +61,7 @@ public: void waitForFrameCount(unsigned frameCount); void getFramesCounters(unsigned* received, unsigned* displayed); + void getFrameDimension(unsigned* width, unsigned* height); private: // Implementation for ::android::hardware::automotive::evs::V1_0::ICarCameraStream @@ -85,6 +86,8 @@ private: bool mRunning = false; unsigned mFramesReceived = 0; // Simple counter -- rolls over eventually! unsigned mFramesDisplayed = 0; // Simple counter -- rolls over eventually! + unsigned mFrameWidth = 0; + unsigned mFrameHeight = 0; }; diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp index d904ad06bf..f7580f02a8 100644 --- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp +++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp @@ -84,9 +84,12 @@ class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { // Make sure we can connect to the enumerator - pEnumerator = getService( - EvsHidlEnvironment::Instance()->getServiceName(kEnumeratorName)); + string service_name = + EvsHidlEnvironment::Instance()->getServiceName(kEnumeratorName); + pEnumerator = getService(service_name); ASSERT_NE(pEnumerator.get(), nullptr); + + mIsHwModule = !service_name.compare(kEnumeratorName); } virtual void TearDown() override {} @@ -114,12 +117,13 @@ protected: sp pEnumerator; // Every test needs access to the service std::vector cameraInfo; // Empty unless/until loadCameraList() is called + bool mIsHwModule; // boolean to tell current module under testing + // is HW module implementation. }; -// -// Tests start here... -// +// Test cases, their implementations, and corresponding requirements are +// documented at go/aae-evs-public-api-test. /* * CameraOpenClean: @@ -180,9 +184,14 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { ASSERT_NE(pCam, pCam2); ASSERT_NE(pCam2, nullptr); - // Verify that the old camera rejects calls - Return badResult = pCam->setMaxFramesInFlight(2); - EXPECT_EQ(EvsResult::OWNERSHIP_LOST, EvsResult(badResult)); + Return result = pCam->setMaxFramesInFlight(2); + if (mIsHwModule) { + // Verify that the old camera rejects calls via HW module. + EXPECT_EQ(EvsResult::OWNERSHIP_LOST, EvsResult(result)); + } else { + // default implementation supports multiple clients. + EXPECT_EQ(EvsResult::OK, EvsResult(result)); + } // Close the superceded camera pEnumerator->closeCamera(pCam); @@ -194,7 +203,8 @@ TEST_F(EvsHidlTest, CameraOpenAggressive) { } ); - // Leave the second camera dangling so it gets cleaned up by the destructor path + // Close the second camera instance + pEnumerator->closeCamera(pCam2); } // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests @@ -343,6 +353,11 @@ TEST_F(EvsHidlTest, CameraStreamPerformance) { printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds); ALOGI("Measured time to first frame %0.2f ms", timeToFirstFrame * kNanoToMilliseconds); + // Check aspect ratio + unsigned width = 0, height = 0; + frameHandler->getFrameDimension(&width, &height); + EXPECT_GE(width, height); + // Wait a bit, then ensure we get at least the required minimum number of frames sleep(5); nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); @@ -496,6 +511,96 @@ TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) { pEnumerator->closeDisplay(pDisplay); } + +/* + * MultiCameraStream: + * Verify that each client can start and stop video streams on the same + * underlying camera. + */ +TEST_F(EvsHidlTest, MultiCameraStream) { + ALOGI("Starting MultiCameraStream test"); + + if (mIsHwModule) { + // This test is not for HW module implementation. + return; + } + + // Get the camera list + loadCameraList(); + + // Test each reported camera + for (auto&& cam: cameraInfo) { + // Create two camera clients. + sp pCam0 = pEnumerator->openCamera(cam.cameraId); + ASSERT_NE(pCam0, nullptr); + + sp pCam1 = pEnumerator->openCamera(cam.cameraId); + ASSERT_NE(pCam1, nullptr); + + // Set up per-client frame receiver objects which will fire up its own thread + sp frameHandler0 = new FrameHandler(pCam0, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler0, nullptr); + + sp frameHandler1 = new FrameHandler(pCam1, cam, + nullptr, + FrameHandler::eAutoReturn); + ASSERT_NE(frameHandler1, nullptr); + + // Start the camera's video stream via client 0 + bool startResult = false; + startResult = frameHandler0->startStream() && + frameHandler1->startStream(); + ASSERT_TRUE(startResult); + + // Ensure the stream starts + frameHandler0->waitForFrameCount(1); + frameHandler1->waitForFrameCount(1); + + nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC); + + // Wait a bit, then ensure both clients get at least the required minimum number of frames + sleep(5); + nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + unsigned framesReceived0 = 0, framesReceived1 = 0; + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + framesReceived0 = framesReceived0 - 1; // Back out the first frame we already waited for + framesReceived1 = framesReceived1 - 1; // Back out the first frame we already waited for + nsecs_t runTime = end - firstFrame; + float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds); + float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds); + printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1); + ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1); + EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond); + EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond); + + // Shutdown one client + frameHandler0->shutdown(); + + // Read frame counters again + frameHandler0->getFramesCounters(&framesReceived0, nullptr); + frameHandler1->getFramesCounters(&framesReceived1, nullptr); + + // Wait a bit again + sleep(5); + unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0; + frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr); + frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr); + EXPECT_EQ(framesReceived0, framesReceivedAfterStop0); + EXPECT_LT(framesReceived1, framesReceivedAfterStop1); + + // Shutdown another + frameHandler1->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam0); + pEnumerator->closeCamera(pCam1); + } +} + + int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); diff --git a/automotive/evs/OWNERS b/automotive/evs/OWNERS new file mode 100644 index 0000000000..fec2a3ad33 --- /dev/null +++ b/automotive/evs/OWNERS @@ -0,0 +1,3 @@ +changyeon@google.com +haoxiangl@google.com +swan@google.com 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/common/include/vhal_v2_0/VmsUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h index 9e32bb5a89..d689e62061 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h @@ -19,6 +19,7 @@ #include #include +#include #include @@ -42,9 +43,25 @@ struct VmsLayer { int type; int subtype; int version; + bool operator==(const VmsLayer& layer) const { + return this->type == layer.type && this->subtype == layer.subtype && + this->version == layer.version; + } + + // Class for hash function + class VmsLayerHashFunction { + public: + // Hash of the variables is returned. + size_t operator()(const VmsLayer& layer) const { + return std::hash()(layer.type) ^ std::hash()(layer.type) ^ + std::hash()(layer.type); + } + }; }; struct VmsLayerAndPublisher { + VmsLayerAndPublisher(VmsLayer layer, int publisher_id) + : layer(layer), publisher_id(publisher_id) {} VmsLayer layer; int publisher_id; }; @@ -66,6 +83,15 @@ struct VmsLayerOffering { std::vector dependencies; }; +// A VmsOffers refers to a list of layers that can be published by the publisher +// with the specified publisher ID. +struct VmsOffers { + VmsOffers(int publisher_id, std::vector offerings) + : publisher_id(publisher_id), offerings(offerings) {} + int publisher_id; + std::vector offerings; +}; + // A VmsSubscriptionsState is delivered in response to a // VmsMessageType.SUBSCRIPTIONS_REQUEST or on the first SUBSCRIBE or last // UNSUBSCRIBE for a layer. It indicates which layers or associated_layers are @@ -81,6 +107,20 @@ struct VmsAvailabilityState { std::vector associated_layers; }; +// An enum to represent the result of parsing START_SESSION message from the VMS service. +enum VmsSessionStatus { + // When a new session is received, the client should acknowledge it with the correct + // IDs in the START_SESSION message. + kNewServerSession, + // When an acknowledgement it received, the client can start using the connection. + kAckToCurrentSession, + // Invalid message with either invalid format or unexpected data. + kInvalidMessage +}; + +// Creates an empty base VMS message with some pre-populated default fields. +std::unique_ptr createBaseVmsMessage(size_t message_size); + // Creates a VehiclePropValue containing a message of type // VmsMessageType.SUBSCRIBE, specifying to the VMS service // which layer to subscribe to. @@ -106,8 +146,7 @@ std::unique_ptr createUnsubscribeToPublisherMessage( // Creates a VehiclePropValue containing a message of type // VmsMessageType.OFFERING, specifying to the VMS service which layers are being // offered and their dependencies, if any. -std::unique_ptr createOfferingMessage( - const std::vector& offering); +std::unique_ptr createOfferingMessage(const VmsOffers& offers); // Creates a VehiclePropValue containing a message of type // VmsMessageType.AVAILABILITY_REQUEST. @@ -118,12 +157,26 @@ std::unique_ptr createAvailabilityRequest(); std::unique_ptr createSubscriptionsRequest(); // Creates a VehiclePropValue containing a message of type VmsMessageType.DATA. -// Returns a nullptr if the byte string in bytes is empty. +// Returns a nullptr if the vms_packet string in bytes is empty or if the layer_publisher +// information in VmsLayerAndPublisher format is missing the later or publisher +// information. // -// For example, to build a VehiclePropMessage containing a proto, the caller -// should convert the proto to a byte string using the SerializeToString proto -// API, then use this inteface to build the VehicleProperty. -std::unique_ptr createDataMessage(const std::string& bytes); +// For example, to build a VehiclePropValue message containing a proto, the caller +// should first convert the proto to a byte string (vms_packet) using the +// SerializeToString proto API. Then, it use this interface to build the VehicleProperty +// by passing publisher and layer information (layer_publisher) and the vms_packet. +std::unique_ptr createDataMessageWithLayerPublisherInfo( + const VmsLayerAndPublisher& layer_publisher, const std::string& vms_packet); + +// Creates a VehiclePropValue containing a message of type +// VmsMessageType.PUBLISHER_ID_REQUEST with the given publisher information. +// Returns a nullptr if the input is empty. +std::unique_ptr createPublisherIdRequest( + const std::string& vms_provider_description); + +// Creates a VehiclePropValue message of type VmsMessageType.START_SESSION. +std::unique_ptr createStartSessionMessage(const int service_id, + const int client_id); // Returns true if the VehiclePropValue pointed to by value contains a valid Vms // message, i.e. the VehicleProperty, VehicleArea, and VmsMessageType are all @@ -143,8 +196,40 @@ VmsMessageType parseMessageType(const VehiclePropValue& value); // function to ParseFromString. std::string parseData(const VehiclePropValue& value); -// TODO(aditin): Need to implement additional parsing functions per message -// type. +// Returns the publisher ID by parsing the VehiclePropValue containing the ID. +// Returns null if the message is invalid. +int32_t parsePublisherIdResponse(const VehiclePropValue& publisher_id_response); + +// Returns true if the new sequence number is greater than the last seen +// sequence number. +bool isSequenceNumberNewer(const VehiclePropValue& subscription_change, + const int last_seen_sequence_number); + +// Returns sequence number of the message. +int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscription_change); + +// Takes a subscription change message and returns the layers that have active +// subscriptions of the layers that are offered by your HAL client/publisher. +// +// A publisher can use this function when receiving a subscription change message +// to determine which layers to publish data on. +// The caller of this function can optionally decide to not consume these layers +// if the subscription change has the sequence number less than the last seen +// sequence number. +std::vector getSubscribedLayers(const VehiclePropValue& subscription_change, + const VmsOffers& offers); + +// Takes an availability change message and returns true if the parsed message implies that +// the service has newly started or restarted. +// If the message has a sequence number 0, it means that the service +// has newly started or restarted. +bool hasServiceNewlyStarted(const VehiclePropValue& availability_change); + +// Takes a start session message, current service ID, current client ID; and returns the type/status +// of the message. It also populates the new service ID with the correct value. +VmsSessionStatus parseStartSessionMessage(const VehiclePropValue& start_session, + const int current_service_id, const int current_client_id, + int* new_service_id); } // namespace vms } // namespace V2_0 diff --git a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp index f001a3236c..d346206c35 100644 --- a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp +++ b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp @@ -27,16 +27,24 @@ namespace vms { static constexpr int kMessageIndex = toInt(VmsBaseMessageIntegerValuesIndex::MESSAGE_TYPE); static constexpr int kMessageTypeSize = 1; +static constexpr int kPublisherIdSize = 1; static constexpr int kLayerNumberSize = 1; static constexpr int kLayerSize = 3; static constexpr int kLayerAndPublisherSize = 4; +static constexpr int kSessionIdsSize = 2; +static constexpr int kPublisherIdIndex = + toInt(VmsPublisherInformationIntegerValuesIndex::PUBLISHER_ID); +static constexpr int kSubscriptionStateSequenceNumberIndex = + toInt(VmsSubscriptionsStateIntegerValuesIndex::SEQUENCE_NUMBER); +static constexpr int kAvailabilitySequenceNumberIndex = + toInt(VmsAvailabilityStateIntegerValuesIndex::SEQUENCE_NUMBER); // TODO(aditin): We should extend the VmsMessageType enum to include a first and // last, which would prevent breakages in this API. However, for all of the // functions in this module, we only need to guarantee that the message type is -// between SUBSCRIBE and DATA. +// between SUBSCRIBE and START_SESSION. static constexpr int kFirstMessageType = toInt(VmsMessageType::SUBSCRIBE); -static constexpr int kLastMessageType = toInt(VmsMessageType::DATA); +static constexpr int kLastMessageType = toInt(VmsMessageType::START_SESSION); std::unique_ptr createBaseVmsMessage(size_t message_size) { auto result = createVehiclePropValue(VehiclePropertyType::INT32, message_size); @@ -77,17 +85,16 @@ std::unique_ptr createUnsubscribeToPublisherMessage( return result; } -std::unique_ptr createOfferingMessage( - const std::vector& offering) { - int message_size = kMessageTypeSize + kLayerNumberSize; - for (const auto& offer : offering) { - message_size += kLayerNumberSize + (1 + offer.dependencies.size()) * kLayerSize; +std::unique_ptr createOfferingMessage(const VmsOffers& offers) { + int message_size = kMessageTypeSize + kPublisherIdSize + kLayerNumberSize; + for (const auto& offer : offers.offerings) { + message_size += kLayerSize + kLayerNumberSize + (offer.dependencies.size() * kLayerSize); } auto result = createBaseVmsMessage(message_size); - std::vector offers = {toInt(VmsMessageType::OFFERING), - static_cast(offering.size())}; - for (const auto& offer : offering) { + std::vector offerings = {toInt(VmsMessageType::OFFERING), offers.publisher_id, + static_cast(offers.offerings.size())}; + for (const auto& offer : offers.offerings) { std::vector layer_vector = {offer.layer.type, offer.layer.subtype, offer.layer.version, static_cast(offer.dependencies.size())}; @@ -97,9 +104,9 @@ std::unique_ptr createOfferingMessage( layer_vector.insert(layer_vector.end(), dependency_layer.begin(), dependency_layer.end()); } - offers.insert(offers.end(), layer_vector.begin(), layer_vector.end()); + offerings.insert(offerings.end(), layer_vector.begin(), layer_vector.end()); } - result->value.int32Values = offers; + result->value.int32Values = offerings; return result; } @@ -119,10 +126,35 @@ std::unique_ptr createSubscriptionsRequest() { return result; } -std::unique_ptr createDataMessage(const std::string& bytes) { +std::unique_ptr createDataMessageWithLayerPublisherInfo( + const VmsLayerAndPublisher& layer_publisher, const std::string& vms_packet) { + auto result = createBaseVmsMessage(kMessageTypeSize + kLayerAndPublisherSize); + result->value.int32Values = hidl_vec{ + toInt(VmsMessageType::DATA), layer_publisher.layer.type, layer_publisher.layer.subtype, + layer_publisher.layer.version, layer_publisher.publisher_id}; + result->value.bytes = std::vector(vms_packet.begin(), vms_packet.end()); + return result; +} + +std::unique_ptr createPublisherIdRequest( + const std::string& vms_provider_description) { auto result = createBaseVmsMessage(kMessageTypeSize); - result->value.int32Values = hidl_vec{toInt(VmsMessageType::DATA)}; - result->value.bytes = std::vector(bytes.begin(), bytes.end()); + result->value.int32Values = hidl_vec{ + toInt(VmsMessageType::PUBLISHER_ID_REQUEST), + }; + result->value.bytes = + std::vector(vms_provider_description.begin(), vms_provider_description.end()); + return result; +} + +std::unique_ptr createStartSessionMessage(const int service_id, + const int client_id) { + auto result = createBaseVmsMessage(kMessageTypeSize + kSessionIdsSize); + result->value.int32Values = hidl_vec{ + toInt(VmsMessageType::START_SESSION), + service_id, + client_id, + }; return result; } @@ -153,6 +185,118 @@ std::string parseData(const VehiclePropValue& value) { } } +int32_t parsePublisherIdResponse(const VehiclePropValue& publisher_id_response) { + if (isValidVmsMessage(publisher_id_response) && + parseMessageType(publisher_id_response) == VmsMessageType::PUBLISHER_ID_RESPONSE && + publisher_id_response.value.int32Values.size() > kPublisherIdIndex) { + return publisher_id_response.value.int32Values[kPublisherIdIndex]; + } + return -1; +} + +bool isSequenceNumberNewer(const VehiclePropValue& subscription_change, + const int last_seen_sequence_number) { + return (isValidVmsMessage(subscription_change) && + parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE && + subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex && + subscription_change.value.int32Values[kSubscriptionStateSequenceNumberIndex] > + last_seen_sequence_number); +} + +int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscription_change) { + if (isValidVmsMessage(subscription_change) && + parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE && + subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) { + return subscription_change.value.int32Values[kSubscriptionStateSequenceNumberIndex]; + } + return -1; +} + +std::vector getSubscribedLayers(const VehiclePropValue& subscription_change, + const VmsOffers& offers) { + if (isValidVmsMessage(subscription_change) && + parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE && + subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) { + const int32_t num_of_layers = subscription_change.value.int32Values[toInt( + VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_LAYERS)]; + const int32_t num_of_associated_layers = subscription_change.value.int32Values[toInt( + VmsSubscriptionsStateIntegerValuesIndex ::NUMBER_OF_ASSOCIATED_LAYERS)]; + + std::unordered_set offered_layers; + for (const auto& offer : offers.offerings) { + offered_layers.insert(offer.layer); + } + std::vector subscribed_layers; + + int current_index = toInt(VmsSubscriptionsStateIntegerValuesIndex::SUBSCRIPTIONS_START); + // Add all subscribed layers which are offered by the current publisher. + for (int i = 0; i < num_of_layers; i++) { + VmsLayer layer = VmsLayer(subscription_change.value.int32Values[current_index], + subscription_change.value.int32Values[current_index + 1], + subscription_change.value.int32Values[current_index + 2]); + if (offered_layers.find(layer) != offered_layers.end()) { + subscribed_layers.push_back(layer); + } + current_index += kLayerSize; + } + // Add all subscribed associated layers which are offered by the current publisher. + // For this, we need to check if the associated layer has a publisher ID which is + // same as that of the current publisher. + for (int i = 0; i < num_of_associated_layers; i++) { + VmsLayer layer = VmsLayer(subscription_change.value.int32Values[current_index], + subscription_change.value.int32Values[current_index + 1], + subscription_change.value.int32Values[current_index + 2]); + current_index += kLayerSize; + if (offered_layers.find(layer) != offered_layers.end()) { + int32_t num_of_publisher_ids = subscription_change.value.int32Values[current_index]; + current_index++; + for (int j = 0; j < num_of_publisher_ids; j++) { + if (subscription_change.value.int32Values[current_index] == + offers.publisher_id) { + subscribed_layers.push_back(layer); + } + current_index++; + } + } + } + return subscribed_layers; + } + return {}; +} + +bool hasServiceNewlyStarted(const VehiclePropValue& availability_change) { + return (isValidVmsMessage(availability_change) && + parseMessageType(availability_change) == VmsMessageType::AVAILABILITY_CHANGE && + availability_change.value.int32Values.size() > kAvailabilitySequenceNumberIndex && + availability_change.value.int32Values[kAvailabilitySequenceNumberIndex] == 0); +} + +VmsSessionStatus parseStartSessionMessage(const VehiclePropValue& start_session, + const int current_service_id, const int current_client_id, + int* new_service_id) { + if (isValidVmsMessage(start_session) && + parseMessageType(start_session) == VmsMessageType::START_SESSION && + start_session.value.int32Values.size() == kSessionIdsSize + 1) { + *new_service_id = start_session.value.int32Values[1]; + const int new_client_id = start_session.value.int32Values[2]; + if (new_client_id != current_client_id) { + // If the new_client_id = -1, it means the service has newly started. + // But if it is not -1 and is different than the current client ID, then + // it means that the service did not have the correct client ID. In + // both these cases, the client should acknowledge with a START_SESSION + // message containing the correct client ID. So here, the status is returned as + // kNewServerSession. + return VmsSessionStatus::kNewServerSession; + } else { + // kAckToCurrentSession is returned if the new client ID is same as the current one. + return VmsSessionStatus::kAckToCurrentSession; + } + } + // If the message is invalid then persist the old service ID. + *new_service_id = current_service_id; + return VmsSessionStatus::kInvalidMessage; +} + } // namespace vms } // namespace V2_0 } // namespace vehicle 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 + +#include +#include + +#include "CommConn.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +void CommConn::start() { + mReadThread = std::make_unique(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 buffer(static_cast(numBytes)); + if (!msg.SerializeToArray(buffer.data(), numBytes)) { + ALOGE("%s: SerializeToString failed!", __func__); + return; + } + + write(buffer); +} + +void CommConn::readThread() { + std::vector 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(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 similarity index 53% rename from automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h rename to 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 #include +#include #include +#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; + + /** + * Process a single message received over a CommConn. Populate the given respMsg with the reply + * message we should send. + */ + 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() {} + + /** + * Start the read thread reading messages from this connection. + */ + virtual void start(); /** * Closes a connection if it is open. */ - virtual void stop() {} + virtual void stop(); /** - * 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. + * Returns true if the connection is open and available to send/receive. */ - virtual int connect() { return 0; } - - /** - * Opens the communications channel. - * - * @return int Returns 0 if channel is opened, else -errno if failed. - */ - virtual int open() = 0; + 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& data) = 0; + + /** + * Serialized and send the given message to the other side. + */ + void sendMessage(emulator::EmulatorMessage const& msg); + + protected: + std::unique_ptr 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..a46de24b16 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 = { @@ -160,6 +196,33 @@ const ConfigDeclaration kVehicleProperties[]{ }, .initialValue = {.int32Values = {1}}}, + {.config = + { + .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}, + }, + .initialValue = {.int32Values = {SEAT_1_LEFT}}}, + + {.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), @@ -177,6 +240,27 @@ const ConfigDeclaration kVehicleProperties[]{ }, .initialValue = {.floatValues = {0.0f}}}, + {.config = + { + .prop = toInt(VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {(int)VehicleUnit::METER_PER_SEC, + (int)VehicleUnit::MILES_PER_HOUR, + (int)VehicleUnit::KILOMETERS_PER_HOUR}, + }, + .initialValue = {.int32Values = {(int)VehicleUnit::KILOMETERS_PER_HOUR}}}, + + {.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), @@ -202,14 +286,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 +304,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 +322,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 +331,41 @@ 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)}}, + .minSampleRate = 1.0f, + .maxSampleRate = 2.0f, + }, + .initialValue = {.floatValues = {100.0f}}}, // units in meters + + {.config = + {.prop = toInt(VehicleProperty::TIRE_PRESSURE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 1.0f, + .maxSampleRate = 2.0f, + .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 +388,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 +406,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 +475,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 +500,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}}}}}, @@ -388,6 +541,7 @@ const ConfigDeclaration kVehicleProperties[]{ {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}, .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}}, .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}}, @@ -443,12 +597,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 +668,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 +681,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 +708,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( - std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))), - mJsonFakeValueGenerator(std::make_unique( - 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(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()(v.stringValue); + mGeneratorHub.registerGenerator(cookie, + std::make_unique(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()(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 mHvacPowerProps; RecurrentTimer mRecurrentTimer; - std::unique_ptr mLinearFakeValueGenerator; - std::unique_ptr 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; -using MuxGuard = std::lock_guard; - 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; + +using FakeValueGeneratorPtr = std::unique_ptr; + +} // 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 + +#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 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 g(mLock); + mGenerators.erase(cookie); + } + mCond.notify_one(); + ALOGI("%s: Unregistered generator, cookie: %d", __func__, cookie); +} + +void GeneratorHub::run() { + while (true) { + std::unique_lock 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 +#include +#include +#include +#include +#include +#include + +#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; + +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, GreaterByTime> mEventQueue; + std::unordered_map 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 +#include +#include #include #include @@ -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 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 JsonFakeValueGenerator::parseFakeValueJson(std::istream& is) { @@ -131,9 +124,14 @@ std::vector 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,30 +139,60 @@ std::vector JsonFakeValueGenerator::parseFakeValueJson(std::is return fakeVhalEvents; } -void JsonFakeValueGenerator::loop() { - static constexpr auto kInvalidTime = TimePoint(Nanos::max()); +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(); +} - 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(mGenCfg.events[mGenCfg.index + 1].timestamp - - mGenCfg.events[mGenCfg.index].timestamp); - nextEventTime = Clock::now() + intervalNano; - } - mGenCfg.index++; +template +void JsonFakeValueGenerator::copyJsonArray(hidl_vec& dest, const Json::Value& jsonArray) { + dest.resize(jsonArray.size()); + for (Json::Value::ArrayIndex i = 0; i < jsonArray.size(); i++) { + if (std::is_same::value) { + dest[i] = jsonArray[i].asInt(); + } else if (std::is_same::value) { + dest[i] = jsonArray[i].asInt64(); + } else if (std::is_same::value) { + dest[i] = jsonArray[i].asFloat(); } - - std::unique_lock g(mLock); - mCond.wait_until(g, nextEventTime); } } +bool JsonFakeValueGenerator::isDiagnosticProperty(int32_t prop) { + return prop == (int32_t)VehicleProperty::OBD2_LIVE_FRAME || + prop == (int32_t)VehicleProperty::OBD2_FREEZE_FRAME; +} + +hidl_vec JsonFakeValueGenerator::generateDiagnosticBytes( + const VehiclePropValue::RawValue& diagnosticValue) { + size_t byteSize = ((size_t)DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX + + (size_t)DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX + 2); + hidl_vec 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); + } + } + + 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& bytes, size_t idx) { + uint8_t mask = 1 << (idx % 8); + bytes[idx / 8] |= mask; +} + } // namespace impl } // namespace V2_0 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 #include -#include #include -#include #include @@ -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; - struct GeneratorCfg { size_t index; std::vector 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 parseFakeValueJson(std::istream& is); - void loop(); + void copyMixedValueJson(VehiclePropValue::RawValue& dest, const Json::Value& jsonValue); + + template + void copyJsonArray(hidl_vec& dest, const Json::Value& jsonArray); + + bool isDiagnosticProperty(int32_t prop); + hidl_vec generateDiagnosticBytes(const VehiclePropValue::RawValue& diagnosticValue); + void setBit(hidl_vec& 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(mGenCfg.currentValue); + break; + case VehiclePropertyType::INT64: + value.int64Values.resize(1); + value.int64Values[0] = static_cast(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& 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(cfg.currentValue); - break; - case VehiclePropertyType::INT64: - value.int64Values.resize(1); - value.int64Values[0] = static_cast(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 - #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; + + VehiclePropValue nextEvent(); + + bool hasNext(); private: - void removeLocked(int propId); - void onTimer(const std::vector& properties); - -private: - mutable std::mutex mLock; - OnHalEvent mOnHalEvent; - RecurrentTimer mRecurrentTimer; - std::unordered_map 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 PipeComm::read() { @@ -60,16 +65,13 @@ std::vector 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 lock(mMutex); - mPipeFd = -1; - } + mPipeFd = -1; } return std::vector(); @@ -78,11 +80,8 @@ std::vector PipeComm::read() { int PipeComm::write(const std::vector& data) { int retVal = 0; - { - std::lock_guard 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 #include -#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 Serialized protobuf data received from emulator. This will be - * an empty vector if the connection was closed or some other error occurred. - */ std::vector 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& 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 #include +#include #include #include #include @@ -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(&cliAddr), &cliLen); - - if (cSockFd >= 0) { - { - std::lock_guard lock(mMutex); - mCurSockFd = cSockFd; - } - ALOGD("%s: Incoming connection received on socket %d", __FUNCTION__, cSockFd); - } else { - cSockFd = -1; +void SocketComm::start() { + if (!listen()) { + return; } - return cSockFd; + mListenThread = std::make_unique(std::bind(&SocketComm::listenThread, this)); } -int SocketComm::open() { +void SocketComm::stop() { + if (mListenFd > 0) { + ::close(mListenFd); + if (mListenThread->joinable()) { + mListenThread->join(); + } + mListenFd = -1; + } +} + +void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) { + std::lock_guard lock(mMutex); + for (std::unique_ptr const& conn : mOpenConnections) { + conn->sendMessage(msg); + } +} + +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(&servAddr), sizeof(servAddr)); + retVal = bind(mListenFd, reinterpret_cast(&servAddr), sizeof(servAddr)); if(retVal < 0) { ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno); + close(mListenFd); + mListenFd = -1; + return false; + } + + 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(&cliAddr), &cliLen); + + if (sfd > 0) { + char addr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &cliAddr.sin_addr, addr, INET_ADDRSTRLEN); + + ALOGD("%s: Incoming connection received from %s:%d", __FUNCTION__, addr, cliAddr.sin_port); + return new SocketConn(mMessageProcessor, sfd); + } + + return nullptr; +} + +void SocketComm::listenThread() { + while (true) { + SocketConn* conn = accept(); + if (conn == nullptr) { + return; + } + + conn->start(); + { + std::lock_guard lock(mMutex); + mOpenConnections.push_back(std::unique_ptr(conn)); + } + } +} + +/** + * Called occasionally to clean up connections that have been closed. + */ +void SocketComm::removeClosedConnections() { + std::lock_guard lock(mMutex); + std::remove_if(mOpenConnections.begin(), mOpenConnections.end(), + [](std::unique_ptr const& c) { return !c->isOpen(); }); +} + +SocketConn::SocketConn(MessageProcessor* messageProcessor, int sfd) + : CommConn(messageProcessor), mSockFd(sfd) {} + +/** + * 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 readExactly(int fd, int numBytes) { + std::vector 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; + } + + totalRead += numRead; + } + return buffer; +} + +/** + * 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 buffer = readExactly(fd, sizeof(int32_t)); + if (buffer.size() == 0) { + return -1; + } + + int32_t value = *reinterpret_cast(buffer.data()); + return ntohl(value); +} + +std::vector SocketConn::read() { + int32_t msgSize = readInt(mSockFd); + if (msgSize <= 0) { + ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mSockFd); + return std::vector(); + } + + return readExactly(mSockFd, msgSize); +} + +void SocketConn::stop() { + if (mSockFd > 0) { close(mSockFd); mSockFd = -1; - return -errno; - } - - listen(mSockFd, 1); - - // Set the socket to be non-blocking so we can poll it continouously - fcntl(mSockFd, F_SETFL, O_NONBLOCK); - - return 0; -} - -std::vector 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); - - 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); - { - std::lock_guard lock(mMutex); - mCurSockFd = -1; - } - - return std::vector(); - } - - std::vector msg = std::vector(msgSize); - - numBytes = ::read(mCurSockFd, msg.data(), msgSize); - - 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 lock(mMutex); - mCurSockFd = -1; - } - - return std::vector(); } } -void SocketComm::stop() { - if (mExit == 0) { - std::lock_guard lock(mMutex); - mExit = 1; - - // Close emulator socket if it is open - if (mCurSockFd != -1) { - close(mCurSockFd); - mCurSockFd = -1; - } - - if (mSockFd != -1) { - close(mSockFd); - mSockFd = -1; - } - } -} - -int SocketComm::write(const std::vector& data) { +int SocketConn::write(const std::vector& data) { static constexpr int MSG_HEADER_LEN = 4; int retVal = 0; union { @@ -168,19 +202,17 @@ int SocketComm::write(const std::vector& data) { msgLen = static_cast(data.size()); msgLen = htonl(msgLen); - std::lock_guard 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 +#include #include -#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(); + /** - * Creates a connection to the other side. + * Serialized and send the given message to all connected clients. + */ + void sendMessage(emulator::EmulatorMessage const& msg); + + private: + int mListenFd; + std::unique_ptr mListenThread; + std::vector> mOpenConnections; + MessageProcessor* mMessageProcessor; + std::mutex mMutex; + + /** + * Opens the socket and begins listening. + * + * @return bool Returns true on success. + */ + bool listen(); + + /** + * 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 fd or socket number if connection is successful. * Otherwise, returns -1 if no connection is availble. */ - int connect() override; + SocketConn* accept(); - /** - * Opens a socket and begins listening. - * - * @return int Returns 0 on success. - */ - int open() override; + 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& data) override; -private: - int mCurSockFd; - std::atomic 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 -#include #include +#include #include +#include #include @@ -35,32 +36,45 @@ namespace V2_0 { namespace impl { -std::unique_ptr CommFactory::create() { - bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false); +VehicleEmulator::VehicleEmulator(EmulatedVehicleHalIface* hal) : mHal{hal} { + mHal->registerEmulator(this); - if (isEmulator) { - return std::make_unique(); - } else { - return std::make_unique(); + ALOGI("Starting SocketComm"); + mSocketComm = std::make_unique(this); + mSocketComm->start(); + + if (android::base::GetBoolProperty("ro.kernel.qemu", false)) { + ALOGI("Starting PipeComm"); + mPipeComm = std::make_unique(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 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 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 msg(static_cast(numBytes)); - - if (!txMsg.SerializeToArray(msg.data(), static_cast(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& msg) { - emulator::EmulatorMessage rxMsg; - emulator::EmulatorMessage respMsg; - - if (rxMsg.ParseFromArray(msg.data(), static_cast(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(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 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 create(); -}; - /** * Emulates vehicle by providing controlling interface from host side either through ADB or Pipe. */ -class VehicleEmulator { -public: - VehicleEmulator(EmulatedVehicleHalIface* hal, - std::unique_ptr 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& 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 mExit { false }; EmulatedVehicleHalIface* mHal; - std::unique_ptr mComm; - std::thread mThread; + std::unique_ptr mSocketComm; + std::unique_ptr mPipeComm; }; } // impl diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp index f64eab55a9..09750718a0 100644 --- a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp +++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp @@ -278,7 +278,6 @@ TEST_F(VehicleHalManagerTest, subscribe) { cb->reset(); VehiclePropValue actualValue(*subscribedValue.get()); - actualValue.status = VehiclePropertyStatus::AVAILABLE; hal->sendPropEvent(std::move(subscribedValue)); ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: " diff --git a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp index 414c5c2a42..7189212505 100644 --- a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp +++ b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp @@ -60,52 +60,64 @@ TEST(VmsUtilsTest, unsubscribeMessage) { } TEST(VmsUtilsTest, singleOfferingMessage) { - std::vector offering = {VmsLayerOffering(VmsLayer(1, 0, 2))}; - auto message = createOfferingMessage(offering); + VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 2))}}; + auto message = createOfferingMessage(offers); ASSERT_NE(message, nullptr); EXPECT_TRUE(isValidVmsMessage(*message)); EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE)); - EXPECT_EQ(message->value.int32Values.size(), 0x6ul); + EXPECT_EQ(message->value.int32Values.size(), 0x7ul); EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING); + // Publisher ID + EXPECT_EQ(message->value.int32Values[1], 123); + // Number of layer offerings - EXPECT_EQ(message->value.int32Values[1], 1); + EXPECT_EQ(message->value.int32Values[2], 1); // Layer - EXPECT_EQ(message->value.int32Values[2], 1); - EXPECT_EQ(message->value.int32Values[3], 0); - EXPECT_EQ(message->value.int32Values[4], 2); + EXPECT_EQ(message->value.int32Values[3], 1); + EXPECT_EQ(message->value.int32Values[4], 0); + EXPECT_EQ(message->value.int32Values[5], 2); // Number of dependencies - EXPECT_EQ(message->value.int32Values[5], 0); + EXPECT_EQ(message->value.int32Values[6], 0); } TEST(VmsUtilsTest, offeringWithDependencies) { VmsLayer layer(1, 0, 2); - std::vector dependencies = {VmsLayer(2, 0, 2)}; + std::vector dependencies = {VmsLayer(2, 0, 2), VmsLayer(3, 0, 3)}; std::vector offering = {VmsLayerOffering(layer, dependencies)}; - auto message = createOfferingMessage(offering); + VmsOffers offers = {123, offering}; + auto message = createOfferingMessage(offers); ASSERT_NE(message, nullptr); EXPECT_TRUE(isValidVmsMessage(*message)); EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE)); - EXPECT_EQ(message->value.int32Values.size(), 0x9ul); + EXPECT_EQ(message->value.int32Values.size(), 0xdul); EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING); + // Publisher ID + EXPECT_EQ(message->value.int32Values[1], 123); + // Number of layer offerings - EXPECT_EQ(message->value.int32Values[1], 1); + EXPECT_EQ(message->value.int32Values[2], 1); // Layer - EXPECT_EQ(message->value.int32Values[2], 1); - EXPECT_EQ(message->value.int32Values[3], 0); - EXPECT_EQ(message->value.int32Values[4], 2); + EXPECT_EQ(message->value.int32Values[3], 1); + EXPECT_EQ(message->value.int32Values[4], 0); + EXPECT_EQ(message->value.int32Values[5], 2); // Number of dependencies - EXPECT_EQ(message->value.int32Values[5], 1); + EXPECT_EQ(message->value.int32Values[6], 2); // Dependency 1 - EXPECT_EQ(message->value.int32Values[6], 2); - EXPECT_EQ(message->value.int32Values[7], 0); - EXPECT_EQ(message->value.int32Values[8], 2); + EXPECT_EQ(message->value.int32Values[7], 2); + EXPECT_EQ(message->value.int32Values[8], 0); + EXPECT_EQ(message->value.int32Values[9], 2); + + // Dependency 2 + EXPECT_EQ(message->value.int32Values[10], 3); + EXPECT_EQ(message->value.int32Values[11], 0); + EXPECT_EQ(message->value.int32Values[12], 3); } TEST(VmsUtilsTest, availabilityMessage) { @@ -127,12 +139,23 @@ TEST(VmsUtilsTest, subscriptionsMessage) { } TEST(VmsUtilsTest, dataMessage) { - std::string bytes = "aaa"; - auto message = createDataMessage(bytes); + const std::string bytes = "aaa"; + const VmsLayerAndPublisher layer_and_publisher(VmsLayer(2, 0, 1), 123); + auto message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes); ASSERT_NE(message, nullptr); EXPECT_TRUE(isValidVmsMessage(*message)); EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE)); - EXPECT_EQ(message->value.int32Values.size(), 0x1ul); + EXPECT_EQ(message->value.int32Values.size(), 0x5ul); + EXPECT_EQ(message->value.int32Values[0], toInt(VmsMessageType::DATA)); + + // Layer + EXPECT_EQ(message->value.int32Values[1], 2); + EXPECT_EQ(message->value.int32Values[2], 0); + EXPECT_EQ(message->value.int32Values[3], 1); + + // Publisher ID + EXPECT_EQ(message->value.int32Values[4], 123); + EXPECT_EQ(parseMessageType(*message), VmsMessageType::DATA); EXPECT_EQ(message->value.bytes.size(), bytes.size()); EXPECT_EQ(memcmp(message->value.bytes.data(), bytes.data(), bytes.size()), 0); @@ -146,14 +169,15 @@ TEST(VmsUtilsTest, emptyMessageInvalid) { TEST(VmsUtilsTest, invalidMessageType) { VmsLayer layer(1, 0, 2); auto message = createSubscribeMessage(layer); - message->value.int32Values[0] = 0; + message->value.int32Values[0] = -1; EXPECT_FALSE(isValidVmsMessage(*message)); } TEST(VmsUtilsTest, parseDataMessage) { - std::string bytes = "aaa"; - auto message = createDataMessage(bytes); + const std::string bytes = "aaa"; + const VmsLayerAndPublisher layer_and_publisher(VmsLayer(1, 0, 1), 123); + auto message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes); auto data_str = parseData(*message); ASSERT_FALSE(data_str.empty()); EXPECT_EQ(data_str, bytes); @@ -166,6 +190,236 @@ TEST(VmsUtilsTest, parseInvalidDataMessage) { EXPECT_TRUE(data_str.empty()); } +TEST(VmsUtilsTest, publisherIdRequest) { + std::string bytes = "pub_id"; + auto message = createPublisherIdRequest(bytes); + ASSERT_NE(message, nullptr); + EXPECT_TRUE(isValidVmsMessage(*message)); + EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE)); + EXPECT_EQ(message->value.int32Values.size(), 0x1ul); + EXPECT_EQ(parseMessageType(*message), VmsMessageType::PUBLISHER_ID_REQUEST); + EXPECT_EQ(message->value.bytes.size(), bytes.size()); + EXPECT_EQ(memcmp(message->value.bytes.data(), bytes.data(), bytes.size()), 0); +} + +TEST(VmsUtilsTest, validPublisherIdResponse) { + auto message = createBaseVmsMessage(2); + message->value.int32Values = + hidl_vec{toInt(VmsMessageType::PUBLISHER_ID_RESPONSE), 1234}; + EXPECT_EQ(parsePublisherIdResponse(*message), 1234); +} + +TEST(VmsUtilsTest, invalidPublisherIdResponse) { + auto message = createBaseVmsMessage(1); + EXPECT_EQ(parsePublisherIdResponse(*message), -1); +} + +TEST(VmsUtilsTest, validSequenceNumberForSubscriptionsState) { + auto message = createBaseVmsMessage(2); + message->value.int32Values = + hidl_vec{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234}; + EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), 1234); +} + +TEST(VmsUtilsTest, invalidSubscriptionsState) { + auto message = createBaseVmsMessage(1); + EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), -1); +} + +TEST(VmsUtilsTest, newSequenceNumberForExistingSmallerNumber) { + auto message = createBaseVmsMessage(2); + message->value.int32Values = + hidl_vec{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234}; + EXPECT_TRUE(isSequenceNumberNewer(*message, 1233)); +} + +TEST(VmsUtilsTest, newSequenceNumberForExistingGreaterNumber) { + auto message = createBaseVmsMessage(2); + message->value.int32Values = + hidl_vec{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234}; + EXPECT_FALSE(isSequenceNumberNewer(*message, 1235)); +} + +TEST(VmsUtilsTest, newSequenceNumberForSameNumber) { + auto message = createBaseVmsMessage(2); + message->value.int32Values = + hidl_vec{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234}; + EXPECT_FALSE(isSequenceNumberNewer(*message, 1234)); +} + +TEST(VmsUtilsTest, subscribedLayers) { + VmsOffers offers = {123, + {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}), + VmsLayerOffering(VmsLayer(2, 0, 1))}}; + auto message = createBaseVmsMessage(2); + message->value.int32Values = hidl_vec{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), + 1234, // sequence number + 2, // number of layers + 1, // number of associated layers + 1, // layer 1 + 0, + 1, + 4, // layer 2 + 1, + 1, + 2, // associated layer + 0, + 1, + 2, // number of publisher IDs + 111, // publisher IDs + 123}; + EXPECT_TRUE(isValidVmsMessage(*message)); + auto result = getSubscribedLayers(*message, offers); + EXPECT_EQ(static_cast(result.size()), 2); + EXPECT_EQ(result.at(0), VmsLayer(1, 0, 1)); + EXPECT_EQ(result.at(1), VmsLayer(2, 0, 1)); +} + +TEST(VmsUtilsTest, subscribedLayersWithDifferentSubtype) { + VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}}; + auto message = createBaseVmsMessage(2); + message->value.int32Values = hidl_vec{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), + 1234, // sequence number + 1, // number of layers + 0, // number of associated layers + 1, // layer 1 + 1, // different subtype + 1}; + EXPECT_TRUE(isValidVmsMessage(*message)); + EXPECT_TRUE(getSubscribedLayers(*message, offers).empty()); +} + +TEST(VmsUtilsTest, subscribedLayersWithDifferentVersion) { + VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}}; + auto message = createBaseVmsMessage(2); + message->value.int32Values = hidl_vec{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), + 1234, // sequence number + 1, // number of layers + 0, // number of associated layers + 1, // layer 1 + 0, + 2}; // different version + EXPECT_TRUE(isValidVmsMessage(*message)); + EXPECT_TRUE(getSubscribedLayers(*message, offers).empty()); +} + +TEST(VmsUtilsTest, subscribedLayersWithDifferentPublisherId) { + VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}}; + auto message = createBaseVmsMessage(2); + message->value.int32Values = hidl_vec{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), + 1234, // sequence number + 0, // number of layers + 1, // number of associated layers + 1, // associated layer 1 + 0, + 1, + 1, // number of publisher IDs + 234}; // publisher ID 1 + EXPECT_TRUE(isValidVmsMessage(*message)); + EXPECT_TRUE(getSubscribedLayers(*message, offers).empty()); +} + +TEST(VmsUtilsTest, serviceNewlyStarted) { + auto message = createBaseVmsMessage(2); + message->value.int32Values = hidl_vec{toInt(VmsMessageType::AVAILABILITY_CHANGE), 0}; + EXPECT_TRUE(hasServiceNewlyStarted(*message)); +} + +TEST(VmsUtilsTest, serviceNotNewlyStarted) { + auto message = createBaseVmsMessage(2); + message->value.int32Values = + hidl_vec{toInt(VmsMessageType::AVAILABILITY_CHANGE), 1234}; + EXPECT_FALSE(hasServiceNewlyStarted(*message)); +} + +TEST(VmsUtilsTest, invalidAvailabilityChange) { + auto message = createBaseVmsMessage(1); + EXPECT_FALSE(hasServiceNewlyStarted(*message)); +} + +TEST(VmsUtilsTest, startSessionRequest) { + auto message = createStartSessionMessage(123, 456); + ASSERT_NE(message, nullptr); + EXPECT_TRUE(isValidVmsMessage(*message)); + EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE)); + EXPECT_EQ(message->value.int32Values.size(), 0x3ul); + EXPECT_EQ(parseMessageType(*message), VmsMessageType::START_SESSION); + EXPECT_EQ(message->value.int32Values[1], 123); + EXPECT_EQ(message->value.int32Values[2], 456); +} + +TEST(VmsUtilsTest, startSessionServiceNewlyStarted) { + auto message = createBaseVmsMessage(3); + int new_service_id; + message->value.int32Values = hidl_vec{toInt(VmsMessageType::START_SESSION), 123, -1}; + EXPECT_EQ(parseStartSessionMessage(*message, 122, 456, &new_service_id), + VmsSessionStatus::kNewServerSession); + EXPECT_EQ(new_service_id, 123); +} + +TEST(VmsUtilsTest, startSessionServiceNewlyStartedEdgeCase) { + auto message = createBaseVmsMessage(3); + int new_service_id; + message->value.int32Values = hidl_vec{toInt(VmsMessageType::START_SESSION), 0, -1}; + EXPECT_EQ(parseStartSessionMessage(*message, -1, 0, &new_service_id), + VmsSessionStatus::kNewServerSession); + EXPECT_EQ(new_service_id, 0); +} + +TEST(VmsUtilsTest, startSessionClientNewlyStarted) { + auto message = createBaseVmsMessage(3); + int new_service_id; + message->value.int32Values = hidl_vec{toInt(VmsMessageType::START_SESSION), 123, 456}; + EXPECT_EQ(parseStartSessionMessage(*message, -1, 456, &new_service_id), + VmsSessionStatus::kAckToCurrentSession); + EXPECT_EQ(new_service_id, 123); +} + +TEST(VmsUtilsTest, startSessionClientNewlyStartedWithSameServerAndClientId) { + auto message = createBaseVmsMessage(3); + int new_service_id; + message->value.int32Values = hidl_vec{toInt(VmsMessageType::START_SESSION), 123, 456}; + EXPECT_EQ(parseStartSessionMessage(*message, 123, 456, &new_service_id), + VmsSessionStatus::kAckToCurrentSession); + EXPECT_EQ(new_service_id, 123); +} + +TEST(VmsUtilsTest, startSessionWithZeroAsIds) { + auto message = createBaseVmsMessage(3); + int new_service_id; + message->value.int32Values = hidl_vec{toInt(VmsMessageType::START_SESSION), 0, 0}; + EXPECT_EQ(parseStartSessionMessage(*message, 0, 0, &new_service_id), + VmsSessionStatus::kAckToCurrentSession); + EXPECT_EQ(new_service_id, 0); +} + +TEST(VmsUtilsTest, startSessionOldServiceId) { + auto message = createBaseVmsMessage(3); + int new_service_id; + message->value.int32Values = hidl_vec{toInt(VmsMessageType::START_SESSION), 120, 456}; + EXPECT_EQ(parseStartSessionMessage(*message, 123, 456, &new_service_id), + VmsSessionStatus::kAckToCurrentSession); + EXPECT_EQ(new_service_id, 120); +} + +TEST(VmsUtilsTest, startSessionNegativeServerId) { + auto message = createBaseVmsMessage(3); + int new_service_id; + message->value.int32Values = hidl_vec{toInt(VmsMessageType::START_SESSION), -1, 456}; + EXPECT_EQ(parseStartSessionMessage(*message, -1, 456, &new_service_id), + VmsSessionStatus::kAckToCurrentSession); + EXPECT_EQ(new_service_id, -1); +} + +TEST(VmsUtilsTest, startSessionInvalidMessageFormat) { + auto message = createBaseVmsMessage(2); + int new_service_id; + message->value.int32Values = hidl_vec{toInt(VmsMessageType::START_SESSION), 123}; + EXPECT_EQ(parseStartSessionMessage(*message, 123, 456, &new_service_id), + VmsSessionStatus::kInvalidMessage); + EXPECT_EQ(new_service_id, 123); +} + } // namespace } // namespace vms diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 69b7628927..f6ebcdd7d0 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 @@ -278,7 +282,6 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:INT32 | VehicleArea:SEAT), - /** * Current odometer value of the vehicle * @@ -305,6 +308,37 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:FLOAT | 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 * @@ -587,7 +621,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 @@ -601,7 +641,9 @@ enum VehicleProperty : int32_t { /** * Night mode * - * True indicates that night mode is currently enabled. + * True indicates that the night mode sensor has detected that the car cabin environment has + * low light. The platform could use this, for example, to enable appropriate UI for + * better viewing in dark or low light environments. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ @@ -943,12 +985,17 @@ enum VehicleProperty : int32_t { * * Indicates whether the vehicle is displaying temperature to the user as * Celsius or Fahrenheit. + * VehiclePropConfig.configArray is used to indicate the supported temperature display units. + * For example: configArray[0] = CELSIUS + * configArray[1] = FAHRENHEIT + * * This parameter MAY be used for displaying any HVAC temperature in the system. * Values must be one of VehicleUnit::CELSIUS or VehicleUnit::FAHRENHEIT * Note that internally, all temperatures are represented in floating point Celsius. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE + * @data_enum VehicleUnit */ HVAC_TEMPERATURE_DISPLAY_UNITS = ( 0x050E @@ -1071,6 +1118,123 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:INT32 | VehicleArea:SEAT), + /** + * Distance units for display + * + * Indicates which units the car is using to display distances to the user. Eg. Mile, Meter + * Kilometer. + * + * Distance units are defined in VehicleUnit. + * VehiclePropConfig.configArray is used to indicate the supported distance display units. + * For example: configArray[0] = METER + * configArray[1] = KILOMETER + * configArray[2] = MILE + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @data_enum VehicleUnit + */ + DISTANCE_DISPLAY_UNITS = ( + 0x0600 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /** + * Fuel volume units for display + * + * Indicates which units the car is using to display fuel volume to the user. Eg. Liter or + * Gallon. + * + * VehiclePropConfig.configArray is used to indicate the supported fuel volume display units. + * Volume units are defined in VehicleUnit. + * For example: configArray[0] = LITER + * configArray[1] = GALLON + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @data_enum VehicleUnit + */ + FUEL_VOLUME_DISPLAY_UNITS = ( + 0x0601 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /** + * Tire pressure units for display + * + * Indicates which units the car is using to display tire pressure to the user. Eg. PSI, Bar or + * Kilopascal. + * + * VehiclePropConfig.configArray is used to indicate the supported pressure display units. + * Pressure units are defined in VehicleUnit. + * For example: configArray[0] = KILOPASCAL + * configArray[1] = PSI + * configArray[2] = BAR + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @data_enum VehicleUnit + */ + TIRE_PRESSURE_DISPLAY_UNITS = ( + 0x0602 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /** + * EV battery units for display + * + * Indicates which units the car is using to display EV battery information to the user. Eg. + * watt-hours(Wh), kilowatt-hours(kWh) or ampere-hours(Ah). + * + * VehiclePropConfig.configArray is used to indicate the supported electrical energy units. + * Electrical energy units are defined in VehicleUnit. + * For example: configArray[0] = WATT_HOUR + * configArray[1] = AMPERE_HOURS + * configArray[2] = KILOWATT_HOUR + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @data_enum VehicleUnit + */ + EV_BATTERY_DISPLAY_UNITS = ( + 0x0603 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /** + * Fuel consumption units for display + * + * Indicates type of units the car is using to display fuel consumption information to user + * True indicates units are distance over volume such as MPG. + * False indicates units are volume over distance such as L/100KM. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = ( + 0x0604 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + + /** + * Speed units for display + * + * Indicates type of units the car is using to display speed to user. Eg. m/s, km/h, or mph. + * + * VehiclePropConfig.configArray is used to indicate the supported speed display units. + * Pressure units are defined in VehicleUnit. + * For example: configArray[0] = METER_PER_SEC + * configArray[1] = MILES_PER_HOUR + * configArray[2] = KILOMETERS_PER_HOUR + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + VEHICLE_SPEED_DISPLAY_UNITS = ( + 0x0605 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), /** * Outside temperature @@ -1088,7 +1252,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 +1263,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 +1282,7 @@ enum VehicleProperty : int32_t { * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VEHICLE_PROP_ACCESS_WRITE + * @access VehiclePropertyAccess:WRITE */ AP_POWER_STATE_REPORT = ( 0x0A01 @@ -1171,6 +1335,8 @@ enum VehicleProperty : int32_t { * int32Values[2] : target display defined in VehicleDisplay. Events not * tied to specific display must be sent to * VehicleDisplay#MAIN. + * int32Values[3] : [optional] Number of ticks. The value must be equal or + * greater than 1. When omitted, Android will default to 1. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ @@ -1737,6 +1903,22 @@ enum VehicleProperty : int32_t { | VehiclePropertyType:INT32 | VehicleArea:SEAT), + /** + * Seat Occupancy + * + * Indicates whether a particular seat is occupied or not, to the best of the car's ability + * to determine. Valid values are from the VehicleSeatOccupancyState enum. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * @data_enum VehicleSeatOccupancyState + */ + SEAT_OCCUPANCY = ( + 0x0BB0 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + /** * Window Position * @@ -2072,6 +2254,83 @@ enum VehicleProperty : int32_t { | VehiclePropertyGroup:SYSTEM | VehiclePropertyType:INT32 | VehicleArea:GLOBAL), + + /** + * Cabin lights + * + * Return current status of cabin lights. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * @data_enum VehicleLightState + */ + CABIN_LIGHTS_STATE = ( + 0x0F01 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /** + * Cabin lights switch + * + * The position of the physical switch which controls the cabin lights. + * This might be different than the CABIN_LIGHTS_STATE if the lights are on because a door + * is open or because of a voice command. + * For example, while the switch is in the "off" or "automatic" position. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @data_enum VehicleLightSwitch + */ + CABIN_LIGHTS_SWITCH = ( + 0x0F02 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /** + * Reading lights + * + * Return current status of reading lights. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * @data_enum VehicleLightState + */ + READING_LIGHTS_STATE = ( + 0x0F03 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /** + * Reading lights switch + * + * The position of the physical switch which controls the reading lights. + * This might be different than the READING_LIGHTS_STATE if the lights are on because a door + * is open or because of a voice command. + * For example, while the switch is in the "off" or "automatic" position. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @data_enum VehicleLightSwitch + */ + READING_LIGHTS_SWITCH = ( + 0x0F04 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + +}; + +/** + * Used by seat occupancy to enumerate the current occupancy state of the seat. + */ +enum VehicleSeatOccupancyState : int32_t { + + UNKNOWN = 0, + VACANT = 1, + OCCUPIED = 2 }; /** @@ -2230,17 +2489,8 @@ enum VehicleApPowerStateConfigFlag : int32_t { }; 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 +2500,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 +2535,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 +2567,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. + * 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. */ - 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. - */ - 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 { @@ -2383,29 +2613,45 @@ enum VehicleDisplay : int32_t { * Units used for int or float type with no attached enum types. */ enum VehicleUnit : int32_t { - SHOULD_NOT_USE = 0x000, + SHOULD_NOT_USE = 0x000, - METER_PER_SEC = 0x01, - RPM = 0x02, - HERTZ = 0x03, - PERCENTILE = 0x10, - MILLIMETER = 0x20, - METER = 0x21, - KILOMETER = 0x23, - CELSIUS = 0x30, - FAHRENHEIT = 0x31, - KELVIN = 0x32, - MILLILITER = 0x40, - NANO_SECS = 0x50, - SECS = 0x53, - YEAR = 0x59, - KILOPASCAL = 0x70, + METER_PER_SEC = 0x01, + RPM = 0x02, + HERTZ = 0x03, + PERCENTILE = 0x10, + MILLIMETER = 0x20, + METER = 0x21, + KILOMETER = 0x23, + MILE = 0x24, + CELSIUS = 0x30, + FAHRENHEIT = 0x31, + KELVIN = 0x32, + MILLILITER = 0x40, + LITER = 0x41, + + /** deprecated. Use US_GALLON instead. */ + GALLON = 0x42, + US_GALLON = 0x42, + IMPERIAL_GALLON = 0x43, + NANO_SECS = 0x50, + SECS = 0x53, + YEAR = 0x59, // Electrical Units - WATT_HOUR = 0x60, - MILLIAMPERE = 0x61, - MILLIVOLT = 0x62, - MILLIWATTS = 0x63, + WATT_HOUR = 0x60, + MILLIAMPERE = 0x61, + MILLIVOLT = 0x62, + MILLIWATTS = 0x63, + AMPERE_HOURS = 0x64, + KILOWATT_HOUR = 0x65, + + KILOPASCAL = 0x70, + PSI = 0x71, + BAR = 0x72, + DEGREES = 0x80, + + MILES_PER_HOUR = 0x90, + KILOMETERS_PER_HOUR = 0x91, }; /** @@ -2554,6 +2800,14 @@ struct VehicleAreaConfig { */ int32_t areaId; + /** + * If the property has @data_enum, leave the range to zero. + * + * Range will be ignored in the following cases: + * - The VehiclePropertyType is not INT32, INT64 or FLOAT. + * - Both of min value and max value are zero. + */ + int32_t minInt32Value; int32_t maxInt32Value; @@ -3148,7 +3402,17 @@ enum VmsMessageType : int32_t { */ PUBLISHER_INFORMATION_RESPONSE = 16, - LAST_VMS_MESSAGE_TYPE = PUBLISHER_INFORMATION_RESPONSE, + /** + * A notification indicating that the sender has been reset. + * + * The receiving party must reset its internal state and respond to the + * sender with a START_SESSION message as acknowledgement. + * + * This message type uses enum VmsStartSessionMessageIntegerValuesIndex. + */ + START_SESSION = 17, + + LAST_VMS_MESSAGE_TYPE = START_SESSION, }; /** @@ -3161,6 +3425,30 @@ enum VmsBaseMessageIntegerValuesIndex : int32_t { MESSAGE_TYPE = 0, }; +/* + * Handshake data sent as part of a VmsMessageType.START_SESSION message. + * + * A new session is initiated by sending a START_SESSION message with the + * sender's identifier populated and the receiver's identifier set to -1. + * + * Identifier values are independently generated, but must be non-negative, and + * increase monotonically between reboots. + * + * Upon receiving a START_SESSION with a mis-matching identifier, the receiver + * must clear any cached VMS offering or subscription state and acknowledge the + * new session by responding with a START_SESSION message that populates both + * identifier fields. + * + * Any VMS messages received between initiation and completion of the handshake + * must be discarded. + */ +enum VmsStartSessionMessageIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex { + /* Identifier field for the Android system service. */ + SERVICE_ID = 1, + /* Identifier field for the HAL client process. */ + CLIENT_ID = 2, +}; + /* * A VMS message with a layer is sent as part of a VmsMessageType.SUBSCRIBE or * VmsMessageType.UNSUBSCRIBE messages. diff --git a/biometrics/face/1.0/Android.bp b/biometrics/face/1.0/Android.bp new file mode 100644 index 0000000000..ebb8668938 --- /dev/null +++ b/biometrics/face/1.0/Android.bp @@ -0,0 +1,18 @@ +// 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", + ], + 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..180d829116 --- /dev/null +++ b/biometrics/face/1.0/IBiometricsFace.hal @@ -0,0 +1,274 @@ +/* + * 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; + +/** + * 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. + * + * Note that onLockoutChanged() MUST be invoked by the implementation in + * response to a user change in order to update the framework with the + * timeout of the new user (or 0 if the user is not locked out). + * + * @param userId A non-negative user identifier that must be unique and + * persistent for a given user. + * @param storePath absolute filesystem path to the template storage + * directory. This must be the /data/vendor_de//facedata + * directory specified by the SeLinux policy. + */ + @callflow(next={"authenticate", "generateChallenge", "enumerate", "remove"}) + setActiveUser(int32_t userId, string storePath) generates (Status status); + + /** + * Begins a secure transaction request, e.g. enroll() or resetLockout(). + * + * Generates a unique and cryptographically secure random token used to + * indicate the start of a secure transaction. generateChallenge() and + * revokeChallenge() specify a window where the resulting HAT that is + * generated in response to checking the user's PIN/pattern/password + * can be used to verify/perform a secure transaction. + * + * generateChallenge() generates a challenge which must then be wrapped by + * gatekeeper after verifying a successful strong authentication attempt, + * which generates a Hardware Authentication Token. The challenge prevents + * spoofing and replay attacks and ensures that only a transaction backed + * by a user authentication (PIN/pattern/password) can proceed. + * + * The implementation should be tolerant of revokeChallenge() being invoked + * after timeout has expired. + * + * @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", "setFeature"}) + generateChallenge(uint32_t challengeTimeoutSec) + generates (OptionalUint64 result); + + /** + * Enrolls a user's face. + * + * Note that the Hardware Authentication Token must be valid for the + * duration of enrollment and thus should be explicitly invalidated by a + * call to revokeChallenge() when enrollment is complete, to reduce the + * window of opportunity to re-use the challenge and HAT. For example, + * Settings calls generateChallenge() once to allow the user to enroll one + * or more faces or toggle secure settings without having to re-enter the + * PIN/pattern/password. Once the user completes the operation, Settings + * invokes revokeChallenge() to close the transaction. If the HAT is expired, + * the implementation must invoke onError with UNABLE_TO_PROCESS. + * + * 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 successful strong authentication request. + * @param timeoutSec A timeout in seconds, after which this enroll + * attempt is cancelled. Note that the framework can continue + * enrollment by calling this again with a valid HAT. This timeout is + * expected to be used to limit power usage if the device becomes idle + * during enrollment. The implementation is expected to send + * ERROR_TIMEOUT if this happens. + * @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 hat, uint32_t timeoutSec, vec disabledFeatures) + generates (Status status); + + /** + * Finishes the secure transaction by invalidating the challenge generated + * by generateChallenge(). + * + * Clients must call this method once the secure transaction (e.g. enroll + * or setFeature) is completed. See generateChallenge(). + * + * @return status The status of this method call. + */ + @callflow(next={"authenticate", "setActiveUser", "enumerate", "remove"}) + revokeChallenge() generates (Status status); + + /** + * 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. This method must return ILLEGAL_ARGUMENT if + * the HAT or faceId is invalid. This must only be invoked after + * setActiveUser() is called. + * + * 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(). + * + * Note: This call may block for a short amount of time (few hundred + * milliseconds). Clients are expected to invoke this asynchronously if it + * takes much longer than the above limit. Also note that the result is + * returned solely through Status (and not onError). + * + * @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(). + * @param faceId the ID of the enrollment returned by onEnrollResult() for + * the feature to update. + * @return status The status of this method call. + */ + setFeature(Feature feature, bool enabled, vec hat, uint32_t faceId) + generates(Status status); + + /** + * Retrieves the current state of the feature. If the faceId is invalid, + * the implementation must return ILLEGAL_ARGUMENT. + * + * @param faceId the ID of the enrollment returned by enroll(). + * @return result with the value set to true if the feature is enabled, + * false if disabled. + */ + getFeature(Feature feature, uint32_t faceId) generates (OptionalBool result); + + /** + * 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 the current enroll, authenticate, remove, or enumerate operation. + * + * @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. + * + * Note: This call may block for a short amount of time (few hundred + * milliseconds). Clients are expected to invoke this asynchronously if it + * takes much longer than the above limit. + * + * @param hat A valid Hardware Authentication Token, generated when the + * user authenticates with PIN/pattern/pass. When the Hardware + * Authentication Token is verified, lockout must be reset and + * onLockoutChanged must be called with duration 0. + * @return status The status of this method call. + */ + resetLockout(vec hat) generates (Status status); +}; diff --git a/biometrics/face/1.0/IBiometricsFaceClientCallback.hal b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal new file mode 100644 index 0000000000..d7c317d2f0 --- /dev/null +++ b/biometrics/face/1.0/IBiometricsFaceClientCallback.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.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 authentication 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 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 removed A list of ids that were removed. + * @param userId The active user id for the removed face template. + */ + oneway onRemoved(uint64_t deviceId, vec removed, int32_t userId); + + /** + * 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 faceIds, + int32_t userId); + + /** + * A callback invoked when the lockout state changes. + * + * This method must only be invoked when setActiveUser() is called, + * when lockout starts, and when lockout ends. When lockout starts, + * duration must be greater than 0, and when lockout ends, duration must + * be 0. This must be called before calling onError() with parameters + * LOCKOUT or LOCKOUT_PERMANENT. If the user is permanently locked out, + * the duration must be MAX_UINT64. + * + * @param duration the remaining lockout duration in milliseconds, or 0 + * if the user is not locked out. + */ + oneway onLockoutChanged(uint64_t duration); +}; diff --git a/biometrics/face/1.0/types.hal b/biometrics/face/1.0/types.hal new file mode 100644 index 0000000000..de6b99ef1d --- /dev/null +++ b/biometrics/face/1.0/types.hal @@ -0,0 +1,383 @@ +/* + * 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 occurred that cannot be resolved. Try again later. + */ + HW_UNAVAILABLE = 1, + + /** + * The current enroll or authenticate operation could not be completed, + * e.g. the sensor was unable to process the current image or the HAT was + * invalid. + */ + 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. + + * The timeout is a device-specific time meant to optimize power. For + * example after 30 seconds of searching for a face it can be use to + * indicate that the implementation is no longer looking and the framework + * should restart the operation on the next user interaction. + */ + 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, enumerate, enroll) 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 tilt 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 roll angle would be zero if the user's + * head is vertically aligned with the camera. + * + * 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, + + /** + * The sensor is dirty. The user should be informed to clean the sensor. + */ + SENSOR_DIRTY = 21, + + /** + * Used to enable a vendor-specific acquisition message. + */ + VENDOR = 22 +}; + +/** + * 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 + * getFeature() for usage of the value. + */ +struct OptionalBool { + /** + * The return status. + */ + Status status; + + /** + * This value is only meaningful if status is OK. + */ + bool value; +}; diff --git a/biometrics/face/1.0/vts/functional/Android.bp b/biometrics/face/1.0/vts/functional/Android.bp new file mode 100644 index 0000000000..fa68c4e8d7 --- /dev/null +++ b/biometrics/face/1.0/vts/functional/Android.bp @@ -0,0 +1,24 @@ +// +// 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_test { + name: "VtsHalBiometricsFaceV1_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalBiometricsFaceV1_0TargetTest.cpp"], + static_libs: ["android.hardware.biometrics.face@1.0"], + test_suites: ["general-tests"], +} + diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp new file mode 100644 index 0000000000..d3d738798b --- /dev/null +++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp @@ -0,0 +1,355 @@ +/* + * 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 "biometrics_face_hidl_hal_test" + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using android::sp; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo; +using android::hardware::biometrics::face::V1_0::FaceError; +using android::hardware::biometrics::face::V1_0::Feature; +using android::hardware::biometrics::face::V1_0::IBiometricsFace; +using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback; +using android::hardware::biometrics::face::V1_0::OptionalBool; +using android::hardware::biometrics::face::V1_0::OptionalUint64; +using android::hardware::biometrics::face::V1_0::Status; + +namespace { + +// Arbitrary, nonexistent userId +constexpr uint32_t kUserId = 9; +// Arbitrary, nonexistent faceId +constexpr uint32_t kFaceId = 5; +constexpr uint32_t kTimeoutSec = 3; +constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec); +constexpr int kGenerateChallengeIterations = 10; +constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata"; +constexpr char kCallbackNameOnEnrollResult[] = "onEnrollResult"; +constexpr char kCallbackNameOnAuthenticated[] = "onAuthenticated"; +constexpr char kCallbackNameOnAcquired[] = "onAcquired"; +constexpr char kCallbackNameOnError[] = "onError"; +constexpr char kCallbackNameOnRemoved[] = "onRemoved"; +constexpr char kCallbackNameOnEnumerate[] = "onEnumerate"; +constexpr char kCallbackNameOnLockoutChanged[] = "onLockoutChanged"; + +// Callback arguments that need to be captured for the tests. +struct FaceCallbackArgs { + // The error passed to the last onError() callback. + FaceError error; + + // The userId passed to the last onRemoved() callback. + int32_t userId; +}; + +// Test callback class for the BiometricsFace HAL. +// The HAL will call these callback methods to notify about completed operations +// or encountered errors. +class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase, + public IBiometricsFaceClientCallback { + public: + Return onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { + NotifyFromCallback(kCallbackNameOnEnrollResult); + return Void(); + } + + Return onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec&) override { + NotifyFromCallback(kCallbackNameOnAuthenticated); + return Void(); + } + + Return onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override { + NotifyFromCallback(kCallbackNameOnAcquired); + return Void(); + } + + Return onError(uint64_t, int32_t, FaceError error, int32_t) override { + FaceCallbackArgs args = {}; + args.error = error; + NotifyFromCallback(kCallbackNameOnError, args); + return Void(); + } + + Return onRemoved(uint64_t, const hidl_vec&, int32_t userId) override { + FaceCallbackArgs args = {}; + args.userId = userId; + NotifyFromCallback(kCallbackNameOnRemoved, args); + return Void(); + } + + Return onEnumerate(uint64_t, const hidl_vec&, int32_t) override { + NotifyFromCallback(kCallbackNameOnEnumerate); + return Void(); + } + + Return onLockoutChanged(uint64_t) override { + NotifyFromCallback(kCallbackNameOnLockoutChanged); + return Void(); + } +}; + +// Test environment for the BiometricsFace HAL. +class FaceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // Get the test environment singleton. + static FaceHidlEnvironment* Instance() { + static FaceHidlEnvironment* instance = new FaceHidlEnvironment; + return instance; + } + + void registerTestServices() override { registerTestService(); } + + private: + FaceHidlEnvironment() = default; +}; + +// Test class for the BiometricsFace HAL. +class FaceHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + void SetUp() override { + mService = ::testing::VtsHalHidlTargetTestBase::getService( + FaceHidlEnvironment::Instance()->getServiceName()); + ASSERT_NE(mService, nullptr); + mCallback = new FaceCallback(); + mCallback->SetWaitTimeoutDefault(kTimeout); + Return ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) { + ASSERT_EQ(Status::OK, res.status); + // Makes sure the "deviceId" represented by "res.value" is not 0. + // 0 would mean the HIDL is not available. + ASSERT_NE(0UL, res.value); + }); + ASSERT_TRUE(ret1.isOk()); + Return ret2 = mService->setActiveUser(kUserId, kFacedataDir); + ASSERT_EQ(Status::OK, static_cast(ret2)); + } + + void TearDown() override {} + + sp mService; + sp mCallback; +}; + +// generateChallenge should always return a unique, cryptographically secure, +// non-zero number. +TEST_F(FaceHidlTest, GenerateChallengeTest) { + std::map m; + for (int i = 0; i < kGenerateChallengeIterations; ++i) { + Return ret = + mService->generateChallenge(kTimeoutSec, [&m](const OptionalUint64& res) { + ASSERT_EQ(Status::OK, res.status); + EXPECT_NE(0UL, res.value); + m[res.value]++; + EXPECT_EQ(1UL, m[res.value]); + }); + ASSERT_TRUE(ret.isOk()); + } +} + +// enroll with an invalid (all zeroes) HAT should fail. +TEST_F(FaceHidlTest, EnrollZeroHatTest) { + // Filling HAT with zeros + hidl_vec token(69); + for (size_t i = 0; i < 69; i++) { + token[i] = 0; + } + + Return ret = mService->enroll(token, kTimeoutSec, {}); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // onError should be called with a meaningful (nonzero) error. + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); +} + +// enroll with an invalid HAT should fail. +TEST_F(FaceHidlTest, EnrollGarbageHatTest) { + // Filling HAT with pseudorandom invalid data. + // Using default seed to make the test reproducible. + std::mt19937 gen(std::mt19937::default_seed); + std::uniform_int_distribution dist; + hidl_vec token(69); + for (size_t i = 0; i < 69; ++i) { + token[i] = dist(gen); + } + + Return ret = mService->enroll(token, kTimeoutSec, {}); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // onError should be called with a meaningful (nonzero) error. + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); +} + +// setFeature with an invalid (all zeros) HAT should fail. +TEST_F(FaceHidlTest, SetFeatureZeroHatTest) { + hidl_vec token(69); + for (size_t i = 0; i < 69; i++) { + token[i] = 0; + } + + Return ret = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token, 0); + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, static_cast(ret)); +} + +// setFeature with an invalid HAT should fail. +TEST_F(FaceHidlTest, SetFeatureGarbageHatTest) { + // Filling HAT with pseudorandom invalid data. + // Using default seed to make the test reproducible. + std::mt19937 gen(std::mt19937::default_seed); + std::uniform_int_distribution dist; + hidl_vec token(69); + for (size_t i = 0; i < 69; ++i) { + token[i] = dist(gen); + } + + Return ret = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token, 0); + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, static_cast(ret)); +} + +void assertGetFeatureFails(const sp& service, uint32_t faceId, Feature feature) { + // Features cannot be retrieved for invalid faces. + Return res = service->getFeature(feature, faceId, [](const OptionalBool& result) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, result.status); + }); + ASSERT_TRUE(res.isOk()); +} + +TEST_F(FaceHidlTest, GetFeatureRequireAttentionTest) { + assertGetFeatureFails(mService, 0 /* faceId */, Feature::REQUIRE_ATTENTION); +} + +TEST_F(FaceHidlTest, GetFeatureRequireDiversityTest) { + assertGetFeatureFails(mService, 0 /* faceId */, Feature::REQUIRE_DIVERSITY); +} + +// revokeChallenge should always return within the timeout +TEST_F(FaceHidlTest, RevokeChallengeTest) { + auto start = std::chrono::system_clock::now(); + Return ret = mService->revokeChallenge(); + auto elapsed = std::chrono::system_clock::now() - start; + ASSERT_EQ(Status::OK, static_cast(ret)); + ASSERT_GE(kTimeout, elapsed); +} + +// The call to getAuthenticatorId should succeed. +TEST_F(FaceHidlTest, GetAuthenticatorIdTest) { + Return ret = mService->getAuthenticatorId( + [](const OptionalUint64& res) { ASSERT_EQ(Status::OK, res.status); }); + ASSERT_TRUE(ret.isOk()); +} + +// The call to enumerate should succeed. +TEST_F(FaceHidlTest, EnumerateTest) { + Return ret = mService->enumerate(); + ASSERT_EQ(Status::OK, static_cast(ret)); + auto res = mCallback->WaitForCallback(kCallbackNameOnEnumerate); + EXPECT_TRUE(res.no_timeout); +} + +// The call to remove should succeed for any faceId +TEST_F(FaceHidlTest, RemoveFaceTest) { + // Remove a face + Return ret = mService->remove(kFaceId); + ASSERT_EQ(Status::OK, static_cast(ret)); +} + +// Remove should accept 0 to delete all faces +TEST_F(FaceHidlTest, RemoveAllFacesTest) { + // Remove all faces + Return ret = mService->remove(0); + ASSERT_EQ(Status::OK, static_cast(ret)); +} + +// Active user should successfully set to a writable location. +TEST_F(FaceHidlTest, SetActiveUserTest) { + // Create an active user + Return ret = mService->setActiveUser(2, kFacedataDir); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // Reset active user + ret = mService->setActiveUser(kUserId, kFacedataDir); + ASSERT_EQ(Status::OK, static_cast(ret)); +} + +// Active user should fail to set to an unwritable location. +TEST_F(FaceHidlTest, SetActiveUserUnwritableTest) { + // Create an active user to an unwritable location (device root dir) + Return ret = mService->setActiveUser(3, "/"); + ASSERT_NE(Status::OK, static_cast(ret)); + + // Reset active user + ret = mService->setActiveUser(kUserId, kFacedataDir); + ASSERT_EQ(Status::OK, static_cast(ret)); +} + +// Active user should fail to set to a null location. +TEST_F(FaceHidlTest, SetActiveUserNullTest) { + // Create an active user to a null location. + Return ret = mService->setActiveUser(4, nullptr); + ASSERT_NE(Status::OK, static_cast(ret)); + + // Reset active user + ret = mService->setActiveUser(kUserId, kFacedataDir); + ASSERT_EQ(Status::OK, static_cast(ret)); +} + +// Cancel should always return CANCELED from any starting state including +// the IDLE state. +TEST_F(FaceHidlTest, CancelTest) { + Return ret = mService->cancel(); + // check that we were able to make an IPC request successfully + ASSERT_EQ(Status::OK, static_cast(ret)); + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + // make sure callback was invoked within kRevokeChallengeTimeout + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(FaceError::CANCELED, res.args->error); +} + +TEST_F(FaceHidlTest, OnLockoutChangedTest) { + // Update active user and ensure onLockoutChanged was called. + Return ret = mService->setActiveUser(kUserId + 1, kFacedataDir); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // Make sure callback was invoked + auto res = mCallback->WaitForCallback(kCallbackNameOnLockoutChanged); + EXPECT_TRUE(res.no_timeout); +} + +} // anonymous namespace + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(FaceHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + FaceHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} 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 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..88a726fefb 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 - #include "resources.h" +#include + namespace android { namespace hardware { namespace broadcastradio { @@ -52,6 +49,7 @@ static Properties initProperties(const VirtualRadio& virtualRadio) { static_cast(IdentifierType::AMFM_FREQUENCY), static_cast(IdentifierType::RDS_PI), static_cast(IdentifierType::HD_STATION_ID_EXT), + static_cast(IdentifierType::DAB_SID_EXT), }); prop.vendorInfo = hidl_vec({ {"com.google.dummy", "dummy"}, @@ -66,7 +64,6 @@ BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio) mAmFmConfig(gDefaultAmFmConfig) {} Return BroadcastRadio::getProperties(getProperties_cb _hidl_cb) { - ALOGV("%s", __func__); _hidl_cb(mProperties); return {}; } @@ -77,8 +74,6 @@ AmFmRegionConfig BroadcastRadio::getAmFmConfig() const { } Return BroadcastRadio::getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb) { - ALOGV("%s(%d)", __func__, full); - if (full) { AmFmRegionConfig config = {}; config.ranges = hidl_vec({ @@ -96,8 +91,6 @@ Return BroadcastRadio::getAmFmRegionConfig(bool full, getAmFmRegionConfig_ } Return BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb) { - ALOGV("%s", __func__); - hidl_vec config = { {"5A", 174928}, {"7D", 194064}, {"8A", 195936}, {"8B", 197648}, {"9A", 202928}, {"9B", 204640}, {"9C", 206352}, {"10B", 211648}, {"10C", 213360}, {"10D", 215072}, @@ -111,7 +104,7 @@ Return BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb) Return BroadcastRadio::openSession(const sp& 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 +115,7 @@ Return BroadcastRadio::openSession(const sp& 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 +127,14 @@ Return BroadcastRadio::openSession(const sp& callback, } Return 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(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 +142,7 @@ Return BroadcastRadio::getImage(uint32_t id, getImage_cb _hidl_cb) { Return BroadcastRadio::registerAnnouncementListener( const hidl_vec& enabled, const sp& /* 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 #include -#include 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 TunerSession::tune(const ProgramSelector& sel) { - ALOGV("%s(%s)", __func__, toString(sel).c_str()); + LOG(DEBUG) << "tune to " << toString(sel); + lock_guard 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 TunerSession::tune(const ProgramSelector& sel) { return Result::OK; } -Return TunerSession::scan(bool directionUp, bool /* skipSubChannel */) { - ALOGV("%s", __func__); +Return TunerSession::scan(bool directionUp, bool skipSubChannel) { + LOG(DEBUG) << "seek up=" << directionUp << " skipSubChannel=" << skipSubChannel; + lock_guard lk(mMut); if (mIsClosed) return Result::INVALID_STATE; @@ -130,8 +129,8 @@ Return 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 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 lk(mMut); tuneInternalLocked(tuneTo); @@ -173,21 +172,21 @@ Return TunerSession::scan(bool directionUp, bool /* skipSubChannel */) { } Return TunerSession::step(bool directionUp) { - ALOGV("%s", __func__); + LOG(DEBUG) << "step up=" << directionUp; lock_guard 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 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 lk(mMut); @@ -213,7 +212,7 @@ Return 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 TunerSession::cancel() { - ALOGV("%s", __func__); lock_guard lk(mMut); if (mIsClosed) return {}; @@ -232,7 +230,7 @@ Return TunerSession::cancel() { } Return TunerSession::startProgramListUpdates(const ProgramFilter& filter) { - ALOGV("%s(%s)", __func__, toString(filter).c_str()); + LOG(DEBUG) << "requested program list updates, filter=" << toString(filter); lock_guard lk(mMut); if (mIsClosed) return Result::INVALID_STATE; @@ -259,41 +257,37 @@ Return TunerSession::startProgramListUpdates(const ProgramFilter& filter } Return TunerSession::stopProgramListUpdates() { - ALOGV("%s", __func__); + LOG(DEBUG) << "requested program list updates to stop"; return {}; } Return 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 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 TunerSession::setParameters(const hidl_vec& /* parameters */, setParameters_cb _hidl_cb) { - ALOGV("%s", __func__); - _hidl_cb({}); return {}; } Return TunerSession::getParameters(const hidl_vec& /* keys */, getParameters_cb _hidl_cb) { - ALOGV("%s", __func__); - _hidl_cb({}); return {}; } Return TunerSession::close() { - ALOGV("%s", __func__); + LOG(DEBUG) << "closing session..."; lock_guard lk(mMut); if (mIsClosed) return {}; @@ -304,7 +298,7 @@ Return TunerSession::close() { std::optional 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 #include -#include 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..c59fd8ff4b 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 -#include namespace android { namespace hardware { @@ -32,6 +28,7 @@ using std::move; using std::mutex; using std::vector; using utils::make_selector_amfm; +using utils::make_selector_dab; VirtualRadio gAmFmRadio( "AM/FM radio mock", @@ -45,6 +42,16 @@ VirtualRadio gAmFmRadio( {make_selector_amfm(106100), "106 KMEL", "Drake", "Marvins Room"}, }); +// clang-format off +VirtualRadio gDabRadio( + "DAB radio mock", + { + {make_selector_dab(12345, 225648), "BBC Radio 1", "Khalid", "Talk"}, // 12B + {make_selector_dab(22345, 222064), "Classic FM", "Jean Sibelius", "Andante Festivo"}, // 11D + {make_selector_dab(32345, 222064), "Absolute Radio", "Coldplay", "Clocks"}, // 11D + }); +// clang-format on + VirtualRadio::VirtualRadio(const std::string& name, const vector& initialList) : mName(name), mPrograms(initialList) {} diff --git a/broadcastradio/2.0/default/VirtualRadio.h b/broadcastradio/2.0/default/VirtualRadio.h index 9c07816b4b..6fa70c5d16 100644 --- a/broadcastradio/2.0/default/VirtualRadio.h +++ b/broadcastradio/2.0/default/VirtualRadio.h @@ -52,6 +52,9 @@ class VirtualRadio { /** AM/FM virtual radio space. */ extern VirtualRadio gAmFmRadio; +/** DAB virtual radio space. */ +extern VirtualRadio gDabRadio; + } // namespace implementation } // namespace V2_0 } // namespace broadcastradio diff --git a/broadcastradio/2.0/default/service.cpp b/broadcastradio/2.0/default/service.cpp index 7e677a1323..349aba28e0 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 #include @@ -25,13 +23,21 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::hardware::broadcastradio::V2_0::implementation::BroadcastRadio; using android::hardware::broadcastradio::V2_0::implementation::gAmFmRadio; +using android::hardware::broadcastradio::V2_0::implementation::gDabRadio; -int main(int /* argc */, char** /* argv */) { +int main() { + android::base::SetDefaultTag("BcRadioDef"); + android::base::SetMinimumLogSeverity(android::base::VERBOSE); configureRpcThreadpool(4, true); BroadcastRadio broadcastRadio(gAmFmRadio); - auto status = broadcastRadio.registerAsService(); - CHECK_EQ(status, android::OK) << "Failed to register Broadcast Radio HAL implementation"; + auto amFmStatus = broadcastRadio.registerAsService("amfm"); + CHECK_EQ(amFmStatus, android::OK) + << "Failed to register Broadcast Radio AM/FM HAL implementation"; + + BroadcastRadio dabRadio(gDabRadio); + auto dabStatus = dabRadio.registerAsService("dab"); + CHECK_EQ(dabStatus, android::OK) << "Failed to register Broadcast Radio DAB HAL implementation"; joinRpcThreadpool(); return 1; // joinRpcThreadpool shouldn't exit 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 @@ -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; ::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/tests/Android.bp b/broadcastradio/common/tests/Android.bp index ef8733c290..0ace941ac1 100644 --- a/broadcastradio/common/tests/Android.bp +++ b/broadcastradio/common/tests/Android.bp @@ -58,6 +58,7 @@ cc_test { "android.hardware.broadcastradio@common-utils-2x-lib", ], shared_libs: [ + "libhidlbase", "android.hardware.broadcastradio@2.0", ], test_suites: ["general-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 -#include - 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 lk(mMut); mIsTerminating = true; @@ -49,8 +43,6 @@ WorkerThread::~WorkerThread() { } void WorkerThread::schedule(function task, milliseconds delay) { - ALOGV("%s", __func__); - auto when = steady_clock::now() + delay; lock_guard lk(mMut); @@ -59,14 +51,11 @@ void WorkerThread::schedule(function task, milliseconds delay) { } void WorkerThread::cancelAll() { - ALOGV("%s", __func__); - lock_guard lk(mMut); priority_queue().swap(mTasks); // empty queue } void WorkerThread::threadLoop() { - ALOGV("%s", __func__); while (!mIsTerminating) { unique_lock lk(mMut); if (mTasks.empty()) { diff --git a/broadcastradio/common/utils2x/Utils.cpp b/broadcastradio/common/utils2x/Utils.cpp index f292c0855f..43f272efdb 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 #include -#include 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; } }; @@ -301,6 +299,20 @@ ProgramSelector make_selector_amfm(uint32_t frequency) { return sel; } +ProgramSelector make_selector_dab(uint32_t sidExt, uint32_t ensemble) { + ProgramSelector sel = {}; + // TODO(maryabad): Have a helper function to create the sidExt instead of + // passing the whole identifier here. Something like make_dab_sid_ext. + sel.primaryId = make_identifier(IdentifierType::DAB_SID_EXT, sidExt); + hidl_vec secondaryIds = { + make_identifier(IdentifierType::DAB_ENSEMBLE, ensemble), + // TODO(maryabad): Include frequency here when the helper method to + // translate between ensemble and frequency is implemented. + }; + sel.secondaryIds = secondaryIds; + return sel; +} + Metadata make_metadata(MetadataKey key, int64_t value) { Metadata meta = {}; meta.key = static_cast(key); diff --git a/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h b/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h index c4aecb218f..f4e0732056 100644 --- a/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h +++ b/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h @@ -126,6 +126,7 @@ bool isValid(const V2_0::ProgramSelector& sel); V2_0::ProgramIdentifier make_identifier(V2_0::IdentifierType type, uint64_t value); V2_0::ProgramSelector make_selector_amfm(uint32_t frequency); +V2_0::ProgramSelector make_selector_dab(uint32_t sidExt, uint32_t ensemble); V2_0::Metadata make_metadata(V2_0::MetadataKey key, int64_t value); V2_0::Metadata make_metadata(V2_0::MetadataKey key, std::string value); 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/Android.bp b/camera/common/1.0/default/Android.bp index 21f81f5acc..3e5c6d7812 100644 --- a/camera/common/1.0/default/Android.bp +++ b/camera/common/1.0/default/Android.bp @@ -20,6 +20,7 @@ cc_library_static { "libhardware", "libcamera_metadata", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "libexif", ], include_dirs: ["system/media/private/camera/include"], diff --git a/camera/common/1.0/default/CameraMetadata.cpp b/camera/common/1.0/default/CameraMetadata.cpp index 4c54931a11..eb1bd1c149 100644 --- a/camera/common/1.0/default/CameraMetadata.cpp +++ b/camera/common/1.0/default/CameraMetadata.cpp @@ -171,17 +171,16 @@ status_t CameraMetadata::sort() { } status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) { - int tagType = get_camera_metadata_tag_type(tag); + int tagType = get_local_camera_metadata_tag_type(tag, mBuffer); if ( CC_UNLIKELY(tagType == -1)) { ALOGE("Update metadata entry: Unknown tag %d", tag); return INVALID_OPERATION; } if ( CC_UNLIKELY(tagType != expectedType) ) { ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; " - "got type %s data instead ", - get_camera_metadata_tag_name(tag), tag, - camera_metadata_type_names[tagType], - camera_metadata_type_names[expectedType]); + "got type %s data instead ", + get_local_camera_metadata_tag_name(tag, mBuffer), tag, + camera_metadata_type_names[tagType], camera_metadata_type_names[expectedType]); return INVALID_OPERATION; } return OK; @@ -298,7 +297,7 @@ status_t CameraMetadata::updateImpl(uint32_t tag, const void *data, ALOGE("%s: CameraMetadata is locked", __FUNCTION__); return INVALID_OPERATION; } - int type = get_camera_metadata_tag_type(tag); + int type = get_local_camera_metadata_tag_type(tag, mBuffer); if (type == -1) { ALOGE("%s: Tag %d not found", __FUNCTION__, tag); return BAD_VALUE; @@ -332,9 +331,9 @@ status_t CameraMetadata::updateImpl(uint32_t tag, const void *data, } if (res != OK) { - ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)", - __FUNCTION__, get_camera_metadata_section_name(tag), - get_camera_metadata_tag_name(tag), tag, strerror(-res), res); + ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)", __FUNCTION__, + get_local_camera_metadata_section_name(tag, mBuffer), + get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res); } IF_ALOGV() { @@ -391,18 +390,16 @@ status_t CameraMetadata::erase(uint32_t tag) { if (res == NAME_NOT_FOUND) { return OK; } else if (res != OK) { - ALOGE("%s: Error looking for entry %s.%s (%x): %s %d", - __FUNCTION__, - get_camera_metadata_section_name(tag), - get_camera_metadata_tag_name(tag), tag, strerror(-res), res); + ALOGE("%s: Error looking for entry %s.%s (%x): %s %d", __FUNCTION__, + get_local_camera_metadata_section_name(tag, mBuffer), + get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res); return res; } res = delete_camera_metadata_entry(mBuffer, entry.index); if (res != OK) { - ALOGE("%s: Error deleting entry %s.%s (%x): %s %d", - __FUNCTION__, - get_camera_metadata_section_name(tag), - get_camera_metadata_tag_name(tag), tag, strerror(-res), res); + ALOGE("%s: Error deleting entry %s.%s (%x): %s %d", __FUNCTION__, + get_local_camera_metadata_section_name(tag, mBuffer), + get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res); } return res; } diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp index dc4e0f01ff..467c121a94 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); @@ -253,6 +253,14 @@ CameraModule::~CameraModule() } mCameraInfoMap.removeItemsAt(0); } + + while (mPhysicalCameraInfoMap.size() > 0) { + camera_metadata_t* metadata = mPhysicalCameraInfoMap.editValueAt(0); + if (metadata != NULL) { + free_camera_metadata(metadata); + } + mPhysicalCameraInfoMap.removeItemsAt(0); + } } int CameraModule::init() { @@ -264,7 +272,8 @@ int CameraModule::init() { res = mModule->init(); ATRACE_END(); } - mCameraInfoMap.setCapacity(getNumberOfCameras()); + mNumberOfCameras = getNumberOfCameras(); + mCameraInfoMap.setCapacity(mNumberOfCameras); return res; } @@ -319,6 +328,52 @@ 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; + } + + // The camera_metadata_t returned by get_physical_camera_info could be using + // more memory than necessary due to unused reserved space. Reduce the + // size by appending it to a new CameraMetadata object, which internally + // calls resizeIfNeeded. + CameraMetadata m; + m.append(info); + camera_metadata_t* derivedMetadata = m.release(); + index = mPhysicalCameraInfoMap.add(physicalCameraId, derivedMetadata); + } + + 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 +467,64 @@ 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; +} + +void CameraModule::notifyDeviceStateChange(uint64_t deviceState) { + if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_5 && + mModule->notify_device_state_change != NULL) { + ATRACE_BEGIN("camera_module->notify_device_state_change"); + ALOGI("%s: calling notify_device_state_change with state %" PRId64, __FUNCTION__, + deviceState); + mModule->notify_device_state_change(deviceState); + ATRACE_END(); + } +} + +bool CameraModule::isLogicalMultiCamera( + const common::V1_0::helper::CameraMetadata& metadata, + std::unordered_set* physicalCameraIds) { + if (physicalCameraIds == nullptr) { + ALOGE("%s: physicalCameraIds must not be null", __FUNCTION__); + return false; + } + + bool isLogicalMultiCamera = false; + camera_metadata_ro_entry_t capabilities = + metadata.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); + for (size_t i = 0; i < capabilities.count; i++) { + if (capabilities.data.u8[i] == + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) { + isLogicalMultiCamera = true; + break; + } + } + + if (isLogicalMultiCamera) { + camera_metadata_ro_entry_t entry = + metadata.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS); + const uint8_t* ids = entry.data.u8; + size_t start = 0; + for (size_t i = 0; i < entry.count; ++i) { + if (ids[i] == '\0') { + if (start != i) { + const char* physicalId = reinterpret_cast(ids+start); + physicalCameraIds->emplace(physicalId); + } + start = i + 1; + } + } + } + return isLogicalMultiCamera; +} + status_t CameraModule::filterOpenErrorCode(status_t err) { switch(err) { case NO_ERROR: @@ -426,8 +539,24 @@ status_t CameraModule::filterOpenErrorCode(status_t err) { } void CameraModule::removeCamera(int cameraId) { - free_camera_metadata( - const_cast(mCameraInfoMap[cameraId].static_camera_characteristics)); + std::unordered_set physicalIds; + camera_metadata_t *metadata = const_cast( + mCameraInfoMap.valueFor(cameraId).static_camera_characteristics); + common::V1_0::helper::CameraMetadata hidlMetadata(metadata); + + if (isLogicalMultiCamera(hidlMetadata, &physicalIds)) { + for (const auto& id : physicalIds) { + int idInt = std::stoi(id); + if (mPhysicalCameraInfoMap.indexOfKey(idInt) >= 0) { + free_camera_metadata(mPhysicalCameraInfoMap[idInt]); + mPhysicalCameraInfoMap.removeItem(idInt); + } else { + ALOGE("%s: Cannot find corresponding static metadata for physical id %s", + __FUNCTION__, id.c_str()); + } + } + } + free_camera_metadata(metadata); mCameraInfoMap.removeItem(cameraId); mDeviceVersionMap.removeItem(cameraId); } diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp index 21706a84a3..b8c40e95b8 100644 --- a/camera/common/1.0/default/HandleImporter.cpp +++ b/camera/common/1.0/default/HandleImporter.cpp @@ -25,7 +25,9 @@ namespace common { namespace V1_0 { namespace helper { -using MapperError = android::hardware::graphics::mapper::V2_0::Error; +using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error; +using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error; +using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper; HandleImporter::HandleImporter() : mInitialized(false) {} @@ -34,8 +36,14 @@ void HandleImporter::initializeLocked() { return; } - mMapper = IMapper::getService(); - if (mMapper == nullptr) { + mMapperV3 = IMapperV3::getService(); + if (mMapperV3 != nullptr) { + mInitialized = true; + return; + } + + mMapperV2 = IMapper::getService(); + if (mMapperV2 == nullptr) { ALOGE("%s: cannnot acccess graphics mapper HAL!", __FUNCTION__); return; } @@ -45,10 +53,90 @@ void HandleImporter::initializeLocked() { } void HandleImporter::cleanup() { - mMapper.clear(); + mMapperV3.clear(); + mMapperV2.clear(); mInitialized = false; } +template +bool HandleImporter::importBufferInternal(const sp mapper, buffer_handle_t& handle) { + E error; + buffer_handle_t importedHandle; + auto ret = mapper->importBuffer( + hidl_handle(handle), + [&](const auto& tmpError, const auto& tmpBufferHandle) { + error = tmpError; + importedHandle = static_cast(tmpBufferHandle); + }); + + if (!ret.isOk()) { + ALOGE("%s: mapper importBuffer failed: %s", + __FUNCTION__, ret.description().c_str()); + return false; + } + + if (error != E::NONE) { + return false; + } + + handle = importedHandle; + return true; +} + +template +YCbCrLayout HandleImporter::lockYCbCrInternal(const sp mapper, buffer_handle_t& buf, + uint64_t cpuUsage, const IMapper::Rect& accessRegion) { + hidl_handle acquireFenceHandle; + auto buffer = const_cast(buf); + YCbCrLayout layout = {}; + + typename M::Rect accessRegionCopy = {accessRegion.left, accessRegion.top, + accessRegion.width, accessRegion.height}; + mapper->lockYCbCr(buffer, cpuUsage, accessRegionCopy, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpLayout) { + if (tmpError == E::NONE) { + // Member by member copy from different versions of YCbCrLayout. + layout.y = tmpLayout.y; + layout.cb = tmpLayout.cb; + layout.cr = tmpLayout.cr; + layout.yStride = tmpLayout.yStride; + layout.cStride = tmpLayout.cStride; + layout.chromaStep = tmpLayout.chromaStep; + } else { + ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError); + } + }); + return layout; +} + +template +int HandleImporter::unlockInternal(const sp mapper, buffer_handle_t& buf) { + int releaseFence = -1; + auto buffer = const_cast(buf); + + mapper->unlock( + buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) { + if (tmpError == E::NONE) { + auto fenceHandle = tmpReleaseFence.getNativeHandle(); + if (fenceHandle) { + if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) { + ALOGE("%s: bad release fence numInts %d numFds %d", + __FUNCTION__, fenceHandle->numInts, fenceHandle->numFds); + return; + } + releaseFence = dup(fenceHandle->data[0]); + if (releaseFence < 0) { + ALOGE("%s: bad release fence FD %d", + __FUNCTION__, releaseFence); + } + } + } else { + ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError); + } + }); + return releaseFence; +} + // In IComposer, any buffer_handle_t is owned by the caller and we need to // make a clone for hwcomposer2. We also need to translate empty handle // to nullptr. This function does that, in-place. @@ -63,33 +151,16 @@ bool HandleImporter::importBuffer(buffer_handle_t& handle) { initializeLocked(); } - if (mMapper == nullptr) { - ALOGE("%s: mMapper is null!", __FUNCTION__); - return false; + if (mMapperV3 != nullptr) { + return importBufferInternal(mMapperV3, handle); } - MapperError error; - buffer_handle_t importedHandle; - auto ret = mMapper->importBuffer( - hidl_handle(handle), - [&](const auto& tmpError, const auto& tmpBufferHandle) { - error = tmpError; - importedHandle = static_cast(tmpBufferHandle); - }); - - if (!ret.isOk()) { - ALOGE("%s: mapper importBuffer failed: %s", - __FUNCTION__, ret.description().c_str()); - return false; + if (mMapperV2 != nullptr) { + return importBufferInternal(mMapperV2, handle); } - if (error != MapperError::NONE) { - return false; - } - - handle = importedHandle; - - return true; + ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); + return false; } void HandleImporter::freeBuffer(buffer_handle_t handle) { @@ -98,15 +169,23 @@ void HandleImporter::freeBuffer(buffer_handle_t handle) { } Mutex::Autolock lock(mLock); - if (mMapper == nullptr) { - ALOGE("%s: mMapper is null!", __FUNCTION__); + if (mMapperV3 == nullptr && mMapperV2 == nullptr) { + ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); return; } - auto ret = mMapper->freeBuffer(const_cast(handle)); - if (!ret.isOk()) { - ALOGE("%s: mapper freeBuffer failed: %s", - __FUNCTION__, ret.description().c_str()); + if (mMapperV3 != nullptr) { + auto ret = mMapperV3->freeBuffer(const_cast(handle)); + if (!ret.isOk()) { + ALOGE("%s: mapper freeBuffer failed: %s", + __FUNCTION__, ret.description().c_str()); + } + } else { + auto ret = mMapperV2->freeBuffer(const_cast(handle)); + if (!ret.isOk()) { + ALOGE("%s: mapper freeBuffer failed: %s", + __FUNCTION__, ret.description().c_str()); + } } } @@ -138,91 +217,82 @@ void* HandleImporter::lock( buffer_handle_t& buf, uint64_t cpuUsage, size_t size) { Mutex::Autolock lock(mLock); void *ret = 0; - IMapper::Rect accessRegion { 0, 0, static_cast(size), 1 }; if (!mInitialized) { initializeLocked(); } - if (mMapper == nullptr) { - ALOGE("%s: mMapper is null!", __FUNCTION__); + if (mMapperV3 == nullptr && mMapperV2 == nullptr) { + ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); return ret; } hidl_handle acquireFenceHandle; auto buffer = const_cast(buf); - mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, - [&](const auto& tmpError, const auto& tmpPtr) { - if (tmpError == MapperError::NONE) { - ret = tmpPtr; - } else { - ALOGE("%s: failed to lock error %d!", - __FUNCTION__, tmpError); - } - }); + if (mMapperV3 != nullptr) { + IMapperV3::Rect accessRegion { 0, 0, static_cast(size), 1 }; + // No need to use bytesPerPixel and bytesPerStride because we are using + // an 1-D buffer and accressRegion. + mMapperV3->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/, + const auto& /*bytesPerStride*/) { + if (tmpError == MapperErrorV3::NONE) { + ret = tmpPtr; + } else { + ALOGE("%s: failed to lock error %d!", + __FUNCTION__, tmpError); + } + }); + } else { + IMapper::Rect accessRegion { 0, 0, static_cast(size), 1 }; + mMapperV2->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpPtr) { + if (tmpError == MapperErrorV2::NONE) { + ret = tmpPtr; + } else { + ALOGE("%s: failed to lock error %d!", + __FUNCTION__, tmpError); + } + }); + } ALOGV("%s: ptr %p size: %zu", __FUNCTION__, ret, size); return ret; } - YCbCrLayout HandleImporter::lockYCbCr( buffer_handle_t& buf, uint64_t cpuUsage, const IMapper::Rect& accessRegion) { Mutex::Autolock lock(mLock); - YCbCrLayout layout = {}; if (!mInitialized) { initializeLocked(); } - if (mMapper == nullptr) { - ALOGE("%s: mMapper is null!", __FUNCTION__); - return layout; + if (mMapperV3 != nullptr) { + return lockYCbCrInternal( + mMapperV3, buf, cpuUsage, accessRegion); } - hidl_handle acquireFenceHandle; - auto buffer = const_cast(buf); - mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle, - [&](const auto& tmpError, const auto& tmpLayout) { - if (tmpError == MapperError::NONE) { - layout = tmpLayout; - } else { - ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError); - } - }); + if (mMapperV2 != nullptr) { + return lockYCbCrInternal( + mMapperV2, buf, cpuUsage, accessRegion); + } - ALOGV("%s: layout y %p cb %p cr %p y_str %d c_str %d c_step %d", - __FUNCTION__, layout.y, layout.cb, layout.cr, - layout.yStride, layout.cStride, layout.chromaStep); - return layout; + ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); + return {}; } int HandleImporter::unlock(buffer_handle_t& buf) { - int releaseFence = -1; - auto buffer = const_cast(buf); - mMapper->unlock( - buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) { - if (tmpError == MapperError::NONE) { - auto fenceHandle = tmpReleaseFence.getNativeHandle(); - if (fenceHandle) { - if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) { - ALOGE("%s: bad release fence numInts %d numFds %d", - __FUNCTION__, fenceHandle->numInts, fenceHandle->numFds); - return; - } - releaseFence = dup(fenceHandle->data[0]); - if (releaseFence <= 0) { - ALOGE("%s: bad release fence FD %d", - __FUNCTION__, releaseFence); - } - } - } else { - ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError); - } - }); + if (mMapperV3 != nullptr) { + return unlockInternal(mMapperV3, buf); + } + if (mMapperV2 != nullptr) { + return unlockInternal(mMapperV2, buf); + } - return releaseFence; + ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__); + return -1; } } // namespace helper diff --git a/camera/common/1.0/default/OWNERS b/camera/common/1.0/default/OWNERS index 18acfee145..f48a95c5b3 100644 --- a/camera/common/1.0/default/OWNERS +++ b/camera/common/1.0/default/OWNERS @@ -1,6 +1 @@ -cychen@google.com -epeev@google.com -etalvala@google.com -shuzhenwang@google.com -yinchiayeh@google.com -zhijunhe@google.com +include platform/frameworks/av:/camera/OWNERS 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 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* 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 sGlobalVendorTagDescriptor; +static sp sGlobalVendorTagDescriptorCache; status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps, /*out*/ @@ -310,6 +404,39 @@ sp VendorTagDescriptor::getGlobalVendorTagDescriptor() { return sGlobalVendorTagDescriptor; } +status_t VendorTagDescriptorCache::setAsGlobalVendorTagCache( + const sp& 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::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..c89e934655 100644 --- a/camera/common/1.0/default/include/CameraModule.h +++ b/camera/common/1.0/default/include/CameraModule.h @@ -17,6 +17,9 @@ #ifndef CAMERA_COMMON_1_0_CAMERAMODULE_H #define CAMERA_COMMON_1_0_CAMERAMODULE_H +#include +#include + #include #include #include @@ -65,6 +68,13 @@ 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); + void notifyDeviceStateChange(uint64_t deviceState); + + static bool isLogicalMultiCamera( + const common::V1_0::helper::CameraMetadata& metadata, + std::unordered_set* physicalCameraIds); private: // Derive camera characteristics keys defined after HAL device version @@ -74,8 +84,10 @@ private: int32_t keyTag, const Vector& appendKeys); status_t filterOpenErrorCode(status_t err); camera_module_t *mModule; + int mNumberOfCameras; KeyedVector mCameraInfoMap; KeyedVector mDeviceVersionMap; + KeyedVector mPhysicalCameraInfoMap; Mutex mCameraInfoLock; }; diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h index f9cd9fb604..a93d4554ad 100644 --- a/camera/common/1.0/default/include/HandleImporter.h +++ b/camera/common/1.0/default/include/HandleImporter.h @@ -19,6 +19,7 @@ #include #include +#include #include using android::hardware::graphics::mapper::V2_0::IMapper; @@ -57,10 +58,18 @@ private: void initializeLocked(); void cleanup(); + template + bool importBufferInternal(const sp mapper, buffer_handle_t& handle); + template + YCbCrLayout lockYCbCrInternal(const sp mapper, buffer_handle_t& buf, uint64_t cpuUsage, + const IMapper::Rect& accessRegion); + template + int unlockInternal(const sp mapper, buffer_handle_t& buf); + Mutex mLock; bool mInitialized; - sp mMapper; - + sp mMapperV2; + sp mMapperV3; }; } // namespace helper 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 desc); + + int32_t getVendorTagDescriptor(metadata_vendor_id_t id, sp* 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> 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 { + 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& cache); + + /** + * Returns the global vendor tag cache used by this process. + * This will contain NULL if no vendor tags are defined. + */ + static sp 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/Android.bp b/camera/device/1.0/default/Android.bp index 4a7fc9c1e0..aa3b941c2e 100644 --- a/camera/device/1.0/default/Android.bp +++ b/camera/device/1.0/default/Android.bp @@ -15,6 +15,7 @@ cc_library_shared { "android.hardware.camera.common@1.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "android.hardware.graphics.common@1.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", diff --git a/camera/device/1.0/default/OWNERS b/camera/device/1.0/default/OWNERS index 18acfee145..f48a95c5b3 100644 --- a/camera/device/1.0/default/OWNERS +++ b/camera/device/1.0/default/OWNERS @@ -1,6 +1 @@ -cychen@google.com -epeev@google.com -etalvala@google.com -shuzhenwang@google.com -yinchiayeh@google.com -zhijunhe@google.com +include platform/frameworks/av:/camera/OWNERS diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal index 69715dec64..dec3bd88c6 100644 --- a/camera/device/3.2/ICameraDeviceCallback.hal +++ b/camera/device/3.2/ICameraDeviceCallback.hal @@ -125,6 +125,21 @@ interface ICameraDeviceCallback { * via a SHUTTER notify() call. It is highly recommended to dispatch this * call as early as possible. * + * The SHUTTER notify calls for requests with android.control.enableZsl + * set to TRUE and ANDROID_CONTROL_CAPTURE_INTENT == STILL_CAPTURE may be + * out-of-order compared to SHUTTER notify for other kinds of requests + * (including regular, reprocess, or zero-shutter-lag requests with + * different capture intents). + * + * As a result, the capture results of zero-shutter-lag requests with + * ANDROID_CONTROL_CAPTURE_INTENT == STILL_CAPTURE may be out-of-order + * compared to capture results for other kinds of requests. + * + * Different SHUTTER notify calls for zero-shutter-lag requests with + * ANDROID_CONTROL_CAPTURE_INTENT == STILL_CAPTURE must be in order between + * them, as is for other kinds of requests. SHUTTER notify calls for + * zero-shutter-lag requests with non STILL_CAPTURE intent must be in order + * with SHUTTER notify calls for regular requests. * ------------------------------------------------------------------------ * Performance requirements: * diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp index 325c0085a4..edb008ed62 100644 --- a/camera/device/3.2/default/Android.bp +++ b/camera/device/3.2/default/Android.bp @@ -13,6 +13,7 @@ cc_library_shared { "android.hardware.camera.device@3.2", "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "liblog", "libhardware", "libcamera_metadata", 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 CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { +Return CameraDevice::getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb) { Status status = initStatus(); CameraResourceCost resCost; if (status == Status::OK) { @@ -141,7 +141,8 @@ Return CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { return Void(); } -Return CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) { +Return CameraDevice::getCameraCharacteristics( + ICameraDevice::getCameraCharacteristics_cb _hidl_cb) { Status status = initStatus(); CameraMetadata cameraCharacteristics; if (status == Status::OK) { @@ -172,7 +173,8 @@ Return CameraDevice::setTorchMode(TorchMode mode) { return status; } -Return CameraDevice::open(const sp& callback, open_cb _hidl_cb) { +Return CameraDevice::open(const sp& callback, + ICameraDevice::open_cb _hidl_cb) { Status status = initStatus(); sp session = nullptr; diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp index fd785df1a9..99cdccbcdb 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& callback) : - camera3_callback_ops({&sProcessCaptureResult, &sNotify}), + camera3_callback_ops({&sProcessCaptureResult, &sNotify, nullptr, nullptr}), mDevice(device), mDeviceVersion(device->common.version), mFreeBufEarly(shouldFreeBufEarly()), @@ -97,11 +99,20 @@ bool CameraDeviceSession::initialize() { return true; } - int32_t reqFMQSize = property_get_int32("ro.camera.req.fmq.size", /*default*/-1); + // "ro.camera" properties are no longer supported on vendor side. + // Support a fall back for the fmq size override that uses "ro.vendor.camera" + // properties. + int32_t reqFMQSize = property_get_int32("ro.vendor.camera.req.fmq.size", /*default*/-1); if (reqFMQSize < 0) { - reqFMQSize = CAMERA_REQUEST_METADATA_QUEUE_SIZE; + reqFMQSize = property_get_int32("ro.camera.req.fmq.size", /*default*/-1); + if (reqFMQSize < 0) { + reqFMQSize = CAMERA_REQUEST_METADATA_QUEUE_SIZE; + } else { + ALOGV("%s: request FMQ size overridden to %d", __FUNCTION__, reqFMQSize); + } } else { - ALOGV("%s: request FMQ size overridden to %d", __FUNCTION__, reqFMQSize); + ALOGV("%s: request FMQ size overridden to %d via fallback property", __FUNCTION__, + reqFMQSize); } mRequestMetadataQueue = std::make_unique( @@ -112,12 +123,22 @@ bool CameraDeviceSession::initialize() { return true; } - int32_t resFMQSize = property_get_int32("ro.camera.res.fmq.size", /*default*/-1); + // "ro.camera" properties are no longer supported on vendor side. + // Support a fall back for the fmq size override that uses "ro.vendor.camera" + // properties. + int32_t resFMQSize = property_get_int32("ro.vendor.camera.res.fmq.size", /*default*/-1); if (resFMQSize < 0) { - resFMQSize = CAMERA_RESULT_METADATA_QUEUE_SIZE; + resFMQSize = property_get_int32("ro.camera.res.fmq.size", /*default*/-1); + if (resFMQSize < 0) { + resFMQSize = CAMERA_RESULT_METADATA_QUEUE_SIZE; + } else { + ALOGV("%s: result FMQ size overridden to %d", __FUNCTION__, resFMQSize); + } } else { - ALOGV("%s: result FMQ size overridden to %d", __FUNCTION__, resFMQSize); + ALOGV("%s: result FMQ size overridden to %d via fallback property", __FUNCTION__, + resFMQSize); } + mResultMetadataQueue = std::make_shared( static_cast(resFMQSize), false /* non blocking */); @@ -246,10 +267,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& allBufPtrs, hidl_vec& allFences) { + return importRequestImpl(request, allBufPtrs, allFences); +} + +Status CameraDeviceSession::importRequestImpl( + const CaptureRequest& request, + hidl_vec& allBufPtrs, + hidl_vec& allFences, + bool allowEmptyBuf) { bool hasInputBuf = (request.inputBuffer.streamId != -1 && request.inputBuffer.bufferId != 0); size_t numOutputBufs = request.outputBuffers.size(); @@ -277,25 +338,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 +1322,26 @@ Return 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 +1455,14 @@ status_t CameraDeviceSession::constructCaptureResult(CaptureResult& result, result.outputBuffers[i].streamId = static_cast(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 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 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& allBufPtrs, hidl_vec& allFences); + Status importRequestImpl( + const CaptureRequest& request, + hidl_vec& allBufPtrs, + hidl_vec& 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& 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 module, const std::string& cameraId, const SortedVector>& 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 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 getResourceCost(getResourceCost_cb _hidl_cb) override; - Return getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override; - Return setTorchMode(TorchMode mode) override; + Return getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb); + Return getCameraCharacteristics(ICameraDevice::getCameraCharacteristics_cb _hidl_cb); + Return setTorchMode(TorchMode mode); // Open the device HAL and also return a default capture session - Return open(const sp& callback, open_cb _hidl_cb) override; + Return open(const sp& callback, ICameraDevice::open_cb _hidl_cb); // Forward the dump call to the opened session, or do nothing - Return dumpState(const ::android::hardware::hidl_handle& fd) override; + Return 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 parent) : + mParent(parent) {} + + virtual Return getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return open(const sp& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + private: + sp mParent; + }; + }; } // namespace implementation diff --git a/camera/device/3.2/default/OWNERS b/camera/device/3.2/default/OWNERS index 18acfee145..f48a95c5b3 100644 --- a/camera/device/3.2/default/OWNERS +++ b/camera/device/3.2/default/OWNERS @@ -1,6 +1 @@ -cychen@google.com -epeev@google.com -etalvala@google.com -shuzhenwang@google.com -yinchiayeh@google.com -zhijunhe@google.com +include platform/frameworks/av:/camera/OWNERS diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp index b1e9b46d8f..39d379d049 100644 --- a/camera/device/3.3/default/Android.bp +++ b/camera/device/3.3/default/Android.bp @@ -15,6 +15,7 @@ cc_library_shared { "android.hardware.camera.device@3.3", "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "liblog", "libhardware", "libcamera_metadata", diff --git a/camera/device/3.3/default/OWNERS b/camera/device/3.3/default/OWNERS index 18acfee145..f48a95c5b3 100644 --- a/camera/device/3.3/default/OWNERS +++ b/camera/device/3.3/default/OWNERS @@ -1,6 +1 @@ -cychen@google.com -epeev@google.com -etalvala@google.com -shuzhenwang@google.com -yinchiayeh@google.com -zhijunhe@google.com +include platform/frameworks/av:/camera/OWNERS diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp index 272bf42baa..c22b13c2c4 100644 --- a/camera/device/3.4/default/Android.bp +++ b/camera/device/3.4/default/Android.bp @@ -48,6 +48,7 @@ cc_library_shared { "android.hardware.camera.device@3.4", "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "liblog", "libhardware", "libcamera_metadata", @@ -84,6 +85,7 @@ cc_library_shared { "android.hardware.camera.device@3.4", "android.hardware.camera.provider@2.4", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "liblog", "libhardware", "libcamera_metadata", diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp index f2e031c674..b4ebe22701 100644 --- a/camera/device/3.4/default/CameraDeviceSession.cpp +++ b/camera/device/3.4/default/CameraDeviceSession.cpp @@ -22,6 +22,7 @@ #include #include #include "CameraDeviceSession.h" +#include "CameraModule.h" namespace android { namespace hardware { @@ -30,6 +31,8 @@ namespace device { namespace V3_4 { namespace implementation { +using ::android::hardware::camera::common::V1_0::helper::CameraModule; + CameraDeviceSession::CameraDeviceSession( camera3_device_t* device, const camera_metadata_t* deviceInfo, @@ -54,31 +57,9 @@ CameraDeviceSession::CameraDeviceSession( mResultBatcher_3_4.setNumPartialResults(mNumPartialResults); - camera_metadata_entry_t capabilities = - mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); - bool isLogicalMultiCamera = false; - for (size_t i = 0; i < capabilities.count; i++) { - if (capabilities.data.u8[i] == - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) { - isLogicalMultiCamera = true; - break; - } - } - if (isLogicalMultiCamera) { - camera_metadata_entry entry = - mDeviceInfo.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS); - const uint8_t* ids = entry.data.u8; - size_t start = 0; - for (size_t i = 0; i < entry.count; ++i) { - if (ids[i] == '\0') { - if (start != i) { - const char* physicalId = reinterpret_cast(ids+start); - mPhysicalCameraIds.emplace(physicalId); - } - start = i + 1; - } - } - } + // Parse and store current logical camera's physical ids. + (void)CameraModule::isLogicalMultiCamera(mDeviceInfo, &mPhysicalCameraIds); + } CameraDeviceSession::~CameraDeviceSession() { @@ -87,6 +68,14 @@ CameraDeviceSession::~CameraDeviceSession() { Return 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, bool useOverriddenFields) { Status status = initStatus(); HalStreamConfiguration outStreams; @@ -97,7 +86,7 @@ Return 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 +98,7 @@ Return 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 +106,7 @@ Return CameraDeviceSession::configureStreams_3_4( " trigger overrides!", __FUNCTION__, mInflightAETriggerOverrides.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } if (!mInflightRawBoostPresent.empty()) { @@ -125,12 +114,12 @@ Return 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 +128,15 @@ Return CameraDeviceSession::configureStreams_3_4( } camera3_stream_configuration_t stream_list{}; + // Block reading mStreamConfigCounter until configureStream returns + Mutex::Autolock _sccl(mStreamConfigCounterLock); + mStreamConfigCounter = streamConfigCounter; hidl_vec streams; stream_list.session_parameters = paramBuffer; - if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) { + if (!preProcessConfigurationLocked_3_4(requestedConfiguration, + useOverriddenFields, &stream_list, &streams)) { _hidl_cb(Status::INTERNAL_ERROR, outStreams); - return Void(); + return; } ATRACE_BEGIN("camera3->configure_streams"); @@ -168,11 +161,11 @@ Return CameraDeviceSession::configureStreams_3_4( } _hidl_cb(status, outStreams); - return Void(); + return; } bool CameraDeviceSession::preProcessConfigurationLocked_3_4( - const StreamConfiguration& requestedConfiguration, + const StreamConfiguration& requestedConfiguration, bool useOverriddenFields, camera3_stream_configuration_t *stream_list /*out*/, hidl_vec *streams /*out*/) { @@ -195,25 +188,41 @@ bool CameraDeviceSession::preProcessConfigurationLocked_3_4( mPhysicalCameraIdMap[id] = requestedConfiguration.streams[i].physicalCameraId; mStreamMap[id].data_space = mapToLegacyDataspace( mStreamMap[id].data_space); - mStreamMap[id].physical_camera_id = mPhysicalCameraIdMap[id].c_str(); mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{}); } else { - // width/height/format must not change, but usage/rotation might need to change + // width/height/format must not change, but usage/rotation might need to change. + // format and data_space may change. if (mStreamMap[id].stream_type != (int) requestedConfiguration.streams[i].v3_2.streamType || mStreamMap[id].width != requestedConfiguration.streams[i].v3_2.width || mStreamMap[id].height != requestedConfiguration.streams[i].v3_2.height || - mStreamMap[id].format != (int) requestedConfiguration.streams[i].v3_2.format || - mStreamMap[id].data_space != - mapToLegacyDataspace( static_cast ( - requestedConfiguration.streams[i].v3_2.dataSpace)) || mPhysicalCameraIdMap[id] != requestedConfiguration.streams[i].physicalCameraId) { ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id); return false; } + if (useOverriddenFields) { + android_dataspace_t requestedDataSpace = + mapToLegacyDataspace(static_cast( + requestedConfiguration.streams[i].v3_2.dataSpace)); + if (mStreamMap[id].format != (int) requestedConfiguration.streams[i].v3_2.format || + mStreamMap[id].data_space != requestedDataSpace) { + ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id); + return false; + } + } else { + mStreamMap[id].format = + (int) requestedConfiguration.streams[i].v3_2.format; + mStreamMap[id].data_space = (android_dataspace_t) + requestedConfiguration.streams[i].v3_2.dataSpace; + } mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].v3_2.rotation; mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].v3_2.usage; } + // It is possible for the entry in 'mStreamMap' to get initialized by an older + // HIDL API. Make sure that the physical id is always initialized when using + // a more recent API call. + mStreamMap[id].physical_camera_id = mPhysicalCameraIdMap[id].c_str(); + (*streams)[i] = &mStreamMap[id]; } diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp index 38a78e070c..9a2fddff88 100644 --- a/camera/device/3.4/default/ExternalCameraDevice.cpp +++ b/camera/device/3.4/default/ExternalCameraDevice.cpp @@ -47,24 +47,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 ExternalCameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { +Return ExternalCameraDevice::getResourceCost( + ICameraDevice::getResourceCost_cb _hidl_cb) { CameraResourceCost resCost; resCost.resourceCost = 100; _hidl_cb(Status::OK, resCost); @@ -72,11 +79,11 @@ Return ExternalCameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) } Return 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(); } @@ -93,7 +100,7 @@ Return ExternalCameraDevice::setTorchMode(TorchMode) { } Return ExternalCameraDevice::open( - const sp& callback, open_cb _hidl_cb) { + const sp& callback, ICameraDevice::open_cb _hidl_cb) { Status status = Status::OK; sp session = nullptr; @@ -142,7 +149,7 @@ Return ExternalCameraDevice::open( } } - session = new ExternalCameraDeviceSession( + session = createSession( callback, mCfg, mSupportedFormats, mCroppingType, mCameraCharacteristics, mCameraId, std::move(fd)); if (session == nullptr) { @@ -335,8 +342,7 @@ status_t ExternalCameraDevice::initDefaultCharsKeys( 256, 144, 240, 160, 256, 154, - 240, 240, - 320, 240}; + 240, 180}; UPDATE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegAvailableThumbnailSizes, ARRAY_SIZE(jpegAvailableThumbnailSizes)); @@ -404,8 +410,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 @@ -512,52 +522,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; } @@ -1030,6 +997,18 @@ void ExternalCameraDevice::initSupportedFormatsLocked(int fd) { } } +sp ExternalCameraDevice::createSession( + const sp& cb, + const ExternalCameraConfig& cfg, + const std::vector& 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 a12d8e4243..dc5579ac67 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 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 ExternalCameraDeviceSession::flush() { return Status::OK; } -Return ExternalCameraDeviceSession::close() { +Return 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 ExternalCameraDeviceSession::close() { return Void(); } -Status ExternalCameraDeviceSession::importRequest( +Status ExternalCameraDeviceSession::importRequestLocked( + const CaptureRequest& request, + hidl_vec& allBufPtrs, + hidl_vec& 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& allBufPtrs, - hidl_vec& allFences) { + hidl_vec& 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,14 +853,16 @@ Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptrbuffers[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; // TODO: refactor - if (req->buffers[i].acquireFence > 0) { + 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); @@ -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) { @@ -1683,7 +1778,7 @@ int ExternalCameraDeviceSession::OutputThread::createJpegLocked( /* Unlock the HAL jpeg code buffer */ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); - if (relFence > 0) { + if (relFence >= 0) { halBuf.acquireFence = relFence; } @@ -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 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 @@ -1765,10 +1866,23 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { } } + 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 >= 0) { int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs); if (ret) { halBuf.fenceTimeout = true; @@ -1843,7 +1957,7 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { return onDeviceError("%s: format coversion failed!", __FUNCTION__); } int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); - if (relFence > 0) { + if (relFence >= 0) { halBuf.acquireFence = relFence; } } break; @@ -1866,7 +1980,8 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( const Size& v4lSize, const Size& thumbSize, - const hidl_vec& streams) { + const hidl_vec& streams, + uint32_t blobBufferSize) { std::lock_guard lk(mBufferLock); if (mScaledYu12Frames.size() != 0) { ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)", @@ -1935,6 +2050,8 @@ Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( it = mIntermediateBuffers.erase(it); } } + + mBlobBufferSize = blobBufferSize; return Status::OK; } @@ -2034,7 +2151,7 @@ void ExternalCameraDeviceSession::cleanupBuffersLocked(int id) { } void ExternalCameraDeviceSession::updateBufferCaches(const hidl_vec& cachesToRemove) { - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mCbsLock); for (auto& cache : cachesToRemove) { auto cbsIt = mCirculatingBuffers.find(cache.streamId); if (cbsIt == mCirculatingBuffers.end()) { @@ -2053,7 +2170,9 @@ void ExternalCameraDeviceSession::updateBufferCaches(const hidl_vec } } -bool ExternalCameraDeviceSession::isSupported(const Stream& stream) { +bool ExternalCameraDeviceSession::isSupported(const Stream& stream, + const std::vector& supportedFormats, + const ExternalCameraConfig& devCfg) { int32_t ds = static_cast(stream.dataSpace); PixelFormat fmt = stream.format; uint32_t width = stream.width; @@ -2084,7 +2203,7 @@ bool ExternalCameraDeviceSession::isSupported(const Stream& stream) { // intentional no-ops. break; case PixelFormat::Y16: - if (!mCfg.depthEnabled) { + if (!devCfg.depthEnabled) { ALOGI("%s: Depth is not Enabled", __FUNCTION__); return false; } @@ -2101,7 +2220,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; } @@ -2436,9 +2555,10 @@ void ExternalCameraDeviceSession::enqueueV4l2Frame(const sp& 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& supportedFormats, + const ExternalCameraConfig& devCfg) { if (config.operationMode != StreamConfigurationMode::NORMAL_MODE) { ALOGE("%s: unsupported operation mode: %d", __FUNCTION__, config.operationMode); return Status::ILLEGAL_ARGUMENT; @@ -2453,7 +2573,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, devCfg)) { return Status::ILLEGAL_ARGUMENT; } if (stream.format == PixelFormat::BLOB) { @@ -2475,7 +2595,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, mCfg); + if (status != Status::OK) { + return status; + } + + status = initStatus(); if (status != Status::OK) { return status; } @@ -2491,30 +2625,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; + } } } @@ -2599,7 +2736,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 a07c62936f..e25deff797 100644 --- a/camera/device/3.4/default/ExternalCameraUtils.cpp +++ b/camera/device/3.4/default/ExternalCameraUtils.cpp @@ -159,9 +159,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"; @@ -275,10 +277,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); @@ -324,7 +333,8 @@ ExternalCameraConfig::ExternalCameraConfig() : maxJpegBufSize(kDefaultJpegBufSize), numVideoBuffers(kDefaultNumVideoBuffer), numStillBuffers(kDefaultNumStillBuffer), - depthEnabled(false) { + depthEnabled(false), + 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..f48a95c5b3 100644 --- a/camera/device/3.4/default/OWNERS +++ b/camera/device/3.4/default/OWNERS @@ -1,6 +1 @@ -cychen@google.com -epeev@google.com -etalvala@google.com -shuzhenwang@google.com -yinchiayeh@google.com -zhijunhe@google.com +include platform/frameworks/av:/camera/OWNERS 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..280c4bec46 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 @@ -80,13 +80,19 @@ protected: ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb); bool preProcessConfigurationLocked_3_4( - const StreamConfiguration& requestedConfiguration, + const StreamConfiguration& requestedConfiguration, bool useOverriddenFields, camera3_stream_configuration_t *stream_list /*out*/, hidl_vec *streams /*out*/); void postProcessConfigurationLocked_3_4(const StreamConfiguration& requestedConfiguration); 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, bool useOverriddenFields = true); + Return processCaptureRequest_3_4( const hidl_vec& requests, const hidl_vec& cachesToRemove, @@ -117,6 +123,10 @@ protected: // Physical camera ids for the logical multi-camera. Empty if this // is not a logical multi-camera. std::unordered_set mPhysicalCameraIds; + + Mutex mStreamConfigCounterLock; + uint32_t mStreamConfigCounter = 1; + private: struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession { 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..71b7c17dd6 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 flush(); - Return close(); + Return close(bool callerIsDtor = false); Return configureStreams_3_3( const V3_2::StreamConfiguration&, @@ -170,32 +170,65 @@ protected: std::vector 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& supportedFormats, + const ExternalCameraConfig& devCfg); // TODO: change to unique_ptr for better tracking sp dequeueV4l2FrameLocked(/*out*/nsecs_t* shutterTs); // Called with mLock hold void enqueueV4l2Frame(const sp&); // 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& supportedFormats, + const ExternalCameraConfig& cfg); // Validate and import request's output buffers and acquire fence - Status importRequest( + virtual Status importRequestLocked( const CaptureRequest& request, hidl_vec& allBufPtrs, hidl_vec& allFences); + + Status importRequestLockedImpl( + const CaptureRequest& request, + hidl_vec& allBufPtrs, + hidl_vec& 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& allFences, size_t numFences); void cleanupBuffersLocked(int id); @@ -221,18 +254,26 @@ protected: class OutputThread : public android::Thread { public: OutputThread(wp parent, CroppingType); - ~OutputThread(); + virtual ~OutputThread(); Status allocateIntermediateBuffers( const Size& v4lSize, const Size& thumbSize, - const hidl_vec& streams); + const hidl_vec& streams, + uint32_t blobBufferSize); Status submitRequest(const std::shared_ptr&); 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&) { return 0; } + virtual int waitForBufferRequestDone( + /*out*/std::vector*) { return 0; } + static const uint32_t FLEX_YUV_GENERIC = static_cast('F') | static_cast('L') << 8 | static_cast('E') << 16 | static_cast('X') << 24; @@ -289,6 +330,7 @@ protected: std::unordered_map, 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 +356,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 +389,8 @@ protected: typedef std::unordered_map CirculatingBuffers; // Stream ID -> circulating buffers map std::map 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 28b9cef7af..bd7980780b 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 #include "ExternalCameraDeviceSession.h" +#include + 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,36 +59,57 @@ 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 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 getResourceCost(getResourceCost_cb _hidl_cb) override; + Return getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb); - Return getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override; + Return getCameraCharacteristics( + ICameraDevice::getCameraCharacteristics_cb _hidl_cb); - Return setTorchMode(TorchMode) override; + Return setTorchMode(TorchMode); // Open the device HAL and also return a default capture session - Return open(const sp&, open_cb) override; + Return open(const sp&, ICameraDevice::open_cb); // Forward the dump call to the opened session, or do nothing - Return dumpState(const ::android::hardware::hidl_handle&) override; + Return 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 createSession( + const sp&, + const ExternalCameraConfig& cfg, + const std::vector& 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 available capabilities keys status_t initAvailableCapabilities( ::android::hardware::camera::common::V1_0::helper::CameraMetadata*); // 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*); @@ -123,6 +146,7 @@ protected: /*inout*/std::vector* pFmts); Mutex mLock; + bool mInitialized = false; bool mInitFailed = false; std::string mCameraId; const ExternalCameraConfig& mCfg; @@ -132,6 +156,84 @@ protected: wp mSession = nullptr; ::android::hardware::camera::common::V1_0::helper::CameraMetadata mCameraCharacteristics; + + const std::vector 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 parent) : + mParent(parent) {} + + virtual Return getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return open(const sp& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + private: + sp 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 f696057068..341c62218d 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 @@ -85,6 +85,9 @@ struct ExternalCameraConfig { // Minimum output stream size Size minStreamSize; + // The value of android.sensor.orientation + int32_t orientation; + private: ExternalCameraConfig(); static bool updateFpsList(tinyxml2::XMLElement* fpsList, std::vector& fpsLimits); diff --git a/camera/device/3.5/Android.bp b/camera/device/3.5/Android.bp new file mode 100644 index 0000000000..362a5e6894 --- /dev/null +++ b/camera/device/3.5/Android.bp @@ -0,0 +1,24 @@ +// 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", + ], + 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 part of fully + * qualified camera device name "device@.//". 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 bufReqs) + generates (BufferRequestStatus st, vec 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 buffers); + +}; diff --git a/camera/device/3.5/ICameraDeviceSession.hal b/camera/device/3.5/ICameraDeviceSession.hal new file mode 100644 index 0000000000..c868e1e96c --- /dev/null +++ b/camera/device/3.5/ICameraDeviceSession.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.camera.device@3.5; + +import android.hardware.camera.common@1.0::Status; +import @3.2::CameraMetadata; +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. + * - In case the HAL overrides dataspace or format for + * IMPLEMENTATION_DEFINED pixel format, camera framework must use original + * dataspace and format in subsequent configureStreams_3_5 calls for the same + * stream. HAL is allowed to change the overriding behavior of format or + * dataspace for reconfiguration of the same stream depending on the stream + * combination. + * + * @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 streamIds, + uint32_t streamConfigCounter + ); + + /** + * isReconfigurationRequired: + * + * Check whether complete stream reconfiguration is required for possible new session + * parameter values. + * + * This method must be called by the camera framework in case the client changes + * the value of any advertised session parameters. Depending on the specific values + * the HAL can decide whether a complete stream reconfiguration is required. In case + * the HAL returns false, the camera framework must skip the internal reconfiguration. + * In case Hal returns true, the framework must reconfigure the streams and pass the + * new session parameter values accordingly. + * This call may be done by the framework some time before the request with new parameters + * is submitted to the HAL, and the request may be cancelled before it ever gets submitted. + * Therefore, the HAL must not use this query as an indication to change its behavior in any + * way. + * ------------------------------------------------------------------------ + * + * Preconditions: + * + * The framework can call this method at any time after active + * session configuration. There must be no impact on 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: + * HW and SW camera settings must not be changed and there must not be + * a user-visible impact on camera performance. + * + * @param oldSessionParams Before session parameters, usually the current session parameters. + * @param newSessionParams The new session parameters which may be set by client. + * + * @return Status Status code for the operation, one of: + * OK: + * On successful reconfiguration required query. + * METHOD_NOT_SUPPORTED: + * The camera device does not support the reconfiguration query. + * INTERNAL_ERROR: + * The reconfiguration query cannot complete due to internal + * error. + * @return true in case the stream reconfiguration is required, false otherwise. + */ + isReconfigurationRequired(CameraMetadata oldSessionParams, CameraMetadata newSessionParams) + generates(Status status, bool reconfigurationNeeded); +}; diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp new file mode 100644 index 0000000000..26b3b6734b --- /dev/null +++ b/camera/device/3.5/default/Android.bp @@ -0,0 +1,104 @@ +// +// 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", + "android.hardware.graphics.mapper@3.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", + "android.hardware.graphics.mapper@3.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 + +#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 module, const std::string& cameraId, + const SortedVector>& cameraDeviceNames) : + V3_4::implementation::CameraDevice(module, cameraId, cameraDeviceNames) { +} + +CameraDevice::~CameraDevice() { +} + +sp CameraDevice::createSession(camera3_device_t* device, + const camera_metadata_t* deviceInfo, + const sp& callback) { + sp 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 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 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 (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 (it.v3_2.streamType); + streamBuffer[i].width = it.v3_2.width; + streamBuffer[i].height = it.v3_2.height; + streamBuffer[i].format = static_cast (it.v3_2.format); + streamBuffer[i].data_space = static_cast (it.v3_2.dataSpace); + streamBuffer[i].usage = static_cast (it.v3_2.usage); + streamBuffer[i].physical_camera_id = it.physicalCameraId.c_str(); + streamBuffer[i++].rotation = static_cast (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..44d067d475 --- /dev/null +++ b/camera/device/3.5/default/CameraDeviceSession.cpp @@ -0,0 +1,407 @@ +/* + * 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 + +#include +#include +#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& callback) : + V3_4::implementation::CameraDeviceSession(device, deviceInfo, callback) { + + mCallback_3_5 = nullptr; + + auto castResult = ICameraDeviceCallback::castFrom(callback); + if (castResult.isOk()) { + sp 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 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, false /*useOverriddenFields*/); + return Void(); +} + +Return CameraDeviceSession::signalStreamFlush( + const hidl_vec& streamIds, uint32_t streamConfigCounter) { + if (mDevice->ops->signal_stream_flush == nullptr) { + return Void(); + } + + uint32_t currentCounter = 0; + { + Mutex::Autolock _l(mStreamConfigCounterLock); + currentCounter = mStreamConfigCounter; + } + + if (streamConfigCounter < currentCounter) { + ALOGV("%s: streamConfigCounter %d is stale (current %d), skipping signal_stream_flush call", + __FUNCTION__, streamConfigCounter, mStreamConfigCounter); + return Void(); + } + + std::vector 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]; + } + } + + mDevice->ops->signal_stream_flush(mDevice, streams.size(), streams.data()); + return Void(); +} + +Status CameraDeviceSession::importRequest( + const CaptureRequest& request, + hidl_vec& allBufPtrs, + hidl_vec& 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 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 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& fences, std::vector>& bufs) { + hidl_vec 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 hBufReqs(num_buffer_reqs); + for (size_t i = 0; i < num_buffer_reqs; i++) { + hBufReqs[i].streamId = + static_cast(buffer_reqs[i].stream)->mId; + hBufReqs[i].numBuffersRequested = buffer_reqs[i].num_buffers_requested; + } + + ATRACE_BEGIN("HIDL requestStreamBuffers"); + BufferRequestStatus status; + hidl_vec bufRets; + auto err = mCallback_3_5->requestStreamBuffers(hBufReqs, + [&status, &bufRets] + (BufferRequestStatus s, const hidl_vec& 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(); + + switch (status) { + case BufferRequestStatus::FAILED_CONFIGURING: + return CAMERA3_BUF_REQ_FAILED_CONFIGURING; + case BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS: + return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS; + default: + break; // Other status Handled by following code + } + + if (status != BufferRequestStatus::OK && status != BufferRequestStatus::FAILED_PARTIAL && + status != BufferRequestStatus::FAILED_UNKNOWN) { + ALOGE("%s: unknown buffer request error code %d", __FUNCTION__, status); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + + // Only OK, FAILED_PARTIAL and FAILED_UNKNOWN reaches here + 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; + } + + *num_returned_buf_reqs = num_buffer_reqs; + 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; + } + + // Handle failed streams + for (size_t i = 0; i < num_buffer_reqs; i++) { + if (bufRets[i].val.getDiscriminator() == 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()); + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + } + } + + if (status == BufferRequestStatus::FAILED_UNKNOWN) { + return CAMERA3_BUF_REQ_FAILED_UNKNOWN; + } + + // Only BufferRequestStatus::OK and BufferRequestStatus::FAILED_PARTIAL reaches here + std::vector importedFences; + std::vector> importedBuffers; + for (size_t i = 0; i < num_buffer_reqs; i++) { + if (bufRets[i].val.getDiscriminator() != + StreamBuffersVal::hidl_discriminator::buffers) { + continue; + } + int streamId = bufRets[i].streamId; + const hidl_vec& hBufs = bufRets[i].val.buffers(); + camera3_stream_buffer_t* outBufs = returned_buf_reqs[i].output_buffers; + returned_buf_reqs[i].num_output_buffers = hBufs.size(); + 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); + // Buffer import should never fail - restart HAL since something is very wrong. + LOG_ALWAYS_FATAL_IF(s != Status::OK, + "%s: import stream %d bufferId %" PRIu64 " failed!", + __FUNCTION__, streamId, hBuf.bufferId); + + pushBufferId(*(outBuf.buffer), hBuf.bufferId, streamId); + importedBuffers.push_back(std::make_pair(*(outBuf.buffer), streamId)); + + bool succ = sHandleImporter.importFence(hBuf.acquireFence, outBuf.acquire_fence); + // Fence import should never fail - restart HAL since something is very wrong. + LOG_ALWAYS_FATAL_IF(!succ, + "%s: stream %d bufferId %" PRIu64 "acquire fence is invalid", + __FUNCTION__, streamId, hBuf.bufferId); + 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; + } + + return (status == BufferRequestStatus::OK) ? + CAMERA3_BUF_REQ_OK : CAMERA3_BUF_REQ_FAILED_PARTIAL; +} + +void CameraDeviceSession::returnStreamBuffers( + uint32_t num_buffers, + const camera3_stream_buffer_t* const* buffers) { + ATRACE_CALL(); + hidl_vec hBufs(num_buffers); + + for (size_t i = 0; i < num_buffers; i++) { + hBufs[i].streamId = + static_cast(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(static_cast(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(static_cast(cb)); + + d->returnStreamBuffers(num_buffers, buffers); +} + +Return CameraDeviceSession::isReconfigurationRequired( + const V3_2::CameraMetadata& oldSessionParams, const V3_2::CameraMetadata& newSessionParams, + ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) { + if (mDevice->ops->is_reconfiguration_required != nullptr) { + const camera_metadata_t *oldParams, *newParams; + V3_2::implementation::convertFromHidl(oldSessionParams, &oldParams); + V3_2::implementation::convertFromHidl(newSessionParams, &newParams); + auto ret = mDevice->ops->is_reconfiguration_required(mDevice, oldParams, newParams); + switch (ret) { + case 0: + _hidl_cb(Status::OK, true); + break; + case -EINVAL: + _hidl_cb(Status::OK, false); + break; + case -ENOSYS: + _hidl_cb(Status::METHOD_NOT_SUPPORTED, true); + break; + default: + _hidl_cb(Status::INTERNAL_ERROR, true); + break; + }; + } else { + _hidl_cb(Status::METHOD_NOT_SUPPORTED, true); + } + + return Void(); +} + +} // 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..d0de1a40b1 --- /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 + +#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 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 ExternalCameraDevice::createSession( + const sp& cb, + const ExternalCameraConfig& cfg, + const std::vector& 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 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 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 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, mCfg); + _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..00c1d0de39 --- /dev/null +++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp @@ -0,0 +1,312 @@ +/* + * 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 + +#include +#include "ExternalCameraDeviceSession.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_5 { +namespace implementation { + +ExternalCameraDeviceSession::ExternalCameraDeviceSession( + const sp& callback, + const ExternalCameraConfig& cfg, + const std::vector& 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 callback3_5 = castResult; + if (callback3_5 != nullptr) { + mCallback_3_5 = callback3_5; + } + } + + if (mCallback_3_5 != nullptr) { + mSupportBufMgr = true; + } +} + +ExternalCameraDeviceSession::~ExternalCameraDeviceSession() { + closeOutputThreadImpl(); +} + +Return ExternalCameraDeviceSession::configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb) { + return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb); +} + +Return ExternalCameraDeviceSession::signalStreamFlush( + const hidl_vec& /*streamIds*/, uint32_t /*streamConfigCounter*/) { + return Void(); +} + +Status ExternalCameraDeviceSession::importRequestLocked( + const CaptureRequest& request, + hidl_vec& allBufPtrs, + hidl_vec& allFences) { + if (mSupportBufMgr) { + return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true); + } + return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false); +} + + +ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread( + wp parent, + sp callbacks) : + mParent(parent), + mCallbacks(callbacks) {} + +int ExternalCameraDeviceSession::BufferRequestThread::requestBufferStart( + const std::vector& bufReqs) { + if (bufReqs.empty()) { + ALOGE("%s: bufReqs is empty!", __FUNCTION__); + return -1; + } + + { + std::lock_guard 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* outBufReq) { + std::unique_lock 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 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 bufRets; + auto err = mCallbacks->requestStreamBuffers(mHalBufferReqs, + [&status, &bufRets] + (BufferRequestStatus s, const hidl_vec& 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 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 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& 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 parent, + CroppingType ct, + sp bufReqThread) : + V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct), + mBufferRequestThread(bufReqThread) {} + +ExternalCameraDeviceSession::OutputThread::~OutputThread() {} + +int ExternalCameraDeviceSession::OutputThread::requestBufferStart( + const std::vector& bufs) { + if (mBufferRequestThread != nullptr) { + return mBufferRequestThread->requestBufferStart(bufs); + } + return 0; +} + +int ExternalCameraDeviceSession::OutputThread::waitForBufferRequestDone( + /*out*/std::vector* outBufs) { + if (mBufferRequestThread != nullptr) { + return mBufferRequestThread->waitForBufferRequestDone(outBufs); + } + return 0; +} + +Return ExternalCameraDeviceSession::isReconfigurationRequired( + const V3_2::CameraMetadata& /*oldSessionParams*/, + const V3_2::CameraMetadata& /*newSessionParams*/, + ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) { + //Stub implementation + _hidl_cb(Status::OK, true); + return Void(); +} + +} // 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..f48a95c5b3 --- /dev/null +++ b/camera/device/3.5/default/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/av:/camera/OWNERS 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..87d616c5e1 --- /dev/null +++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h @@ -0,0 +1,261 @@ +/* + * 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 +#include +#include +#include <../../3.4/default/include/device_v3_4_impl/CameraDeviceSession.h> +#include + +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&); + virtual ~CameraDeviceSession(); + + virtual sp getInterface() override { + return new TrampolineSessionInterface_3_5(this); + } + +protected: + // Methods from v3.4 and earlier will trampoline to inherited implementation + Return configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb); + + Return signalStreamFlush( + const hidl_vec& streamIds, + uint32_t streamConfigCounter); + + virtual Status importRequest( + const CaptureRequest& request, + hidl_vec& allBufPtrs, + hidl_vec& allFences) override; + + Return isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams, + const V3_2::CameraMetadata& newSessionParams, + ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb); + /** + * 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& fences, std::vector>& 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 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 mBufferIdMaps; + + sp mCallback_3_5; + bool mSupportBufMgr; + +private: + + struct TrampolineSessionInterface_3_5 : public ICameraDeviceSession { + TrampolineSessionInterface_3_5(sp parent) : + mParent(parent) {} + + virtual Return constructDefaultRequestSettings( + V3_2::RequestTemplate type, + V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override { + return mParent->constructDefaultRequestSettings(type, _hidl_cb); + } + + virtual Return configureStreams( + const V3_2::StreamConfiguration& requestedConfiguration, + V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override { + return mParent->configureStreams(requestedConfiguration, _hidl_cb); + } + + virtual Return processCaptureRequest_3_4( + const hidl_vec& requests, + const hidl_vec& cachesToRemove, + ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override { + return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb); + } + + virtual Return processCaptureRequest(const hidl_vec& requests, + const hidl_vec& cachesToRemove, + V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override { + return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb); + } + + virtual Return getCaptureRequestMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureRequestMetadataQueue(_hidl_cb); + } + + virtual Return getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return flush() override { + return mParent->flush(); + } + + virtual Return close() override { + return mParent->close(); + } + + virtual Return 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 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 configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + configureStreams_3_5_cb _hidl_cb) override { + return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb); + } + + virtual Return signalStreamFlush( + const hidl_vec& requests, + uint32_t streamConfigCounter) override { + return mParent->signalStreamFlush(requests, streamConfigCounter); + } + + virtual Return isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams, + const V3_2::CameraMetadata& newSessionParams, + ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) override { + return mParent->isReconfigurationRequired(oldSessionParams, newSessionParams, _hidl_cb); + } + private: + sp 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 + +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 module, + const std::string& cameraId, + const SortedVector>& cameraDeviceNames); + virtual ~CameraDevice(); + + virtual sp getInterface() override { + return new TrampolineDeviceInterface_3_5(this); + } + +protected: + virtual sp createSession(camera3_device_t*, + const camera_metadata_t* deviceInfo, + const sp&) override; + + Return getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb); + + Return isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb); + +private: + struct TrampolineDeviceInterface_3_5 : public ICameraDevice { + TrampolineDeviceInterface_3_5(sp parent) : + mParent(parent) {} + + virtual Return getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return open(const sp& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + virtual Return getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override { + return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb); + } + + virtual Return isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override { + return mParent->isStreamCombinationSupported(streams, _hidl_cb); + } + + private: + sp 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..281f93a13b --- /dev/null +++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h @@ -0,0 +1,273 @@ +/* + * 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 +#include +#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&, + const ExternalCameraConfig& cfg, + const std::vector& 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 getInterface() override { + return new TrampolineSessionInterface_3_5(this); + } + + static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config, + const std::vector& supportedFormats, + const ExternalCameraConfig& devCfg) { + return V3_4::implementation::ExternalCameraDeviceSession::isStreamCombinationSupported( + config, supportedFormats, devCfg); + } + +protected: + // Methods from v3.4 and earlier will trampoline to inherited implementation + Return configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb); + + Return signalStreamFlush( + const hidl_vec& requests, + uint32_t streamConfigCounter); + + Return isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams, + const V3_2::CameraMetadata& newSessionParams, + ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb); + + virtual void initOutputThread() override; + virtual void closeOutputThread() override; + void closeOutputThreadImpl(); + + virtual Status importRequestLocked( + const CaptureRequest& request, + hidl_vec& allBufPtrs, + hidl_vec& allFences) override; + + class BufferRequestThread : public android::Thread { + public: + BufferRequestThread( + wp parent, + sp callbacks); + + int requestBufferStart(const std::vector&); + int waitForBufferRequestDone( + /*out*/std::vector*); + + virtual bool threadLoop() override; + + private: + void waitForNextRequest(); + + const wp mParent; + const sp mCallbacks; + + std::mutex mLock; + bool mRequestingBuffer = false; + + std::vector mBufferReqs; + std::vector mPendingReturnBufferReqs; + // mHalBufferReqs is not under mLock protection during the HIDL transaction + hidl_vec 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 mBufferRequestThread; + + class OutputThread : + public V3_4::implementation::ExternalCameraDeviceSession::OutputThread { + public: + // TODO: pass buffer request thread to OutputThread ctor + OutputThread(wp parent, CroppingType, + sp bufReqThread); + virtual ~OutputThread(); + + protected: + // Methods to request output buffer in parallel + virtual int requestBufferStart(const std::vector&) override; + virtual int waitForBufferRequestDone( + /*out*/std::vector*) override; + + const sp mBufferRequestThread; + }; + + sp mCallback_3_5; + bool mSupportBufMgr; + +private: + + struct TrampolineSessionInterface_3_5 : public ICameraDeviceSession { + TrampolineSessionInterface_3_5(sp parent) : + mParent(parent) {} + + virtual Return constructDefaultRequestSettings( + RequestTemplate type, + V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override { + return mParent->constructDefaultRequestSettings(type, _hidl_cb); + } + + virtual Return configureStreams( + const V3_2::StreamConfiguration& requestedConfiguration, + V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override { + return mParent->configureStreams(requestedConfiguration, _hidl_cb); + } + + virtual Return processCaptureRequest(const hidl_vec& requests, + const hidl_vec& cachesToRemove, + V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override { + return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb); + } + + virtual Return getCaptureRequestMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureRequestMetadataQueue(_hidl_cb); + } + + virtual Return getCaptureResultMetadataQueue( + V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override { + return mParent->getCaptureResultMetadataQueue(_hidl_cb); + } + + virtual Return flush() override { + return mParent->flush(); + } + + virtual Return close() override { + return mParent->close(); + } + + virtual Return 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 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 processCaptureRequest_3_4(const hidl_vec& requests, + const hidl_vec& cachesToRemove, + ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override { + return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb); + } + + virtual Return configureStreams_3_5( + const StreamConfiguration& requestedConfiguration, + configureStreams_3_5_cb _hidl_cb) override { + return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb); + } + + virtual Return signalStreamFlush( + const hidl_vec& requests, + uint32_t streamConfigCounter) override { + return mParent->signalStreamFlush(requests, streamConfigCounter); + } + + virtual Return isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams, + const V3_2::CameraMetadata& newSessionParams, + ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) override { + return mParent->isReconfigurationRequired(oldSessionParams, newSessionParams, _hidl_cb); + } + + private: + sp 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 +#include +#include +#include +#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 getInterface() override { + return new TrampolineDeviceInterface_3_5(this); + } + + Return getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb); + + Return isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb); + +protected: + virtual sp createSession( + const sp&, + const ExternalCameraConfig& cfg, + const std::vector& 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 EXTRA_CHARACTERISTICS_KEYS_3_5 = { + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION + }; + +private: + struct TrampolineDeviceInterface_3_5 : public ICameraDevice { + TrampolineDeviceInterface_3_5(sp parent) : + mParent(parent) {} + + virtual Return getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb) + override { + return mParent->getResourceCost(_hidl_cb); + } + + virtual Return getCameraCharacteristics( + V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override { + return mParent->getCameraCharacteristics(_hidl_cb); + } + + virtual Return setTorchMode(TorchMode mode) override { + return mParent->setTorchMode(mode); + } + + virtual Return open(const sp& callback, + V3_2::ICameraDevice::open_cb _hidl_cb) override { + return mParent->open(callback, _hidl_cb); + } + + virtual Return dumpState(const hidl_handle& fd) override { + return mParent->dumpState(fd); + } + + virtual Return getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId, + V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override { + return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb); + } + + virtual Return isStreamCombinationSupported( + const V3_4::StreamConfiguration& streams, + V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override { + return mParent->isStreamCombinationSupported(streams, _hidl_cb); + } + + private: + sp 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..6d861e2e72 --- /dev/null +++ b/camera/device/3.5/types.hal @@ -0,0 +1,176 @@ +/* + * 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; +import @3.2::CameraBlobId; + +/** + * If the result metadata cannot be produced for a physical camera device part of a logical + * multi-camera, then HAL must invoke the notification callback and pass a message with ERROR_RESULT + * code and errorStreamId that contains the stream id associated with that physical device. + * The behavior during absent result metadata remains unchanged for a logical or a non-logical + * camera device and the errorStreamId must be set to -1. + */ + +/** + * 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, or all streams has individual failing + * reason. For the latter case, check per stream status for each returned + * StreamBufferRet. + */ + FAILED_UNKNOWN = 4, +}; + +struct BufferRequest { + int32_t streamId; + uint32_t numBuffersRequested; +}; + +/** + * CameraBlob: + * + * Identical to @3.2::CameraBlob, except that it also supports transport of JPEG + * APP segments blob, which contains JPEG APP1 to APPn (Application Marker) + * segments as specified in JEITA CP-3451. + * + * To capture a JPEG APP segments blob, a stream is created using the pixel format + * HAL_PIXEL_FORMAT_BLOB and dataspace HAL_DATASPACE_JPEG_APP_SEGMENTS. The buffer + * size for the stream is calculated by the framework, based on the static + * metadata field android.heic.maxAppSegmentsCount, and is assigned to both + * @3.2::Stream::width and @3.4::Stream::bufferSize. Camera framework sets + * @3.2::Stream::height to 1. + * + * Similar to JPEG image, the JPEG APP segment images can be of variable size, + * so the HAL needs to include the final size of all APP segments using this + * structure inside the output stream buffer. The camera blob ID field must be + * set to CameraBlobId::JPEG_APP_SEGMENTS. + * + * The transport header must be at the end of the JPEG APP segments output stream + * buffer. That means the blobId must start at byte[buffer_size - + * sizeof(CameraBlob)], where the buffer_size is the size of gralloc + * buffer. The JPEG APP segments data itself starts at the beginning of the + * buffer and must be blobSize bytes long. + */ +enum CameraBlobId : @3.2::CameraBlobId { + JPEG_APP_SEGMENTS = 0x100, +}; + +struct CameraBlob { + CameraBlobId blobId; + uint32_t blobSize; +}; + diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal index 539ae68991..ca0c9d619b 100644 --- a/camera/metadata/3.3/types.hal +++ b/camera/metadata/3.3/types.hal @@ -97,7 +97,7 @@ enum CameraMetadataTag : @3.2::CameraMetadataTag { */ ANDROID_REQUEST_AVAILABLE_SESSION_KEYS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_REQUEST_END, - /** android.request.availablePhysicalCameraRequestKeys [static, int32[], hidden] + /** android.request.availablePhysicalCameraRequestKeys [static, int32[], ndk_public] * *

A subset of the available request keys that can be overridden for * physical devices backing a logical multi-camera.

diff --git a/camera/metadata/3.4/Android.bp b/camera/metadata/3.4/Android.bp new file mode 100644 index 0000000000..6a924580fd --- /dev/null +++ b/camera/metadata/3.4/Android.bp @@ -0,0 +1,17 @@ +// 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", + ], + 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..30c3217ec7 --- /dev/null +++ b/camera/metadata/3.4/types.hal @@ -0,0 +1,261 @@ +/* + * 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; + +import android.hardware.camera.metadata@3.2; +import android.hardware.camera.metadata@3.3; + +/** + * Top level hierarchy definitions for camera metadata. *_INFO sections are for + * the static metadata that can be retrived without opening the camera device. + */ +enum CameraMetadataSection : @3.3::CameraMetadataSection { + ANDROID_HEIC = + android.hardware.camera.metadata@3.3::CameraMetadataSection:ANDROID_SECTION_COUNT, + + ANDROID_HEIC_INFO, + + ANDROID_SECTION_COUNT_3_4, + + VENDOR_SECTION_3_4 = 0x8000, + +}; + +/** + * Hierarchy positions in enum space. All vendor extension sections must be + * defined with tag >= VENDOR_SECTION_START + */ +enum CameraMetadataSectionStart : android.hardware.camera.metadata@3.3::CameraMetadataSectionStart { + ANDROID_HEIC_START = CameraMetadataSection:ANDROID_HEIC << 16, + + ANDROID_HEIC_INFO_START = CameraMetadataSection:ANDROID_HEIC_INFO << 16, + + VENDOR_SECTION_START_3_4 = CameraMetadataSection:VENDOR_SECTION_3_4 << 16, + +}; + +/** + * Main enumeration for defining camera metadata tags added in this revision + * + *

Partial documentation is included for each tag; for complete documentation, reference + * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.

+ */ +enum CameraMetadataTag : @3.3::CameraMetadataTag { + /** android.request.characteristicKeysNeedingPermission [static, int32[], hidden] + * + *

A list of camera characteristics keys that are only available + * in case the camera client has camera permission.

+ */ + 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] + * + *

Recommended stream configurations for common client use cases.

+ */ + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_SCALER_END, + + /** android.scaler.availableRecommendedInputOutputFormatsMap [static, int32, ndk_public] + * + *

Recommended mappings of image formats that are supported by this + * camera device for input streams, to their corresponding output formats.

+ */ + ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP, + + ANDROID_SCALER_END_3_4, + + /** android.info.supportedBufferManagementVersion [static, enum, system] + * + *

The version of buffer management API this camera device supports and opts into.

+ */ + 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] + * + *

Recommended depth stream configurations for common client use cases.

+ */ + ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_DEPTH_END, + + /** android.depth.availableDynamicDepthStreamConfigurations [static, enum[], ndk_public] + * + *

The available dynamic depth dataspace stream + * configurations that this camera device supports + * (i.e. format, width, height, output/input stream).

+ */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, + + /** android.depth.availableDynamicDepthMinFrameDurations [static, int64[], ndk_public] + * + *

This lists the minimum frame duration for each + * format/size combination for dynamic depth output streams.

+ */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, + + /** android.depth.availableDynamicDepthStallDurations [static, int64[], ndk_public] + * + *

This lists the maximum stall duration for each + * output format/size combination for dynamic depth streams.

+ */ + ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, + + ANDROID_DEPTH_END_3_4, + + /** android.logicalMultiCamera.activePhysicalId [dynamic, byte, public] + * + *

String containing the ID of the underlying active physical camera.

+ */ + 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, + + /** android.heic.availableHeicStreamConfigurations [static, enum[], ndk_public] + * + *

The available HEIC (ISO/IEC 23008-12) stream + * configurations that this camera device supports + * (i.e. format, width, height, output/input stream).

+ */ + ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS = CameraMetadataSectionStart:ANDROID_HEIC_START, + + /** android.heic.availableHeicMinFrameDurations [static, int64[], ndk_public] + * + *

This lists the minimum frame duration for each + * format/size combination for HEIC output formats.

+ */ + ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS, + + /** android.heic.availableHeicStallDurations [static, int64[], ndk_public] + * + *

This lists the maximum stall duration for each + * output format/size combination for HEIC streams.

+ */ + ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS, + + ANDROID_HEIC_END_3_4, + + /** android.heic.info.supported [static, enum, system] + * + *

Whether this camera device can support identical set of stream combinations + * involving HEIC image format, compared to the + * table of combinations + * involving JPEG image format required for the device's hardware level and capabilities.

+ */ + ANDROID_HEIC_INFO_SUPPORTED = CameraMetadataSectionStart:ANDROID_HEIC_INFO_START, + + /** android.heic.info.maxJpegAppSegmentsCount [static, byte, system] + * + *

The maximum number of Jpeg APP segments supported by the camera HAL device.

+ */ + ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT, + + ANDROID_HEIC_INFO_END_3_4, + +}; + +/* + * Enumeration definitions for the various entries that need them + */ + +/** android.request.availableCapabilities enumeration values added since v3.3 + * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES + */ +enum CameraMetadataEnumAndroidRequestAvailableCapabilities : + @3.3::CameraMetadataEnumAndroidRequestAvailableCapabilities { + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA, +}; + +/** 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_LOW_LATENCY_SNAPSHOT + = 0x6, + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END + = 0x7, + 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, +}; + +/** android.heic.availableHeicStreamConfigurations enumeration values + * @see ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS + */ +enum CameraMetadataEnumAndroidHeicAvailableHeicStreamConfigurations : uint32_t { + ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT, + ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_INPUT, +}; + +/** android.heic.info.supported enumeration values + * @see ANDROID_HEIC_INFO_SUPPORTED + */ +enum CameraMetadataEnumAndroidHeicInfoSupported : uint32_t { + ANDROID_HEIC_INFO_SUPPORTED_FALSE, + ANDROID_HEIC_INFO_SUPPORTED_TRUE, +}; diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal index 8773bc0819..74c3ff1693 100644 --- a/camera/provider/2.4/ICameraProvider.hal +++ b/camera/provider/2.4/ICameraProvider.hal @@ -140,7 +140,8 @@ interface ICameraProvider { * Torch API support cannot be queried. This may be due to * a failure to initialize the camera subsystem, for example. * @return support Whether the camera devices known to this provider - * supports setTorchMode API or not. + * supports setTorchMode API or not. Devices launched with SDK + * level 29 or higher must return true. * */ isSetTorchModeSupported() generates (Status status, bool support); diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp index ae24d78143..cb78fcb859 100644 --- a/camera/provider/2.4/default/Android.bp +++ b/camera/provider/2.4/default/Android.bp @@ -1,88 +1,196 @@ +cc_library_shared { + name: "android.hardware.camera.provider@2.4-legacy", + defaults: ["hidl_defaults"], + proprietary: true, + srcs: ["LegacyCameraProviderImpl_2_4.cpp"], + shared_libs: [ + "android.hardware.camera.common@1.0", + "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.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "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", + "libcamera_metadata", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + header_libs: [ + "camera.device@3.4-impl_headers", + "camera.device@3.5-impl_headers", + ], + export_include_dirs: ["."], +} + +cc_library_shared { + name: "android.hardware.camera.provider@2.4-external", + proprietary: true, + srcs: ["ExternalCameraProviderImpl_2_4.cpp"], + shared_libs: [ + "android.hardware.camera.common@1.0", + "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.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "camera.device@3.3-impl", + "camera.device@3.4-external-impl", + "camera.device@3.4-impl", + "camera.device@3.5-external-impl", + "camera.device@3.5-impl", + "libcamera_metadata", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libtinyxml2", + "libutils", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + header_libs: [ + "camera.device@3.4-external-impl_headers", + "camera.device@3.5-external-impl_headers" + ], + export_include_dirs: ["."], +} + cc_library_shared { name: "android.hardware.camera.provider@2.4-impl", defaults: ["hidl_defaults"], proprietary: true, relative_install_path: "hw", - srcs: ["CameraProvider.cpp", - "ExternalCameraProvider.cpp"], + srcs: ["CameraProvider_2_4.cpp"], shared_libs: [ - "libhidlbase", - "libhidltransport", - "libutils", - "libcutils", + "android.hardware.camera.common@1.0", "android.hardware.camera.device@1.0", "android.hardware.camera.device@3.2", "android.hardware.camera.device@3.3", "android.hardware.camera.device@3.4", - "camera.device@1.0-impl", - "camera.device@3.2-impl", - "camera.device@3.3-impl", - "camera.device@3.4-impl", - "camera.device@3.4-external-impl", + "android.hardware.camera.device@3.5", "android.hardware.camera.provider@2.4", - "android.hardware.camera.common@1.0", + "android.hardware.camera.provider@2.4-external", + "android.hardware.camera.provider@2.4-legacy", "android.hardware.graphics.mapper@2.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", - "liblog", - "libhardware", + "camera.device@1.0-impl", + "camera.device@3.2-impl", + "camera.device@3.3-impl", + "camera.device@3.4-external-impl", + "camera.device@3.4-impl", + "camera.device@3.5-external-impl", + "camera.device@3.5-impl", "libcamera_metadata", - "libtinyxml2" + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libtinyxml2", + "libutils", ], header_libs: [ + "camera.device@3.4-external-impl_headers", "camera.device@3.4-impl_headers", - "camera.device@3.4-external-impl_headers" + "camera.device@3.5-external-impl_headers", + "camera.device@3.5-impl_headers", ], static_libs: [ "android.hardware.camera.common@1.0-helper", ], + export_include_dirs: ["."], +} + +cc_defaults { + name: "camera_service_defaults", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["service.cpp"], + shared_libs: [ + "android.hardware.camera.common@1.0", + "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.graphics.mapper@2.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libbinder", + "libcamera_metadata", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + header_libs: [ + "camera.device@3.4-external-impl_headers", + "camera.device@3.4-impl_headers", + "camera.device@3.5-external-impl_headers", + "camera.device@3.5-impl_headers", + ], } cc_binary { name: "android.hardware.camera.provider@2.4-service", - defaults: ["hidl_defaults"], - proprietary: true, - relative_install_path: "hw", - srcs: ["service.cpp"], + defaults: ["camera_service_defaults"], compile_multilib: "32", init_rc: ["android.hardware.camera.provider@2.4-service.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_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 { @@ -94,15 +202,24 @@ cc_binary { compile_multilib: "32", init_rc: ["android.hardware.camera.provider@2.4-external-service.rc"], shared_libs: [ - "libhidlbase", - "libhidltransport", - "libbinder", - "liblog", - "libutils", + "android.hardware.camera.common@1.0", "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", + "libbinder", + "libhidlbase", + "libhidltransport", + "liblog", + "libtinyxml2", + "libutils", + ], + header_libs: [ + "camera.device@3.4-external-impl_headers", + "camera.device@3.4-impl_headers", + "camera.device@3.5-external-impl_headers", + "camera.device@3.5-impl_headers", ], } diff --git a/camera/provider/2.4/default/CameraProvider_2_4.cpp b/camera/provider/2.4/default/CameraProvider_2_4.cpp new file mode 100644 index 0000000000..15fc702aa5 --- /dev/null +++ b/camera/provider/2.4/default/CameraProvider_2_4.cpp @@ -0,0 +1,69 @@ +/* + * 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 "CameraProvider_2_4.h" +#include "LegacyCameraProviderImpl_2_4.h" +#include "ExternalCameraProviderImpl_2_4.h" + +const char *kLegacyProviderName = "legacy/0"; +const char *kExternalProviderName = "external/0"; + +namespace android { +namespace hardware { +namespace camera { +namespace provider { +namespace V2_4 { +namespace implementation { + +using android::hardware::camera::provider::V2_4::ICameraProvider; + +extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name); + +template +CameraProvider* getProviderImpl() { + CameraProvider *provider = new CameraProvider(); + if (provider == nullptr) { + ALOGE("%s: cannot allocate camera provider!", __FUNCTION__); + return nullptr; + } + if (provider->isInitFailed()) { + ALOGE("%s: camera provider init failed!", __FUNCTION__); + delete provider; + return nullptr; + } + return provider; +} + +ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) { + using namespace android::hardware::camera::provider::V2_4::implementation; + ICameraProvider* provider = nullptr; + if (strcmp(name, kLegacyProviderName) == 0) { + provider = getProviderImpl(); + } else if (strcmp(name, kExternalProviderName) == 0) { + provider = getProviderImpl(); + } else { + ALOGE("%s: unknown instance name: %s", __FUNCTION__, name); + } + + return provider; +} + +} // namespace implementation +} // namespace V2_4 +} // namespace provider +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/provider/2.4/default/CameraProvider_2_4.h b/camera/provider/2.4/default/CameraProvider_2_4.h new file mode 100644 index 0000000000..d2e5b942d3 --- /dev/null +++ b/camera/provider/2.4/default/CameraProvider_2_4.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H +#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace camera { +namespace provider { +namespace V2_4 { +namespace implementation { + +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::provider::V2_4::ICameraProvider; +using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback; +using ::android::hardware::Return; +using ::android::hardware::hidl_string; +using ::android::sp; + +template +struct CameraProvider : public ICameraProvider { + CameraProvider() : impl() {} + ~CameraProvider() {} + + // Caller must use this method to check if CameraProvider ctor failed + bool isInitFailed() { return impl.isInitFailed(); } + + // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. + Return setCallback(const sp& callback) override { + return impl.setCallback(callback); + } + + Return getVendorTags(getVendorTags_cb _hidl_cb) override { + return impl.getVendorTags(_hidl_cb); + } + + Return getCameraIdList(getCameraIdList_cb _hidl_cb) override { + return impl.getCameraIdList(_hidl_cb); + } + + Return isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override { + return impl.isSetTorchModeSupported(_hidl_cb); + } + + Return getCameraDeviceInterface_V1_x( + const hidl_string& cameraDeviceName, + getCameraDeviceInterface_V1_x_cb _hidl_cb) override { + return impl.getCameraDeviceInterface_V1_x(cameraDeviceName, _hidl_cb); + } + + Return getCameraDeviceInterface_V3_x( + const hidl_string& cameraDeviceName, + getCameraDeviceInterface_V3_x_cb _hidl_cb) override { + return impl.getCameraDeviceInterface_V3_x(cameraDeviceName, _hidl_cb); + } + +private: + IMPL impl; +}; + +} // namespace implementation +} // namespace V2_4 +} // namespace provider +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H diff --git a/camera/provider/2.4/default/ExternalCameraProvider.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp similarity index 70% rename from camera/provider/2.4/default/ExternalCameraProvider.cpp rename to camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp index 1cec0e5d97..a6fd288125 100644 --- a/camera/provider/2.4/default/ExternalCameraProvider.cpp +++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "CamPvdr@2.4-external" +#define LOG_TAG "CamPrvdr@2.4-external" //#define LOG_NDEBUG 0 #include @@ -22,8 +22,10 @@ #include #include #include -#include "ExternalCameraProvider.h" +#include +#include "ExternalCameraProviderImpl_2_4.h" #include "ExternalCameraDevice_3_4.h" +#include "ExternalCameraDevice_3_5.h" namespace android { namespace hardware { @@ -32,6 +34,8 @@ namespace provider { namespace V2_4 { namespace implementation { +template struct CameraProvider; + namespace { // "device@/external/" const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)"); @@ -58,18 +62,33 @@ bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion, } // anonymous namespace -ExternalCameraProvider::ExternalCameraProvider() : +ExternalCameraProviderImpl_2_4::ExternalCameraProviderImpl_2_4() : 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() { +ExternalCameraProviderImpl_2_4::~ExternalCameraProviderImpl_2_4() { mHotPlugThread.requestExit(); } -Return ExternalCameraProvider::setCallback( +Return ExternalCameraProviderImpl_2_4::setCallback( const sp& callback) { { Mutex::Autolock _l(mLock); @@ -88,14 +107,16 @@ Return ExternalCameraProvider::setCallback( return Status::OK; } -Return ExternalCameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) { +Return ExternalCameraProviderImpl_2_4::getVendorTags( + ICameraProvider::getVendorTags_cb _hidl_cb) { // No vendor tag support for USB camera hidl_vec zeroSections; _hidl_cb(Status::OK, zeroSections); return Void(); } -Return ExternalCameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) { +Return ExternalCameraProviderImpl_2_4::getCameraIdList( + ICameraProvider::getCameraIdList_cb _hidl_cb) { // External camera HAL always report 0 camera, and extra cameras // are just reported via cameraDeviceStatusChange callbacks hidl_vec hidlDeviceNameList; @@ -103,25 +124,25 @@ Return ExternalCameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb return Void(); } -Return ExternalCameraProvider::isSetTorchModeSupported( - isSetTorchModeSupported_cb _hidl_cb) { +Return ExternalCameraProviderImpl_2_4::isSetTorchModeSupported( + ICameraProvider::isSetTorchModeSupported_cb _hidl_cb) { // setTorchMode API is supported, though right now no external camera device // has a flash unit. _hidl_cb (Status::OK, true); return Void(); } -Return ExternalCameraProvider::getCameraDeviceInterface_V1_x( +Return ExternalCameraProviderImpl_2_4::getCameraDeviceInterface_V1_x( const hidl_string&, - getCameraDeviceInterface_V1_x_cb _hidl_cb) { + ICameraProvider::getCameraDeviceInterface_V1_x_cb _hidl_cb) { // External Camera HAL does not support HAL1 _hidl_cb(Status::OPERATION_NOT_SUPPORTED, nullptr); return Void(); } -Return ExternalCameraProvider::getCameraDeviceInterface_V3_x( +Return ExternalCameraProviderImpl_2_4::getCameraDeviceInterface_V3_x( const hidl_string& cameraDeviceName, - getCameraDeviceInterface_V3_x_cb _hidl_cb) { + ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) { std::string cameraId, deviceVersion; bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId); @@ -136,35 +157,63 @@ Return ExternalCameraProvider::getCameraDeviceInterface_V3_x( return Void(); } - ALOGV("Constructing v3.4 external camera device"); - sp device; - sp deviceImpl = - new device::V3_4::implementation::ExternalCameraDevice( + sp 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(); } -void ExternalCameraProvider::addExternalCamera(const char* devName) { +void ExternalCameraProviderImpl_2_4::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); } } -void ExternalCameraProvider::deviceAdded(const char* devName) { +void ExternalCameraProviderImpl_2_4::deviceAdded(const char* devName) { { base::unique_fd fd(::open(devName, O_RDWR)); if (fd.get() < 0) { @@ -197,9 +246,14 @@ void ExternalCameraProvider::deviceAdded(const char* devName) { return; } -void ExternalCameraProvider::deviceRemoved(const char* devName) { +void ExternalCameraProviderImpl_2_4::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) { @@ -210,14 +264,15 @@ void ExternalCameraProvider::deviceRemoved(const char* devName) { } } -ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent) : +ExternalCameraProviderImpl_2_4::HotplugThread::HotplugThread( + ExternalCameraProviderImpl_2_4* parent) : Thread(/*canCallJava*/false), mParent(parent), mInternalDevices(parent->mCfg.mInternalDevices) {} -ExternalCameraProvider::HotplugThread::~HotplugThread() {} +ExternalCameraProviderImpl_2_4::HotplugThread::~HotplugThread() {} -bool ExternalCameraProvider::HotplugThread::threadLoop() { +bool ExternalCameraProviderImpl_2_4::HotplugThread::threadLoop() { // Find existing /dev/video* devices DIR* devdir = opendir(kDevicePath); if(devdir == 0) { diff --git a/camera/provider/2.4/default/ExternalCameraProvider.h b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.h similarity index 71% rename from camera/provider/2.4/default/ExternalCameraProvider.h rename to camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.h index c83cc708bf..8c79f68f10 100644 --- a/camera/provider/2.4/default/ExternalCameraProvider.h +++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.h @@ -20,13 +20,14 @@ #include #include #include -#include "utils/Mutex.h" -#include "utils/Thread.h" -#include +#include +#include #include #include #include "ExternalCameraUtils.h" +#include "CameraProvider_2_4.h" + namespace android { namespace hardware { namespace camera { @@ -47,25 +48,32 @@ using ::android::hardware::hidl_string; using ::android::sp; using ::android::Mutex; -struct ExternalCameraProvider : public ICameraProvider { - ExternalCameraProvider(); - ~ExternalCameraProvider(); +/** + * The implementation of external webcam CameraProvider 2.4, separated + * from the HIDL interface layer to allow for implementation reuse by later + * provider versions. + * + * This camera provider supports standard UVC webcameras via the Linux V4L2 + * UVC driver. + */ +struct ExternalCameraProviderImpl_2_4 { + ExternalCameraProviderImpl_2_4(); + ~ExternalCameraProviderImpl_2_4(); + + // Caller must use this method to check if CameraProvider ctor failed + bool isInitFailed() { return false;} // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. - Return setCallback(const sp& callback) override; - - Return getVendorTags(getVendorTags_cb _hidl_cb) override; - - Return getCameraIdList(getCameraIdList_cb _hidl_cb) override; - - Return isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override; - + Return setCallback(const sp& callback); + Return getVendorTags(ICameraProvider::getVendorTags_cb _hidl_cb); + Return getCameraIdList(ICameraProvider::getCameraIdList_cb _hidl_cb); + Return isSetTorchModeSupported(ICameraProvider::isSetTorchModeSupported_cb _hidl_cb); Return getCameraDeviceInterface_V1_x( const hidl_string&, - getCameraDeviceInterface_V1_x_cb) override; + ICameraProvider::getCameraDeviceInterface_V1_x_cb); Return getCameraDeviceInterface_V3_x( const hidl_string&, - getCameraDeviceInterface_V3_x_cb) override; + ICameraProvider::getCameraDeviceInterface_V3_x_cb); private: @@ -77,13 +85,13 @@ private: class HotplugThread : public android::Thread { public: - HotplugThread(ExternalCameraProvider* parent); + HotplugThread(ExternalCameraProviderImpl_2_4* parent); ~HotplugThread(); virtual bool threadLoop() override; private: - ExternalCameraProvider* mParent = nullptr; + ExternalCameraProviderImpl_2_4* mParent = nullptr; const std::unordered_set mInternalDevices; int mINotifyFD = -1; @@ -95,6 +103,7 @@ private: std::unordered_map mCameraStatusMap; // camera id -> status const ExternalCameraConfig mCfg; HotplugThread mHotPlugThread; + int mPreferredHal3MinorVersion; }; diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp similarity index 75% rename from camera/provider/2.4/default/CameraProvider.cpp rename to camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp index 63139390cb..4cff1b79a1 100644 --- a/camera/provider/2.4/default/CameraProvider.cpp +++ b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp @@ -14,20 +14,21 @@ * limitations under the License. */ -#define LOG_TAG "CamProvider@2.4-impl" +#define LOG_TAG "CamPrvdr@2.4-legacy" //#define LOG_NDEBUG 0 #include -#include "CameraProvider.h" -#include "ExternalCameraProvider.h" +#include "LegacyCameraProviderImpl_2_4.h" #include "CameraDevice_1_0.h" #include "CameraDevice_3_3.h" #include "CameraDevice_3_4.h" +#include "CameraDevice_3_5.h" +#include "CameraProvider_2_4.h" #include +#include #include #include - namespace android { namespace hardware { namespace camera { @@ -35,15 +36,13 @@ namespace provider { namespace V2_4 { namespace implementation { +template struct CameraProvider; + namespace { -const char *kLegacyProviderName = "legacy/0"; -const char *kExternalProviderName = "external/0"; // "device@/legacy/" 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; @@ -68,7 +67,7 @@ bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion, using ::android::hardware::camera::common::V1_0::CameraMetadataType; using ::android::hardware::camera::common::V1_0::Status; -void CameraProvider::addDeviceNames(int camera_id, CameraDeviceStatus status, bool cam_new) +void LegacyCameraProviderImpl_2_4::addDeviceNames(int camera_id, CameraDeviceStatus status, bool cam_new) { char cameraId[kMaxCameraIdLen]; snprintf(cameraId, sizeof(cameraId), "%d", camera_id); @@ -108,7 +107,7 @@ void CameraProvider::addDeviceNames(int camera_id, CameraDeviceStatus status, bo } } -void CameraProvider::removeDeviceNames(int camera_id) +void LegacyCameraProviderImpl_2_4::removeDeviceNames(int camera_id) { std::string cameraIdStr = std::to_string(camera_id); @@ -135,14 +134,12 @@ void CameraProvider::removeDeviceNames(int camera_id) /** * static callback forwarding methods from HAL to instance */ -void CameraProvider::sCameraDeviceStatusChange( +void LegacyCameraProviderImpl_2_4::sCameraDeviceStatusChange( const struct camera_module_callbacks* callbacks, int camera_id, int new_status) { - CameraProvider* cp = const_cast( - static_cast(callbacks)); - bool found = false; - + LegacyCameraProviderImpl_2_4* cp = const_cast( + static_cast(callbacks)); if (cp == nullptr) { ALOGE("%s: callback ops is null", __FUNCTION__); return; @@ -153,17 +150,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; - } - } - switch (status) { + 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) { case CameraDeviceStatus::PRESENT: case CameraDeviceStatus::ENUMERATING: if (!found) { @@ -174,16 +177,15 @@ void CameraProvider::sCameraDeviceStatusChange( if (found) { cp->removeDeviceNames(camera_id); } - } } } -void CameraProvider::sTorchModeStatusChange( +void LegacyCameraProviderImpl_2_4::sTorchModeStatusChange( const struct camera_module_callbacks* callbacks, const char* camera_id, int new_status) { - CameraProvider* cp = const_cast( - static_cast(callbacks)); + LegacyCameraProviderImpl_2_4* cp = const_cast( + static_cast(callbacks)); if (cp == nullptr) { ALOGE("%s: callback ops is null", __FUNCTION__); @@ -203,7 +205,7 @@ void CameraProvider::sTorchModeStatusChange( } } -Status CameraProvider::getHidlStatus(int status) { +Status LegacyCameraProviderImpl_2_4::getHidlStatus(int status) { switch (status) { case 0: return Status::OK; case -ENODEV: return Status::INTERNAL_ERROR; @@ -214,43 +216,40 @@ Status CameraProvider::getHidlStatus(int status) { } } -std::string CameraProvider::getLegacyCameraId(const hidl_string& deviceName) { +std::string LegacyCameraProviderImpl_2_4::getLegacyCameraId(const hidl_string& deviceName) { std::string cameraId; matchDeviceName(deviceName, nullptr, &cameraId); 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 LegacyCameraProviderImpl_2_4::getHidlDeviceName( std::string cameraId, int deviceVersion) { // Maybe consider create a version check method and SortedVec to speed up? if (deviceVersion != CAMERA_DEVICE_API_VERSION_1_0 && 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", @@ -258,15 +257,15 @@ std::string CameraProvider::getHidlDeviceName( return deviceName; } -CameraProvider::CameraProvider() : +LegacyCameraProviderImpl_2_4::LegacyCameraProviderImpl_2_4() : camera_module_callbacks_t({sCameraDeviceStatusChange, sTorchModeStatusChange}) { mInitFailed = initialize(); } -CameraProvider::~CameraProvider() {} +LegacyCameraProviderImpl_2_4::~LegacyCameraProviderImpl_2_4() {} -bool CameraProvider::initialize() { +bool LegacyCameraProviderImpl_2_4::initialize() { camera_module_t *rawModule; int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule); @@ -343,14 +342,15 @@ bool CameraProvider::initialize() { /** * Check that the device HAL version is still in supported. */ -int CameraProvider::checkCameraVersion(int id, camera_info info) { +int LegacyCameraProviderImpl_2_4::checkCameraVersion(int id, camera_info info) { if (mModule == nullptr) { return NO_INIT; } // 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 +360,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: @@ -375,7 +389,7 @@ int CameraProvider::checkCameraVersion(int id, camera_info info) { return OK; } -bool CameraProvider::setUpVendorTags() { +bool LegacyCameraProviderImpl_2_4::setUpVendorTags() { ATRACE_CALL(); vendor_tag_ops_t vOps = vendor_tag_ops_t(); @@ -432,20 +446,38 @@ bool CameraProvider::setUpVendorTags() { } // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. -Return CameraProvider::setCallback(const sp& callback) { +Return LegacyCameraProviderImpl_2_4::setCallback( + const sp& callback) { 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(statusPair.second); + if (id >= mNumberOfLegacyCameras && status != CameraDeviceStatus::NOT_PRESENT) { + addDeviceNames(id, status, true); + } + } + return Status::OK; } -Return CameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) { +Return LegacyCameraProviderImpl_2_4::getVendorTags( + ICameraProvider::getVendorTags_cb _hidl_cb) { _hidl_cb(Status::OK, mVendorTagSections); return Void(); } -Return CameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) { +Return LegacyCameraProviderImpl_2_4::getCameraIdList( + ICameraProvider::getCameraIdList_cb _hidl_cb) { std::vector 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); } @@ -455,14 +487,16 @@ Return CameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) { return Void(); } -Return CameraProvider::isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) { +Return LegacyCameraProviderImpl_2_4::isSetTorchModeSupported( + ICameraProvider::isSetTorchModeSupported_cb _hidl_cb) { bool support = mModule->isSetTorchModeSupported(); _hidl_cb (Status::OK, support); return Void(); } -Return CameraProvider::getCameraDeviceInterface_V1_x( - const hidl_string& cameraDeviceName, getCameraDeviceInterface_V1_x_cb _hidl_cb) { +Return LegacyCameraProviderImpl_2_4::getCameraDeviceInterface_V1_x( + const hidl_string& cameraDeviceName, + ICameraProvider::getCameraDeviceInterface_V1_x_cb _hidl_cb) { std::string cameraId, deviceVersion; bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId); if (!match) { @@ -514,8 +548,9 @@ Return CameraProvider::getCameraDeviceInterface_V1_x( return Void(); } -Return CameraProvider::getCameraDeviceInterface_V3_x( - const hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb) { +Return LegacyCameraProviderImpl_2_4::getCameraDeviceInterface_V3_x( + const hidl_string& cameraDeviceName, + ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) { std::string cameraId, deviceVersion; bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId); if (!match) { @@ -546,85 +581,71 @@ Return CameraProvider::getCameraDeviceInterface_V3_x( return Void(); } - sp device; - if (deviceVersion == kHAL3_4) { - ALOGV("Constructing v3.4 camera device"); - sp deviceImpl = - new android::hardware::camera::device::V3_4::implementation::CameraDevice( + sp 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 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 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); - return Void(); -} -ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) { - if (strcmp(name, kLegacyProviderName) == 0) { - CameraProvider* provider = new CameraProvider(); - if (provider == nullptr) { - ALOGE("%s: cannot allocate camera provider!", __FUNCTION__); - return nullptr; - } - if (provider->isInitFailed()) { - ALOGE("%s: camera provider init failed!", __FUNCTION__); - delete provider; - return nullptr; - } - return provider; - } else if (strcmp(name, kExternalProviderName) == 0) { - ExternalCameraProvider* provider = new ExternalCameraProvider(); - return provider; - } - ALOGE("%s: unknown instance name: %s", __FUNCTION__, name); - return nullptr; + _hidl_cb (Status::OK, deviceImpl->getInterface()); + return Void(); } } // namespace implementation diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.h similarity index 79% rename from camera/provider/2.4/default/CameraProvider.h rename to camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.h index 0f0959f1f0..b4914b3cfe 100644 --- a/camera/provider/2.4/default/CameraProvider.h +++ b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.h @@ -14,16 +14,14 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H -#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H +#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_LEGACYCAMERAPROVIDER_H +#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_LEGACYCAMERAPROVIDER_H -#include +#include #include "hardware/camera_common.h" #include "utils/Mutex.h" #include "utils/SortedVector.h" -#include -#include -#include + #include "CameraModule.h" #include "VendorTagDescriptor.h" @@ -50,26 +48,34 @@ using ::android::hardware::hidl_string; using ::android::sp; using ::android::Mutex; -struct CameraProvider : public ICameraProvider, public camera_module_callbacks_t { - CameraProvider(); - ~CameraProvider(); +/** + * The implementation of legacy wrapper CameraProvider 2.4, separated + * from the HIDL interface layer to allow for implementation reuse by later + * provider versions. + * + * This implementation supports cameras implemented via the legacy libhardware + * camera HAL definitions. + */ +struct LegacyCameraProviderImpl_2_4 : public camera_module_callbacks_t { + LegacyCameraProviderImpl_2_4(); + ~LegacyCameraProviderImpl_2_4(); // Caller must use this method to check if CameraProvider ctor failed bool isInitFailed() { return mInitFailed; } // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. - Return setCallback(const sp& callback) override; - Return getVendorTags(getVendorTags_cb _hidl_cb) override; - Return getCameraIdList(getCameraIdList_cb _hidl_cb) override; - Return isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override; + Return setCallback(const sp& callback); + Return getVendorTags(ICameraProvider::getVendorTags_cb _hidl_cb); + Return getCameraIdList(ICameraProvider::getCameraIdList_cb _hidl_cb); + Return isSetTorchModeSupported(ICameraProvider::isSetTorchModeSupported_cb _hidl_cb); Return getCameraDeviceInterface_V1_x( const hidl_string& cameraDeviceName, - getCameraDeviceInterface_V1_x_cb _hidl_cb) override; + ICameraProvider::getCameraDeviceInterface_V1_x_cb _hidl_cb); Return getCameraDeviceInterface_V3_x( const hidl_string& cameraDeviceName, - getCameraDeviceInterface_V3_x_cb _hidl_cb) override; + ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb); -private: +protected: Mutex mCbLock; sp mCallbacks = nullptr; @@ -98,7 +104,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); @@ -116,9 +121,8 @@ private: void addDeviceNames(int camera_id, CameraDeviceStatus status = CameraDeviceStatus::PRESENT, bool cam_new = false); void removeDeviceNames(int camera_id); -}; -extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name); +}; } // namespace implementation } // namespace V2_4 @@ -127,4 +131,4 @@ extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name); } // namespace hardware } // namespace android -#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H +#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_LEGACYCAMERAPROVIDER_H diff --git a/camera/provider/2.4/default/OWNERS b/camera/provider/2.4/default/OWNERS index 18acfee145..f48a95c5b3 100644 --- a/camera/provider/2.4/default/OWNERS +++ b/camera/provider/2.4/default/OWNERS @@ -1,6 +1 @@ -cychen@google.com -epeev@google.com -etalvala@google.com -shuzhenwang@google.com -yinchiayeh@google.com -zhijunhe@google.com +include platform/frameworks/av:/camera/OWNERS 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..4475f7d981 100644 --- a/camera/provider/2.4/default/service.cpp +++ b/camera/provider/2.4/default/service.cpp @@ -14,21 +14,40 @@ * 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 +#include #include -#include - -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() { - ALOGI("Camera provider Service is starting."); + ALOGI("CameraProvider@2.4 legacy service is starting."); // The camera HAL may communicate to other vendor components via // /dev/vndbinder android::ProcessState::initWithDriver("/dev/vndbinder"); - return defaultPassthroughServiceImplementation("legacy/0", /*maxThreads*/ 6); + status_t status; + if (kLazyService) { + status = defaultLazyPassthroughServiceImplementation("legacy/0", + /*maxThreads*/ 6); + } else { + status = defaultPassthroughServiceImplementation("legacy/0", + /*maxThreads*/ 6); + } + return status; } diff --git a/camera/provider/2.4/vts/OWNERS b/camera/provider/2.4/vts/OWNERS index 003fe71fa8..b8f6b048d2 100644 --- a/camera/provider/2.4/vts/OWNERS +++ b/camera/provider/2.4/vts/OWNERS @@ -1,10 +1,5 @@ # Camera team -cychen@google.com -epeev@google.com -etalvala@google.com -shuzhenwang@google.com -yinchiayeh@google.com -zhijunhe@google.com +include platform/frameworks/av:/camera/OWNERS # VTS team yim@google.com diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp index c71ce2f967..2c3ed37a6a 100644 --- a/camera/provider/2.4/vts/functional/Android.bp +++ b/camera/provider/2.4/vts/functional/Android.bp @@ -37,10 +37,15 @@ 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.camera.provider@2.5", "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.common@1.0", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "android.hidl.allocator@1.0", "libgrallocusage", "libhidlmemory", diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 22b738256d..86c2c1e15c 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -28,10 +28,15 @@ #include #include +#include #include #include +#include #include +#include #include +#include +#include #include #include #include @@ -49,8 +54,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -61,6 +68,7 @@ using namespace ::android::hardware::camera::device; using ::android::hardware::Return; using ::android::hardware::Void; +using ::android::hardware::hidl_bitfield; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; @@ -109,6 +117,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 +140,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 +153,20 @@ struct AvailableZSLInputOutput { int32_t outputFormat; }; +enum ReprocessType { + PRIV_REPROCESS, + YUV_REPROCESS, +}; + namespace { // "device@/legacy/" 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 +201,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; @@ -253,6 +274,16 @@ namespace { ALOGW("Unexpected HAL status code %d", s); return Status::OPERATION_NOT_SUPPORTED; } + + void getFirstApiLevel(/*out*/int32_t* outApiLevel) { + int32_t firstApiLevel = property_get_int32("ro.product.first_api_level", /*default*/-1); + if (firstApiLevel < 0) { + firstApiLevel = property_get_int32("ro.build.version.sdk", /*default*/-1); + } + ASSERT_GT(firstApiLevel, 0); // first_api_level must exist + *outApiLevel = firstApiLevel; + return; + } } // Test environment for camera @@ -526,12 +557,15 @@ public: uint32_t id; ASSERT_TRUE(parseProviderName(service_name, &mProviderType, &id)); + + castProvider(mProvider, &mProvider2_5); + notifyDeviceState(provider::V2_5::DeviceState::NORMAL); } virtual void TearDown() override {} hidl_vec getCameraDeviceNames(sp provider); - struct EmptyDeviceCb : public V3_4::ICameraDeviceCallback { + struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback { virtual Return processCaptureResult( const hidl_vec& /*results*/) override { ALOGI("processCaptureResult callback"); @@ -551,19 +585,65 @@ public: ADD_FAILURE(); // Empty callback should not reach here return Void(); } + + virtual Return requestStreamBuffers( + const hidl_vec&, + 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 emptyBufRets; + _hidl_cb(V3_5::BufferRequestStatus::FAILED_UNKNOWN, emptyBufRets); + return Void(); + } + + virtual Return returnStreamBuffers(const hidl_vec&) 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 processCaptureResult_3_4( const hidl_vec& results) override; Return processCaptureResult(const hidl_vec& results) override; Return notify(const hidl_vec& msgs) override; - private: - bool processCaptureResultLocked(const CaptureResult& results); + Return requestStreamBuffers( + const hidl_vec& bufReqs, + requestStreamBuffers_cb _hidl_cb) override; - CameraHidlTest *mParent; // Parent object + Return returnStreamBuffers(const hidl_vec& buffers) override; + + void setCurrentStreamConfig(const hidl_vec& streams, + const hidl_vec& halStreams); + + void waitForBuffersReturned(); + + private: + bool processCaptureResultLocked(const CaptureResult& results, + hidl_vec 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 mStreams; + hidl_vec mHalStreams; + uint64_t mNextBufferId = 1; + using OutstandingBuffers = std::unordered_map; + // size == mStreams.size(). Tracking each streams outstanding buffers + std::vector mOutstandingBufferIds; + std::condition_variable mFlushedCondition; }; struct TorchProviderCb : public ICameraProviderCallback { @@ -617,6 +697,8 @@ public: CameraHidlTest *mParent; // Parent object }; + void notifyDeviceState(::android::hardware::camera::provider::V2_5::DeviceState newState); + void openCameraDevice(const std::string &name, sp provider, sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device /*out*/); void setupPreviewWindow( @@ -644,14 +726,21 @@ public: void openEmptyDeviceSession(const std::string &name, sp provider, sp *session /*out*/, - camera_metadata_t **staticMeta /*out*/); + camera_metadata_t **staticMeta /*out*/, + ::android::sp *device = nullptr/*out*/); + void castProvider(const sp &provider, + sp *provider2_5 /*out*/); void castSession(const sp &session, int32_t deviceVersion, sp *session3_3 /*out*/, - sp *session3_4 /*out*/); + sp *session3_4 /*out*/, + sp *session3_5 /*out*/); + void castDevice(const sp &device, int32_t deviceVersion, + sp *device3_5/*out*/); void createStreamConfiguration(const ::android::hardware::hidl_vec& 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 +748,15 @@ public: const AvailableStream *previewThreshold, const std::unordered_set& physicalIds, sp *session3_4 /*out*/, + sp *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 *cb /*out*/, + uint32_t streamConfigCounter = 0, + bool allowUnsupport = false); void configurePreviewStream(const std::string &name, int32_t deviceVersion, sp provider, const AvailableStream *previewThreshold, @@ -670,18 +764,54 @@ public: V3_2::Stream *previewStream /*out*/, HalStreamConfiguration *halStreamConfig /*out*/, bool *supportsPartialResults /*out*/, - uint32_t *partialResultCount /*out*/); + uint32_t *partialResultCount /*out*/, + bool *useHalBufManager /*out*/, + sp *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& 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 cameraDevice3_5, + const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4, + bool expectedStatus, bool expectStreamCombQuery); + void verifyLogicalCameraResult(const camera_metadata_t* staticMetadata, + const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& resultMetadata); + + void verifyBuffersReturned(sp session, + int deviceVerison, int32_t streamId, sp cb, + uint32_t streamConfigCounter = 0); + + void verifyBuffersReturned(sp session, + hidl_vec streamIds, sp cb, + uint32_t streamConfigCounter = 0); + + void verifySessionReconfigurationQuery(sp session3_5, + camera_metadata* oldSessionParams, camera_metadata* newSessionParams); + + bool isDepthOnly(camera_metadata_t* staticMeta); + static Status getAvailableOutputStreams(camera_metadata_t *staticMeta, std::vector &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 *physicalIds/*out*/); static Status getSupportedKeys(camera_metadata_t *staticMeta, uint32_t tagId, std::unordered_set *requestIDs/*out*/); + static void fillOutputStreams(camera_metadata_ro_entry_t* entry, + std::vector& outputStreams, + const AvailableStream *threshold = nullptr, + const int32_t availableConfigOutputTag = 0u); static void constructFilteredSettings(const sp& session, const std::unordered_set& availableKeys, RequestTemplate reqTemplate, android::hardware::camera::common::V1_0::helper::CameraMetadata* defaultSettings/*out*/, @@ -689,7 +819,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 &inputOutputMap); static Status findLargestSize( @@ -697,6 +828,7 @@ public: int32_t format, AvailableStream &result); static Status isAutoFocusModeAvailable( CameraParameters &cameraParams, const char *mode) ; + static Status isMonochromeCamera(const camera_metadata_t *staticMeta); protected: @@ -797,6 +929,8 @@ protected: // Camera provider service sp mProvider; + sp<::android::hardware::camera::provider::V2_5::ICameraProvider> mProvider2_5; + // Camera provider type. std::string mProviderType; }; @@ -913,7 +1047,7 @@ Return CameraHidlTest::DeviceCb::processCaptureResult_3_4( bool notify = false; std::unique_lock 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 +1066,9 @@ Return CameraHidlTest::DeviceCb::processCaptureResult( bool notify = false; std::unique_lock l(mParent->mLock); + ::android::hardware::hidl_vec noPhysMetadata; for (size_t i = 0 ; i < results.size(); i++) { - notify = processCaptureResultLocked(results[i]); + notify = processCaptureResultLocked(results[i], noPhysMetadata); } l.unlock(); @@ -944,7 +1079,8 @@ Return CameraHidlTest::DeviceCb::processCaptureResult( return Void(); } -bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results) { +bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results, + hidl_vec physicalCameraMetadata) { bool notify = false; uint32_t frameNumber = results.frameNumber; @@ -985,6 +1121,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( @@ -1040,6 +1190,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 +1232,58 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r if (request->shutterTimestamp != 0) { notify = true; } + + if (mUseHalBufManager) { + // Don't return buffers of bufId 0 (empty buffer) + std::vector buffers; + for (const auto& sb : results.outputBuffers) { + if (sb.bufferId != 0) { + buffers.push_back(sb); + } + } + returnStreamBuffers(buffers); + } return notify; } +void CameraHidlTest::DeviceCb::setCurrentStreamConfig( + const hidl_vec& streams, const hidl_vec& 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 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 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 CameraHidlTest::DeviceCb::notify( const hidl_vec& messages) { std::lock_guard l(mParent->mLock); @@ -1110,6 +1326,125 @@ Return CameraHidlTest::DeviceCb::notify( return Void(); } +Return CameraHidlTest::DeviceCb::requestStreamBuffers( + const hidl_vec& bufReqs, + requestStreamBuffers_cb _hidl_cb) { + using V3_5::BufferRequestStatus; + using V3_5::StreamBufferRet; + using V3_5::StreamBufferRequestError; + hidl_vec bufRets; + std::unique_lock 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 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 tmpRetBuffers(bufReq.numBuffersRequested); + for (size_t j = 0; j < bufReq.numBuffersRequested; j++) { + hidl_handle buffer_handle; + mParent->allocateGraphicBuffer(stream.width, stream.height, + android_convertGralloc1To0Usage( + halStream.producerUsage, halStream.consumerUsage), + halStream.overrideFormat, &buffer_handle); + + tmpRetBuffers[j] = {stream.id, mNextBufferId, buffer_handle, BufferStatus::OK, + nullptr, nullptr}; + mOutstandingBufferIds[idx].insert(std::make_pair(mNextBufferId++, buffer_handle)); + } + atLeastOneStreamOk = true; + bufRets[i].streamId = stream.id; + bufRets[i].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 CameraHidlTest::DeviceCb::returnStreamBuffers( + const hidl_vec& buffers) { + if (!mUseHalBufManager) { + ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__); + ADD_FAILURE(); + } + + std::lock_guard 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 CameraHidlTest::getCameraDeviceNames(sp provider) { std::vector cameraDeviceNames; Return ret; @@ -1169,11 +1504,8 @@ hidl_vec CameraHidlTest::getCameraDeviceNames(sp p // Test devices with first_api_level >= P does not advertise device@1.0 TEST_F(CameraHidlTest, noHal1AfterP) { constexpr int32_t HAL1_PHASE_OUT_API_LEVEL = 28; - int32_t firstApiLevel = property_get_int32("ro.product.first_api_level", /*default*/-1); - if (firstApiLevel < 0) { - firstApiLevel = property_get_int32("ro.build.version.sdk", /*default*/-1); - } - ASSERT_GT(firstApiLevel, 0); // first_api_level must exist + int32_t firstApiLevel = 0; + getFirstApiLevel(&firstApiLevel); // all devices with first API level == 28 and <= 1GB of RAM must set low_ram // and thus be allowed to continue using HAL1 @@ -1194,11 +1526,19 @@ TEST_F(CameraHidlTest, noHal1AfterP) { } // Test if ICameraProvider::isTorchModeSupported returns Status::OK +// Also if first_api_level >= Q torch API must be supported. TEST_F(CameraHidlTest, isTorchModeSupported) { + constexpr int32_t API_LEVEL_Q = 29; + int32_t firstApiLevel = 0; + getFirstApiLevel(&firstApiLevel); + Return ret; ret = mProvider->isSetTorchModeSupported([&](auto status, bool support) { ALOGI("isSetTorchModeSupported returns status:%d supported:%d", (int)status, support); ASSERT_EQ(Status::OK, status); + if (firstApiLevel >= API_LEVEL_Q) { + ASSERT_EQ(true, support); + } }); ASSERT_TRUE(ret.isOk()); } @@ -1269,6 +1609,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 +1651,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 +2392,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 +2409,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 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 +2471,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 +2597,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 +2662,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 +2690,18 @@ TEST_F(CameraHidlTest, openClose) { // cast the 3.3/3.4 interface, and that lower versions can't be cast to it. sp sessionV3_3; sp sessionV3_4; - castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4); - if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) { + sp 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 +2754,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 +2857,13 @@ TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { sp session; sp session3_3; sp session3_4; + sp session3_5; + sp cameraDevice; + sp 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,23 +2874,46 @@ 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(it.format) == PixelFormat::BLOB; + V3_2::DataspaceFlags dataspaceFlag = 0; + switch (static_cast(it.format)) { + case PixelFormat::BLOB: + dataspaceFlag = static_cast(Dataspace::V0_JFIF); + break; + case PixelFormat::Y16: + dataspaceFlag = static_cast(Dataspace::DEPTH); + break; + default: + dataspaceFlag = static_cast(Dataspace::UNKNOWN); + } stream3_2 = {streamId, StreamType::OUTPUT, static_cast(it.width), static_cast(it.height), static_cast(it.format), GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, - (isJpeg) ? static_cast(Dataspace::V0_JFIF) : 0, + dataspaceFlag, StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec 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) { + bool expectStreamCombQuery = (isLogicalMultiCamera(staticMeta) == Status::OK); + verifyStreamCombination(cameraDevice3_5, config3_4, + /*expectedStatus*/ true, expectStreamCombQuery); + 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 +2965,13 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { sp session; sp session3_3; sp session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp session3_5; + sp cameraDevice; + sp 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 +2990,40 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0}; + uint32_t streamConfigCounter = 0; ::android::hardware::hidl_vec 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, + /*expectStreamCombQuery*/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 +3037,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 +3073,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 +3108,14 @@ TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { static_cast(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 +3162,13 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { sp session; sp session3_3; sp session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp session3_5; + sp cameraDevice; + sp 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 +3186,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(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(PixelFormat::IMPLEMENTATION_DEFINED) + && inputIter.outputFormat == static_cast(PixelFormat::Y8)) { + hasPrivToY8 = true; + } else if (inputIter.inputFormat == static_cast(PixelFormat::Y8)) { + if (inputIter.outputFormat == static_cast(PixelFormat::BLOB)) { + hasY8ToBlob = true; + } else if (inputIter.outputFormat == static_cast(PixelFormat::Y8)) { + hasY8ToY8 = true; + } + } AvailableStream outputThreshold = {INT32_MAX, INT32_MAX, inputIter.outputFormat}; std::vector outputStreams; @@ -2814,11 +3253,21 @@ TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { ::android::hardware::hidl_vec 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, /*expectStreamCombQuery*/ false); + 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 +3290,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 +3329,14 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) { sp session; sp session3_3; sp session3_4; + sp 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 availableSessionKeys; auto rc = getSupportedKeys(staticMetaBuffer, ANDROID_REQUEST_AVAILABLE_SESSION_KEYS, @@ -2886,7 +3350,8 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) { } android::hardware::camera::common::V1_0::helper::CameraMetadata previewRequestSettings; - android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams; + android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams, + modifiedSessionParams; constructFilteredSettings(session, availableSessionKeys, RequestTemplate::PREVIEW, &previewRequestSettings, &sessionParams); if (sessionParams.isEmpty()) { @@ -2914,17 +3379,44 @@ TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) { previewStream.bufferSize = 0; ::android::hardware::hidl_vec 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 (const_cast (sessionParamsBuffer)), + modifiedSessionParams = sessionParams; + auto sessionParamsBuffer = sessionParams.release(); + config.sessionParams.setToExternal(reinterpret_cast (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) { + bool newSessionParamsAvailable = false; + for (const auto& it : availableSessionKeys) { + if (modifiedSessionParams.exists(it)) { + modifiedSessionParams.erase(it); + newSessionParamsAvailable = true; + break; + } + } + if (newSessionParamsAvailable) { + auto modifiedSessionParamsBuffer = modifiedSessionParams.release(); + verifySessionReconfigurationQuery(session3_5, sessionParamsBuffer, + modifiedSessionParamsBuffer); + modifiedSessionParams.acquire(modifiedSessionParamsBuffer); + } + + 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()); + }); + } + sessionParams.acquire(sessionParamsBuffer); ASSERT_TRUE(ret.isOk()); free_camera_metadata(staticMetaBuffer); @@ -2959,8 +3451,21 @@ TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { sp session; sp session3_3; sp session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp session3_5; + sp cameraDevice; + sp 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); + + // Check if camera support depth only + if (isDepthOnly(staticMeta)) { + free_camera_metadata(staticMeta); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } outputBlobStreams.clear(); ASSERT_EQ(Status::OK, @@ -2978,6 +3483,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 +3504,21 @@ TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec 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, /*expectStreamCombQuery*/ false); + 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 +3568,13 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { sp session; sp session3_3; sp session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp session3_5; + sp cameraDevice; + sp 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 +3589,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(hfrStream.width), @@ -3077,11 +3599,22 @@ TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { 0, StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec 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, /*expectStreamCombQuery*/ false); + 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 +3648,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 +3687,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 +3722,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 +3779,21 @@ TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { sp session; sp session3_3; sp session3_4; - openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/); - castSession(session, deviceVersion, &session3_3, &session3_4); + sp session3_5; + sp cameraDevice; + sp 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); + + // Check if camera support depth only + if (isDepthOnly(staticMeta)) { + free_camera_metadata(staticMeta); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } outputBlobStreams.clear(); ASSERT_EQ(Status::OK, @@ -3247,6 +3812,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 +3832,21 @@ TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { static_cast(Dataspace::V0_JFIF), StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec 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, /*expectStreamCombQuery*/ false); + 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 +3897,14 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp session; + sp 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 resultQueue; auto resultQueueRet = @@ -3357,17 +3935,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 outputBuffers = {outputBuffer}; StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr}; @@ -3447,6 +4034,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()); } @@ -3465,7 +4056,7 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { for (const auto& name : cameraDeviceNames) { int deviceVersion = getCameraDeviceVersion(name, mProviderType); - if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) { + if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_5) { continue; } std::string version, deviceId; @@ -3528,13 +4119,20 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { V3_4::HalStreamConfiguration halStreamConfig; bool supportsPartialResults = false; + bool useHalBufManager = false; uint32_t partialResultCount = 0; V3_2::Stream previewStream; sp session3_4; + sp session3_5; + sp cb; configurePreviewStreams3_4(name, deviceVersion, mProvider, &previewThreshold, physicalIds, - &session3_4, &previewStream, &halStreamConfig /*out*/, - &supportsPartialResults /*out*/, &partialResultCount /*out*/); - ASSERT_NE(session3_4, nullptr); + &session3_4, &session3_5, &previewStream, &halStreamConfig /*out*/, + &supportsPartialResults /*out*/, &partialResultCount /*out*/, + &useHalBufManager /*out*/, &cb /*out*/, 0 /*streamConfigCounter*/, + true /*allowUnsupport*/); + if (session3_5 == nullptr) { + continue; + } std::shared_ptr resultQueue; auto resultQueueRet = @@ -3562,14 +4160,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 camSettings(1); @@ -3671,6 +4274,15 @@ TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) { defaultPreviewSettings.unlock(settingsBuffer); filteredSettings.unlock(filteredSettingsBuffer); + + if (useHalBufManager) { + hidl_vec 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 +4331,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 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 resultQueue; auto resultQueueRet = session->getCaptureResultMetadataQueue( @@ -3758,13 +4373,18 @@ TEST_F(CameraHidlTest, processCaptureRequestBurstISO) { std::unique_lock 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 (settings.data())); // Disable all 3A routines @@ -3817,6 +4437,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 +4469,25 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp session; + sp 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 +4543,14 @@ TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp session; + sp 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 ret; @@ -3977,12 +4609,14 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp session; + sp 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 resultQueue; auto resultQueueRet = @@ -4012,10 +4646,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 +4720,10 @@ TEST_F(CameraHidlTest, flushPreviewRequest) { } } + if (useHalBufManager) { + verifyBuffersReturned(session, deviceVersion, previewStream.id, cb); + } + ret = session->close(); ASSERT_TRUE(ret.isOk()); } @@ -4107,12 +4749,14 @@ TEST_F(CameraHidlTest, flushEmpty) { V3_2::Stream previewStream; HalStreamConfiguration halStreamConfig; sp session; + sp 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 returnStatus = session->flush(); ASSERT_TRUE(returnStatus.isOk()); @@ -4130,43 +4774,68 @@ TEST_F(CameraHidlTest, flushEmpty) { } } +// Test camera provider@2.5 notify method +TEST_F(CameraHidlTest, providerDeviceStateNotification) { + + notifyDeviceState(provider::V2_5::DeviceState::BACK_COVERED); + notifyDeviceState(provider::V2_5::DeviceState::NORMAL); +} + // Retrieve all valid output stream resolutions from the camera // static characteristics. Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta, std::vector &outputStreams, const AvailableStream *threshold) { + AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast(PixelFormat::Y16)}; if (nullptr == staticMeta) { return Status::ILLEGAL_ARGUMENT; } - camera_metadata_ro_entry entry; - int rc = find_camera_metadata_ro_entry(staticMeta, - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry); - if ((0 != rc) || (0 != (entry.count % 4))) { + camera_metadata_ro_entry scalarEntry; + camera_metadata_ro_entry depthEntry; + int foundScalar = find_camera_metadata_ro_entry(staticMeta, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &scalarEntry); + int foundDepth = find_camera_metadata_ro_entry(staticMeta, + ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, &depthEntry); + if ((0 != foundScalar || (0 != (scalarEntry.count % 4))) && + (0 != foundDepth || (0 != (depthEntry.count % 4)))) { return Status::ILLEGAL_ARGUMENT; } - for (size_t i = 0; i < entry.count; i+=4) { - if (ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT == - entry.data.i32[i + 3]) { + if(foundScalar == 0 && (0 == (scalarEntry.count % 4))) { + fillOutputStreams(&scalarEntry, outputStreams, threshold, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT); + } + + if(foundDepth == 0 && (0 == (depthEntry.count % 4))) { + fillOutputStreams(&depthEntry, outputStreams, &depthPreviewThreshold, + ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT); + } + + return Status::OK; +} + +void CameraHidlTest::fillOutputStreams(camera_metadata_ro_entry_t* entry, + std::vector& outputStreams, const AvailableStream* threshold, + const int32_t availableConfigOutputTag) { + for (size_t i = 0; i < entry->count; i+=4) { + if (availableConfigOutputTag == entry->data.i32[i + 3]) { if(nullptr == threshold) { - AvailableStream s = {entry.data.i32[i+1], - entry.data.i32[i+2], entry.data.i32[i]}; + AvailableStream s = {entry->data.i32[i+1], + entry->data.i32[i+2], entry->data.i32[i]}; outputStreams.push_back(s); } else { - if ((threshold->format == entry.data.i32[i]) && - (threshold->width >= entry.data.i32[i+1]) && - (threshold->height >= entry.data.i32[i+2])) { - AvailableStream s = {entry.data.i32[i+1], - entry.data.i32[i+2], threshold->format}; + if ((threshold->format == entry->data.i32[i]) && + (threshold->width >= entry->data.i32[i+1]) && + (threshold->height >= entry->data.i32[i+2])) { + AvailableStream s = {entry->data.i32[i+1], + entry->data.i32[i+2], threshold->format}; outputStreams.push_back(s); } } } - } - - return Status::OK; } // Get max jpeg buffer size in android.jpeg.maxSize @@ -4187,7 +4856,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 +4880,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 *physicalIds) { if ((nullptr == staticMeta) || (nullptr == physicalIds)) { return Status::ILLEGAL_ARGUMENT; @@ -4348,7 +5017,17 @@ 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; @@ -4362,10 +5041,34 @@ 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 ((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; + } + + 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 (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME == entry.data.u8[i]) { ret = Status::OK; break; } @@ -4438,9 +5141,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 streams3_4(streams3_2.size()); size_t idx = 0; @@ -4454,7 +5159,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 +5171,23 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t const AvailableStream *previewThreshold, const std::unordered_set& physicalIds, sp *session3_4 /*out*/, + sp *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 *outCb /*out*/, + uint32_t streamConfigCounter, + bool allowUnsupport) { 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 outputPreviewStreams; @@ -4490,7 +5205,25 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t }); ASSERT_TRUE(ret.isOk()); - sp cb = new DeviceCb(this); + camera_metadata_t *staticMeta; + ret = device3_x->getCameraCharacteristics([&] (Status s, + CameraMetadata metadata) { + ASSERT_EQ(Status::OK, s); + staticMeta = clone_camera_metadata( + reinterpret_cast(metadata.data())); + ASSERT_NE(nullptr, staticMeta); + }); + ASSERT_TRUE(ret.isOk()); + + camera_metadata_ro_entry entry; + auto status = find_camera_metadata_ro_entry(staticMeta, + ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry); + if ((0 == status) && (entry.count > 0)) { + *partialResultCount = entry.data.i32[0]; + *supportsPartialResults = (*partialResultCount > 1); + } + + sp cb = new DeviceCb(this, deviceVersion, staticMeta); sp session; ret = device3_x->open( cb, @@ -4501,27 +5234,18 @@ void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t session = newSession; }); ASSERT_TRUE(ret.isOk()); + *outCb = cb; sp session3_3; - castSession(session, deviceVersion, &session3_3, session3_4); - ASSERT_NE(nullptr, session3_4); + castSession(session, deviceVersion, &session3_3, session3_4, session3_5); + ASSERT_NE(nullptr, (*session3_4).get()); - camera_metadata_t *staticMeta; - ret = device3_x->getCameraCharacteristics([&] (Status s, - CameraMetadata metadata) { - ASSERT_EQ(Status::OK, s); - staticMeta = clone_camera_metadata( - reinterpret_cast(metadata.data())); - ASSERT_NE(nullptr, staticMeta); - }); - ASSERT_TRUE(ret.isOk()); - - camera_metadata_ro_entry entry; - auto status = find_camera_metadata_ro_entry(staticMeta, - ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry); - if ((0 == status) && (entry.count > 0)) { - *partialResultCount = entry.data.i32[0]; - *supportsPartialResults = (*partialResultCount > 1); + *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(); @@ -4544,6 +5268,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,16 +5278,89 @@ 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; - }); + ASSERT_TRUE(!allowUnsupport || deviceVersion == CAMERA_DEVICE_API_VERSION_3_5); + if (allowUnsupport) { + sp cameraDevice3_5; + castDevice(device3_x, deviceVersion, &cameraDevice3_5); + + bool supported = false; + ret = cameraDevice3_5->isStreamCombinationSupported(config3_4, + [&supported](Status s, bool combStatus) { + ASSERT_TRUE((Status::OK == s) || + (Status::METHOD_NOT_SUPPORTED == s)); + if (Status::OK == s) { + supported = combStatus; + } + }); + ASSERT_TRUE(ret.isOk()); + // If stream combination is not supported, return null session. + if (!supported) { + *session3_5 = nullptr; + return; + } + } + + 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 streams(physicalIds.size()); + hidl_vec 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()); } +bool CameraHidlTest::isDepthOnly(camera_metadata_t* staticMeta) { + camera_metadata_ro_entry scalarEntry; + camera_metadata_ro_entry depthEntry; + + int rc = find_camera_metadata_ro_entry( + staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &scalarEntry); + if (rc == 0) { + for (uint32_t i = 0; i < scalarEntry.count; i++) { + if (scalarEntry.data.u8[i] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) { + return false; + } + } + } + + for (uint32_t i = 0; i < scalarEntry.count; i++) { + if (scalarEntry.data.u8[i] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) { + + rc = find_camera_metadata_ro_entry( + staticMeta, ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, &depthEntry); + size_t i = 0; + if (rc == 0 && depthEntry.data.i32[i] == static_cast(PixelFormat::Y16)) { + // only Depth16 format is supported now + return true; + } + break; + } + } + + return false; +} + // Open a device session and configure a preview stream. void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion, sp provider, @@ -4571,12 +5369,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 *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 outputPreviewStreams; ::android::sp device3_x; @@ -4593,21 +5396,6 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev }); ASSERT_TRUE(ret.isOk()); - sp 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 session3_3; - sp session3_4; - castSession(*session, deviceVersion, &session3_3, &session3_4); - camera_metadata_t *staticMeta; ret = device3_x->getCameraCharacteristics([&] (Status s, CameraMetadata metadata) { @@ -4626,6 +5414,31 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev *supportsPartialResults = (*partialResultCount > 1); } + sp 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 session3_3; + sp session3_4; + sp 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); @@ -4638,17 +5451,50 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev ASSERT_EQ(Status::OK, rc); ASSERT_FALSE(outputPreviewStreams.empty()); + V3_2::DataspaceFlags dataspaceFlag = 0; + switch (static_cast(outputPreviewStreams[0].format)) { + case PixelFormat::Y16: + dataspaceFlag = static_cast(Dataspace::DEPTH); + break; + default: + dataspaceFlag = static_cast(Dataspace::UNKNOWN); + } + V3_2::Stream stream3_2 = {0, StreamType::OUTPUT, static_cast (outputPreviewStreams[0].width), static_cast (outputPreviewStreams[0].height), static_cast (outputPreviewStreams[0].format), - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0}; + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, dataspaceFlag, StreamRotation::ROTATION_0}; ::android::hardware::hidl_vec 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 streams(1); + hidl_vec 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 +5533,48 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev ASSERT_TRUE(ret.isOk()); } +void CameraHidlTest::castDevice(const sp &device, + int32_t deviceVersion, sp *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 provider to corresponding version if available +void CameraHidlTest::castProvider(const sp &provider, + sp *provider2_5 /*out*/) { + ASSERT_NE(nullptr, provider2_5); + auto castResult = provider::V2_5::ICameraProvider::castFrom(provider); + if (castResult.isOk()) { + *provider2_5 = castResult; + } +} + //Cast camera device session to corresponding version void CameraHidlTest::castSession(const sp &session, int32_t deviceVersion, sp *session3_3 /*out*/, - sp *session3_4 /*out*/) { + sp *session3_4 /*out*/, + sp *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 +5587,381 @@ void CameraHidlTest::castSession(const sp &session, int32_ } } +void CameraHidlTest::verifyStreamCombination(sp cameraDevice3_5, + const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4, + bool expectedStatus, bool expectMethodSupported) { + if (cameraDevice3_5.get() != nullptr) { + auto ret = cameraDevice3_5->isStreamCombinationSupported(config3_4, + [expectedStatus, expectMethodSupported] (Status s, bool combStatus) { + ASSERT_TRUE((Status::OK == s) || + (!expectMethodSupported && 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& 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 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 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( + 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!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, &entry); + if (0 == retcode || entry.count > 0) { + ADD_FAILURE() << "ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS " + << " per API contract should never be set by Hal!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS, &entry); + if (0 == retcode || entry.count > 0) { + ADD_FAILURE() << "ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS " + << " per API contract should never be set by Hal!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS, &entry); + if (0 == retcode || entry.count > 0) { + ADD_FAILURE() << "ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS " + << " per API contract should never be set by Hal!"; + } + + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_HEIC_INFO_SUPPORTED, &entry); + if (0 == retcode && entry.count > 0) { + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT, &entry); + if (0 == retcode && entry.count > 0) { + uint8_t maxJpegAppSegmentsCount = entry.data.u8[0]; + ASSERT_TRUE(maxJpegAppSegmentsCount >= 1 && + maxJpegAppSegmentsCount <= 16); + } else { + ADD_FAILURE() << "Get Heic maxJpegAppSegmentsCount failed!"; + } + } +} + +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( + CameraMetadataEnumAndroidSensorInfoColorFilterArrangement::ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO) + || entry.data.i32[0] == static_cast( + 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 session, + int deviceVersion, int32_t streamId, + sp cb, uint32_t streamConfigCounter) { + sp session3_3; + sp session3_4; + sp session3_5; + castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5); + ASSERT_NE(nullptr, session3_5.get()); + + hidl_vec streamIds(1); + streamIds[0] = streamId; + session3_5->signalStreamFlush(streamIds, /*streamConfigCounter*/streamConfigCounter); + cb->waitForBuffersReturned(); +} + +void CameraHidlTest::verifyBuffersReturned( + sp session3_4, + hidl_vec streamIds, sp cb, uint32_t streamConfigCounter) { + auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session3_4); + ASSERT_TRUE(castResult.isOk()); + sp 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 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(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 provider, - sp *session /*out*/, - camera_metadata_t **staticMeta /*out*/) { +void CameraHidlTest::openEmptyDeviceSession(const std::string &name, sp provider, + sp *session /*out*/, camera_metadata_t **staticMeta /*out*/, + ::android::sp *cameraDevice /*out*/) { ASSERT_NE(nullptr, session); ASSERT_NE(nullptr, staticMeta); @@ -4734,6 +5978,9 @@ void CameraHidlTest::openEmptyDeviceSession(const std::string &name, device3_x = device; }); ASSERT_TRUE(ret.isOk()); + if (cameraDevice != nullptr) { + *cameraDevice = device3_x; + } sp cb = new EmptyDeviceCb(); ret = device3_x->open(cb, [&](auto status, const auto& newSession) { @@ -4754,6 +6001,13 @@ void CameraHidlTest::openEmptyDeviceSession(const std::string &name, ASSERT_TRUE(ret.isOk()); } +void CameraHidlTest::notifyDeviceState(provider::V2_5::DeviceState newState) { + if (mProvider2_5.get() == nullptr) return; + + mProvider2_5->notifyDeviceStateChange( + static_cast>(newState)); +} + // Open a particular camera device. void CameraHidlTest::openCameraDevice(const std::string &name, sp provider, @@ -4886,36 +6140,183 @@ void CameraHidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint sp allocator = android::hardware::graphics::allocator::V2_0::IAllocator::getService(); - ASSERT_NE(nullptr, allocator.get()); + sp allocatorV3 = + android::hardware::graphics::allocator::V3_0::IAllocator::getService(); + sp mapperV3 = + android::hardware::graphics::mapper::V3_0::IMapper::getService(); sp mapper = android::hardware::graphics::mapper::V2_0::IMapper::getService(); - ASSERT_NE(mapper.get(), nullptr); - - android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo {}; - descriptorInfo.width = width; - descriptorInfo.height = height; - descriptorInfo.layerCount = 1; - descriptorInfo.format = format; - descriptorInfo.usage = usage; - ::android::hardware::hidl_vec descriptor; - auto ret = mapper->createDescriptor( - descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V2_0::Error err, - ::android::hardware::hidl_vec desc) { - ASSERT_EQ(err, android::hardware::graphics::mapper::V2_0::Error::NONE); - descriptor = desc; - }); - ASSERT_TRUE(ret.isOk()); + if (mapperV3 != nullptr && allocatorV3 != nullptr) { + android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {}; + descriptorInfo.width = width; + descriptorInfo.height = height; + descriptorInfo.layerCount = 1; + descriptorInfo.format = + static_cast(format); + descriptorInfo.usage = usage; - ret = allocator->allocate(descriptor, 1u, - [&](android::hardware::graphics::mapper::V2_0::Error err, uint32_t /*stride*/, - const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) { - ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE, err); - ASSERT_EQ(buffers.size(), 1u); - *buffer_handle = buffers[0]; - }); + auto ret = mapperV3->createDescriptor( + descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V3_0::Error err, + ::android::hardware::hidl_vec desc) { + ASSERT_EQ(err, android::hardware::graphics::mapper::V3_0::Error::NONE); + descriptor = desc; + }); + ASSERT_TRUE(ret.isOk()); + + ret = allocatorV3->allocate(descriptor, 1u, + [&](android::hardware::graphics::mapper::V3_0::Error err, uint32_t /*stride*/, + const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) { + ASSERT_EQ(android::hardware::graphics::mapper::V3_0::Error::NONE, err); + ASSERT_EQ(buffers.size(), 1u); + *buffer_handle = buffers[0]; + }); + ASSERT_TRUE(ret.isOk()); + } else { + ASSERT_NE(mapper.get(), nullptr); + ASSERT_NE(allocator.get(), nullptr); + android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo {}; + descriptorInfo.width = width; + descriptorInfo.height = height; + descriptorInfo.layerCount = 1; + descriptorInfo.format = format; + descriptorInfo.usage = usage; + + auto ret = mapper->createDescriptor( + descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V2_0::Error err, + ::android::hardware::hidl_vec desc) { + ASSERT_EQ(err, android::hardware::graphics::mapper::V2_0::Error::NONE); + descriptor = desc; + }); + ASSERT_TRUE(ret.isOk()); + + ret = allocator->allocate(descriptor, 1u, + [&](android::hardware::graphics::mapper::V2_0::Error err, uint32_t /*stride*/, + const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) { + ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE, err); + ASSERT_EQ(buffers.size(), 1u); + *buffer_handle = buffers[0]; + }); + 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 (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 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); + } +} + +void CameraHidlTest::verifySessionReconfigurationQuery( + sp session3_5, camera_metadata* oldSessionParams, + camera_metadata* newSessionParams) { + ASSERT_NE(nullptr, session3_5.get()); + ASSERT_NE(nullptr, oldSessionParams); + ASSERT_NE(nullptr, newSessionParams); + + android::hardware::hidl_vec oldParams, newParams; + oldParams.setToExternal(reinterpret_cast(oldSessionParams), + get_camera_metadata_size(oldSessionParams)); + newParams.setToExternal(reinterpret_cast(newSessionParams), + get_camera_metadata_size(newSessionParams)); + android::hardware::camera::common::V1_0::Status callStatus; + auto hidlCb = [&callStatus] (android::hardware::camera::common::V1_0::Status s, + bool /*requiredFlag*/) { + callStatus = s; + }; + auto ret = session3_5->isReconfigurationRequired(oldParams, newParams, hidlCb); ASSERT_TRUE(ret.isOk()); + switch (callStatus) { + case android::hardware::camera::common::V1_0::Status::OK: + case android::hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED: + break; + case android::hardware::camera::common::V1_0::Status::INTERNAL_ERROR: + default: + ADD_FAILURE() << "Query calllback failed"; + } } int main(int argc, char **argv) { diff --git a/camera/provider/2.5/Android.bp b/camera/provider/2.5/Android.bp new file mode 100644 index 0000000000..4ca1efbfc3 --- /dev/null +++ b/camera/provider/2.5/Android.bp @@ -0,0 +1,21 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.camera.provider@2.5", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ICameraProvider.hal", + ], + interfaces: [ + "android.hardware.camera.common@1.0", + "android.hardware.camera.device@1.0", + "android.hardware.camera.device@3.2", + "android.hardware.camera.provider@2.4", + "android.hidl.base@1.0", + ], + gen_java: false, +} diff --git a/camera/provider/2.5/ICameraProvider.hal b/camera/provider/2.5/ICameraProvider.hal new file mode 100644 index 0000000000..b4cda6a04f --- /dev/null +++ b/camera/provider/2.5/ICameraProvider.hal @@ -0,0 +1,68 @@ +/* + * 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.provider@2.5; + +import android.hardware.camera.common@1.0::Status; +import android.hardware.camera.provider@2.4::ICameraProvider; + +/** + * Camera provider HAL + * + * Version 2.5 adds support for the notifyDeviceStateChange method + */ +interface ICameraProvider extends @2.4::ICameraProvider { + + /** + * notifyDeviceStateChange: + * + * Notify the HAL provider that the state of the overall device has + * changed in some way that the HAL may want to know about. + * + * For example, a physical shutter may have been uncovered or covered, + * or a camera may have been covered or uncovered by an add-on keyboard + * or other accessory. + * + * The state is a bitfield of potential states, and some physical configurations + * could plausibly correspond to multiple different combinations of state bits. + * The HAL must ignore any state bits it is not actively using to determine + * the appropriate camera configuration. + * + * For example, on some devices the FOLDED state could mean that + * backward-facing cameras are covered by the fold, so FOLDED by itself implies + * BACK_COVERED. But other devices may support folding but not cover any cameras + * when folded, so for those FOLDED would not imply any of the other flags. + * Since these relationships are very device-specific, it is difficult to specify + * a comprehensive policy. But as a recommendation, it is suggested that if a flag + * necessarily implies other flags are set as well, then those flags should be set. + * So even though FOLDED would be enough to infer BACK_COVERED on some devices, the + * BACK_COVERED flag should also be set for clarity. + * + * This method may be invoked by the HAL client at any time. It must not + * cause any active camera device sessions to be closed, but may dynamically + * change which physical camera a logical multi-camera is using for its + * active and future output. + * + * The method must be invoked by the HAL client at least once before the + * client calls ICameraDevice::open on any camera device interfaces listed + * by this provider, to establish the initial device state. + * + * @param newState + * The new state of the device. + */ + notifyDeviceStateChange(bitfield newState); + +}; diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp new file mode 100644 index 0000000000..cd1caebe37 --- /dev/null +++ b/camera/provider/2.5/default/Android.bp @@ -0,0 +1,187 @@ +cc_library_shared { + name: "android.hardware.camera.provider@2.5-legacy", + proprietary: true, + srcs: ["LegacyCameraProviderImpl_2_5.cpp"], + shared_libs: [ + "android.hardware.camera.common@1.0", + "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.provider@2.4-legacy", + "android.hardware.camera.provider@2.5", + "android.hardware.graphics.mapper@2.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "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", + "libcamera_metadata", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + header_libs: [ + "camera.device@3.4-impl_headers", + "camera.device@3.5-impl_headers", + ], + export_include_dirs: ["."], +} + +cc_library_shared { + name: "android.hardware.camera.provider@2.5-external", + proprietary: true, + srcs: ["ExternalCameraProviderImpl_2_5.cpp"], + shared_libs: [ + "android.hardware.camera.common@1.0", + "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.provider@2.4-external", + "android.hardware.camera.provider@2.5", + "android.hardware.graphics.mapper@2.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "camera.device@3.3-impl", + "camera.device@3.4-external-impl", + "camera.device@3.4-impl", + "camera.device@3.5-external-impl", + "camera.device@3.5-impl", + "libcamera_metadata", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libtinyxml2", + "libutils", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + header_libs: [ + "camera.device@3.4-external-impl_headers", + "camera.device@3.5-external-impl_headers" + ], + export_include_dirs: ["."], +} + +cc_defaults { + name: "camera_service_2_5_defaults", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["service.cpp"], + shared_libs: [ + "android.hardware.camera.common@1.0", + "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.provider@2.4-legacy", + "android.hardware.camera.provider@2.5", + "android.hardware.camera.provider@2.5-legacy", + "android.hardware.graphics.mapper@2.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "libbinder", + "libcamera_metadata", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + header_libs: [ + "camera.device@3.4-impl_headers", + "camera.device@3.5-impl_headers" + ], +} + +cc_binary { + name: "android.hardware.camera.provider@2.5-service", + defaults: ["camera_service_2_5_defaults"], + compile_multilib: "32", + init_rc: ["android.hardware.camera.provider@2.5-service.rc"], +} + +cc_binary { + name: "android.hardware.camera.provider@2.5-service_64", + defaults: ["camera_service_2_5_defaults"], + compile_multilib: "64", + init_rc: ["android.hardware.camera.provider@2.5-service_64.rc"], +} + +cc_binary { + name: "android.hardware.camera.provider@2.5-service-lazy", + overrides: ["android.hardware.camera.provider@2.5-service"], + defaults: ["camera_service_2_5_defaults"], + compile_multilib: "32", + init_rc: ["android.hardware.camera.provider@2.5-service-lazy.rc"], + cflags: ["-DLAZY_SERVICE"], +} + +cc_binary { + name: "android.hardware.camera.provider@2.5-service-lazy_64", + overrides: ["android.hardware.camera.provider@2.5-service_64"], + defaults: ["camera_service_2_5_defaults"], + compile_multilib: "64", + init_rc: ["android.hardware.camera.provider@2.5-service-lazy_64.rc"], + cflags: ["-DLAZY_SERVICE"], +} + +cc_binary { + name: "android.hardware.camera.provider@2.5-external-service", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["external-service.cpp"], + compile_multilib: "32", + init_rc: ["android.hardware.camera.provider@2.5-external-service.rc"], + shared_libs: [ + "android.hardware.camera.common@1.0", + "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.provider@2.4-external", + "android.hardware.camera.provider@2.5", + "android.hardware.camera.provider@2.5-external", + "android.hardware.graphics.mapper@2.0", + "libbinder", + "libhidlbase", + "libhidltransport", + "liblog", + "libtinyxml2", + "libutils", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper", + ], + header_libs: [ + "camera.device@3.4-external-impl_headers", + "camera.device@3.4-impl_headers", + "camera.device@3.5-external-impl_headers", + "camera.device@3.5-impl_headers", + ], +} diff --git a/camera/provider/2.5/default/CameraProvider_2_5.h b/camera/provider/2.5/default/CameraProvider_2_5.h new file mode 100644 index 0000000000..d0f1ddaaf5 --- /dev/null +++ b/camera/provider/2.5/default/CameraProvider_2_5.h @@ -0,0 +1,94 @@ +/* + * 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_CAMERA_PROVIDER_V2_5_CAMERAPROVIDER_H +#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_5_CAMERAPROVIDER_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace camera { +namespace provider { +namespace V2_5 { +namespace implementation { + +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::provider::V2_5::ICameraProvider; +using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback; +using ::android::hardware::Return; +using ::android::hardware::hidl_string; +using ::android::sp; + +// Default recommended RPC thread count for camera provider implementations +const int HWBINDER_THREAD_COUNT = 6; + +template +struct CameraProvider : public ICameraProvider { + CameraProvider() : impl() {} + ~CameraProvider() {} + + // Caller must use this method to check if CameraProvider ctor failed + bool isInitFailed() { return impl.isInitFailed(); } + + // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. + Return setCallback(const sp& callback) override { + return impl.setCallback(callback); + } + + Return getVendorTags(getVendorTags_cb _hidl_cb) override { + return impl.getVendorTags(_hidl_cb); + } + + Return getCameraIdList(getCameraIdList_cb _hidl_cb) override { + return impl.getCameraIdList(_hidl_cb); + } + + Return isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override { + return impl.isSetTorchModeSupported(_hidl_cb); + } + + Return getCameraDeviceInterface_V1_x( + const hidl_string& cameraDeviceName, + getCameraDeviceInterface_V1_x_cb _hidl_cb) override { + return impl.getCameraDeviceInterface_V1_x(cameraDeviceName, _hidl_cb); + } + + Return getCameraDeviceInterface_V3_x( + const hidl_string& cameraDeviceName, + getCameraDeviceInterface_V3_x_cb _hidl_cb) override { + return impl.getCameraDeviceInterface_V3_x(cameraDeviceName, _hidl_cb); + } + + // Methods from ::android::hardware::camera::provider::V2_5::ICameraProvider follow. + Return notifyDeviceStateChange(hardware::hidl_bitfield newState) override { + return impl.notifyDeviceStateChange(newState); + } + +private: + IMPL impl; +}; + +} // namespace implementation +} // namespace V2_5 +} // namespace provider +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_5_CAMERAPROVIDER_H diff --git a/audio/common/2.0/default/VersionUtils.h b/camera/provider/2.5/default/ExternalCameraProviderImpl_2_5.cpp similarity index 57% rename from audio/common/2.0/default/VersionUtils.h rename to camera/provider/2.5/default/ExternalCameraProviderImpl_2_5.cpp index 60d1f9cb6d..87851cd4b1 100644 --- a/audio/common/2.0/default/VersionUtils.h +++ b/camera/provider/2.5/default/ExternalCameraProviderImpl_2_5.cpp @@ -14,28 +14,34 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_VERSION_UTILS_H -#define ANDROID_HARDWARE_AUDIO_EFFECT_VERSION_UTILS_H +#define LOG_TAG "CamPrvdr@2.5-external" +//#define LOG_NDEBUG 0 +#include -#include +#include "ExternalCameraProviderImpl_2_5.h" namespace android { namespace hardware { -namespace audio { -namespace common { -namespace V2_0 { +namespace camera { +namespace provider { +namespace V2_5 { 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; +ExternalCameraProviderImpl_2_5::ExternalCameraProviderImpl_2_5() : + ExternalCameraProviderImpl_2_4() { +} + +ExternalCameraProviderImpl_2_5::~ExternalCameraProviderImpl_2_5() { +} + +Return ExternalCameraProviderImpl_2_5::notifyDeviceStateChange( + hidl_bitfield /*newState*/) { + return Void(); +} } // namespace implementation -} // namespace V2_0 -} // namespace common -} // namespace audio +} // namespace V2_5 +} // namespace provider +} // namespace camera } // namespace hardware } // namespace android - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_VERSION_UTILS_H diff --git a/camera/provider/2.5/default/ExternalCameraProviderImpl_2_5.h b/camera/provider/2.5/default/ExternalCameraProviderImpl_2_5.h new file mode 100644 index 0000000000..eeaa7cca06 --- /dev/null +++ b/camera/provider/2.5/default/ExternalCameraProviderImpl_2_5.h @@ -0,0 +1,62 @@ +/* + * 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_CAMERA_PROVIDER_V2_5_EXTCAMERAPROVIDER_H +#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_5_EXTCAMERAPROVIDER_H + +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace camera { +namespace provider { +namespace V2_5 { +namespace implementation { + +using namespace ::android::hardware::camera::provider; + +using ::android::hardware::camera::common::V1_0::CameraDeviceStatus; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::VendorTagSection; +using ::android::hardware::camera::external::common::ExternalCameraConfig; +using ::android::hardware::camera::provider::V2_5::ICameraProvider; +using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_bitfield; + +struct ExternalCameraProviderImpl_2_5 : + public V2_4::implementation::ExternalCameraProviderImpl_2_4 { + ExternalCameraProviderImpl_2_5(); + ~ExternalCameraProviderImpl_2_5(); + + // Methods from ::android::hardware::camera::provider::V2_5::ICameraProvider follow. + Return notifyDeviceStateChange(hidl_bitfield newState); +private: +}; + +} // namespace implementation +} // namespace V2_5 +} // namespace provider +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_5_EXTCAMERAPROVIDER_H diff --git a/camera/provider/2.5/default/LegacyCameraProviderImpl_2_5.cpp b/camera/provider/2.5/default/LegacyCameraProviderImpl_2_5.cpp new file mode 100644 index 0000000000..5233397bb8 --- /dev/null +++ b/camera/provider/2.5/default/LegacyCameraProviderImpl_2_5.cpp @@ -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. + */ + +#define LOG_TAG "CamPrvdr@2.5-legacy" +//#define LOG_NDEBUG 0 +#include +#include + +#include "LegacyCameraProviderImpl_2_5.h" +#include "CameraProvider_2_5.h" + +namespace android { +namespace hardware { +namespace camera { +namespace provider { +namespace V2_5 { +namespace implementation { + +template struct CameraProvider; + +LegacyCameraProviderImpl_2_5::LegacyCameraProviderImpl_2_5() : + LegacyCameraProviderImpl_2_4() { +} + +LegacyCameraProviderImpl_2_5::~LegacyCameraProviderImpl_2_5() {} + +Return LegacyCameraProviderImpl_2_5::notifyDeviceStateChange( + hidl_bitfield newState) { + ALOGD("%s: New device state: 0x%" PRIx64, __FUNCTION__, newState); + uint64_t state = static_cast(newState); + mModule->notifyDeviceStateChange(state); + return Void(); +} + +} // namespace implementation +} // namespace V2_5 +} // namespace provider +} // namespace camera +} // namespace hardware +} // namespace android diff --git a/camera/provider/2.5/default/LegacyCameraProviderImpl_2_5.h b/camera/provider/2.5/default/LegacyCameraProviderImpl_2_5.h new file mode 100644 index 0000000000..62dd97f590 --- /dev/null +++ b/camera/provider/2.5/default/LegacyCameraProviderImpl_2_5.h @@ -0,0 +1,62 @@ +/* + * 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_CAMERA_PROVIDER_V2_5_LEGACYCAMERAPROVIDER_H +#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_5_LEGACYCAMERAPROVIDER_H + +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace camera { +namespace provider { +namespace V2_5 { +namespace implementation { + +using namespace ::android::hardware::camera::provider; + +using ::android::hardware::camera::common::V1_0::CameraDeviceStatus; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::TorchModeStatus; +using ::android::hardware::camera::common::V1_0::VendorTag; +using ::android::hardware::camera::common::V1_0::VendorTagSection; +using ::android::hardware::camera::common::V1_0::helper::CameraModule; +using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptor; +using ::android::hardware::camera::provider::V2_5::DeviceState; +using ::android::hardware::hidl_bitfield; +using ::android::hardware::Return; + +struct LegacyCameraProviderImpl_2_5 : public V2_4::implementation::LegacyCameraProviderImpl_2_4 { + LegacyCameraProviderImpl_2_5(); + ~LegacyCameraProviderImpl_2_5(); + + // Methods from ::android::hardware::camera::provider::V2_5::ICameraProvider follow. + Return notifyDeviceStateChange(hidl_bitfield newState); +private: +}; + +} // namespace implementation +} // namespace V2_5 +} // namespace provider +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_5_CAMERAPROVIDER_H diff --git a/camera/provider/2.5/default/OWNERS b/camera/provider/2.5/default/OWNERS new file mode 100644 index 0000000000..f48a95c5b3 --- /dev/null +++ b/camera/provider/2.5/default/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/av:/camera/OWNERS diff --git a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-external-service.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-external-service.rc new file mode 100644 index 0000000000..107097e661 --- /dev/null +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-external-service.rc @@ -0,0 +1,9 @@ +service vendor.camera-provider-2-5-ext /vendor/bin/hw/android.hardware.camera.provider@2.5-external-service + interface android.hardware.camera.provider@2.5::ICameraProvider external/0 + interface android.hardware.camera.provider@2.4::ICameraProvider external/0 + class hal + user cameraserver + group audio camera input drmrpc usb + ioprio rt 4 + capabilities SYS_NICE + writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks diff --git a/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy.rc new file mode 100644 index 0000000000..b45158a082 --- /dev/null +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy.rc @@ -0,0 +1,11 @@ +service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provider@2.5-service-lazy + interface android.hardware.camera.provider@2.5::ICameraProvider legacy/0 + 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.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc new file mode 100644 index 0000000000..aa070d9b3a --- /dev/null +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service-lazy_64.rc @@ -0,0 +1,11 @@ +service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provider@2.5-service-lazy_64 + interface android.hardware.camera.provider@2.5::ICameraProvider legacy/0 + interface android.hardware.camera.provider@2.5::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.5/default/android.hardware.camera.provider@2.5-service.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service.rc new file mode 100644 index 0000000000..c065815fab --- /dev/null +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service.rc @@ -0,0 +1,9 @@ +service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provider@2.5-service + interface android.hardware.camera.provider@2.5::ICameraProvider legacy/0 + interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0 + 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.5/default/android.hardware.camera.provider@2.5-service_64.rc b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service_64.rc new file mode 100644 index 0000000000..63dd11d349 --- /dev/null +++ b/camera/provider/2.5/default/android.hardware.camera.provider@2.5-service_64.rc @@ -0,0 +1,9 @@ +service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provider@2.5-service_64 + interface android.hardware.camera.provider@2.5::ICameraProvider legacy/0 + interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0 + 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.5/default/external-service.cpp b/camera/provider/2.5/default/external-service.cpp new file mode 100644 index 0000000000..8788916cf3 --- /dev/null +++ b/camera/provider/2.5/default/external-service.cpp @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#define LOG_TAG "android.hardware.camera.provider@2.5-external-service" + +#include +#include +#include + +#include "CameraProvider_2_5.h" +#include "ExternalCameraProviderImpl_2_5.h" + +using android::status_t; +using android::hardware::camera::provider::V2_5::ICameraProvider; + +int main() +{ + using namespace android::hardware::camera::provider::V2_5::implementation; + + ALOGI("CameraProvider@2.5 external webcam service is starting."); + + ::android::hardware::configureRpcThreadpool(/*threads*/ HWBINDER_THREAD_COUNT, /*willJoin*/ true); + + ::android::sp provider = new CameraProvider(); + + status_t status = provider->registerAsService("external/0"); + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering provider service: %d", + status); + + ::android::hardware::joinRpcThreadpool(); + + return 0; +} diff --git a/camera/provider/2.5/default/service.cpp b/camera/provider/2.5/default/service.cpp new file mode 100644 index 0000000000..604215d71c --- /dev/null +++ b/camera/provider/2.5/default/service.cpp @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifdef LAZY_SERVICE +#define LOG_TAG "android.hardware.camera.provider@2.5-service-lazy" +#else +#define LOG_TAG "android.hardware.camera.provider@2.5-service" +#endif + +#include +#include +#include +#include + +#include "CameraProvider_2_5.h" +#include "LegacyCameraProviderImpl_2_5.h" + +using android::status_t; +using android::hardware::camera::provider::V2_5::ICameraProvider; + +#ifdef LAZY_SERVICE +const bool kLazyService = true; +#else +const bool kLazyService = false; +#endif + +int main() +{ + using namespace android::hardware::camera::provider::V2_5::implementation; + + ALOGI("CameraProvider@2.5 legacy service is starting."); + + ::android::hardware::configureRpcThreadpool(/*threads*/ HWBINDER_THREAD_COUNT, /*willJoin*/ true); + + ::android::sp provider = new CameraProvider(); + + status_t status; + if (kLazyService) { + auto serviceRegistrar = std::make_shared<::android::hardware::LazyServiceRegistrar>(); + status = serviceRegistrar->registerService(provider, "legacy/0"); + } else { + status = provider->registerAsService("legacy/0"); + } + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering provider service: %d", + status); + + ::android::hardware::joinRpcThreadpool(); + + return 0; +} diff --git a/camera/provider/2.5/types.hal b/camera/provider/2.5/types.hal new file mode 100644 index 0000000000..6a8ae83c45 --- /dev/null +++ b/camera/provider/2.5/types.hal @@ -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. + */ + +package android.hardware.camera.provider@2.5; + +/** + * DeviceState: + * + * Possible physical states of the overall device, for use with + * ICameraProvider::notifyDeviceStateChange. + * + */ +enum DeviceState : uint64_t { + /** + * The device is in its normal physical configuration. This is the default if the + * device does not support multiple different states. + */ + NORMAL = 0, + + /** + * Camera device(s) facing backward are covered. + */ + BACK_COVERED = 1 << 0, + + /** + * Camera device(s) facing foward are covered. + */ + FRONT_COVERED = 1 << 1, + + /** + * The device is folded. If not set, the device is unfolded or does not + * support folding. + * + * The exact point when this status change happens during the folding + * operation is device-specific. + */ + FOLDED = 1 << 2, + +}; 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 #include #include +#include #include #include @@ -177,6 +178,7 @@ Return 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 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/cas/1.1/Android.bp b/cas/1.1/Android.bp new file mode 100644 index 0000000000..13217b6439 --- /dev/null +++ b/cas/1.1/Android.bp @@ -0,0 +1,19 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.cas@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "ICas.hal", + "ICasListener.hal", + "IMediaCasService.hal", + ], + interfaces: [ + "android.hardware.cas@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} diff --git a/cas/1.1/ICas.hal b/cas/1.1/ICas.hal new file mode 100644 index 0000000000..027968e565 --- /dev/null +++ b/cas/1.1/ICas.hal @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.cas@1.1; + +import @1.0::HidlCasSessionId; +import @1.0::ICas; +import @1.0::Status; + +/** + * ICas is the API to control the cas system and is accessible from both + * Java and native level. It is used to manage sessions, provision/refresh + * the cas system, and process the EMM/ECM messages. It also allows bi-directional, + * scheme-specific communications between the client and the cas system. + */ + +interface ICas extends @1.0::ICas { + /** + * Send an scheme-specific session event to the CasPlugin. + * + * @param sessionId the id of an opened session. + * @param event an integer denoting a scheme-specific event to be sent. + * @param arg a scheme-specific integer argument for the event. + * @param data a byte array containing scheme-specific data for the event. + * @return status the status of the call. + */ + sendSessionEvent(HidlCasSessionId sessionId, int32_t event, int32_t arg, + vec eventData) + generates (Status status); +}; diff --git a/cas/1.1/ICasListener.hal b/cas/1.1/ICasListener.hal new file mode 100644 index 0000000000..5ec1154a3f --- /dev/null +++ b/cas/1.1/ICasListener.hal @@ -0,0 +1,33 @@ +/* + * 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.cas@1.1; + +import @1.0::ICasListener; +import @1.0::HidlCasSessionId; + +interface ICasListener extends @1.0::ICasListener{ + /** + * Notify the listener of a scheme-specific session event from CA system. + * + * @param sessionId the id of an opened session. + * @param event an integer whose meaning is scheme-specific. + * @param arg an integer whose meaning is scheme-specific. + * @param data a byte array of data whose format and meaning are + * scheme-specific. + */ + onSessionEvent(HidlCasSessionId sessionId, int32_t event, int32_t arg, + vec data); +}; diff --git a/cas/1.1/IMediaCasService.hal b/cas/1.1/IMediaCasService.hal new file mode 100644 index 0000000000..e82b54c9db --- /dev/null +++ b/cas/1.1/IMediaCasService.hal @@ -0,0 +1,38 @@ +/* + * 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.cas@1.1; + +import @1.1::ICas; +import @1.1::ICasListener; +import @1.0::IMediaCasService; + +/** + * IMediaCasService is the main entry point for interacting with a vendor's + * cas HAL to create cas and descrambler plugin instances. A cas plugin instance + * opens cas sessions which are used to obtain keys for a descrambler session, + * which can in turn be used to descramble protected video content. + */ + +interface IMediaCasService extends @1.0::IMediaCasService { + /** + * Construct a new instance of a @1.1 ICAS CasPlugin given a CA_system_id. + * + * @param caSystemId the id of the CA system. + * @param listener the event listener to receive events coming from the CasPlugin. + * @return cas the newly created CasPlugin interface. + */ + createPluginExt(int32_t caSystemId, ICasListener listener) generates (ICas cas); +}; diff --git a/cas/1.1/default/Android.bp b/cas/1.1/default/Android.bp new file mode 100644 index 0000000000..68a49cf5b1 --- /dev/null +++ b/cas/1.1/default/Android.bp @@ -0,0 +1,49 @@ +cc_defaults { + name: "cas_service_defaults@1.1", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "CasImpl.cpp", + "DescramblerImpl.cpp", + "MediaCasService.cpp", + "service.cpp", + "SharedLibrary.cpp", + "TypeConvert.cpp", + ], + + compile_multilib: "32", + + shared_libs: [ + "android.hardware.cas@1.0", + "android.hardware.cas@1.1", + "android.hardware.cas.native@1.0", + "android.hidl.memory@1.0", + "libbinder", + "libhidlbase", + "libhidlmemory", + "libhidltransport", + "liblog", + "libutils", + ], + header_libs: [ + "libstagefright_foundation_headers", + "media_plugin_headers", + ], +} + +cc_binary { + name: "android.hardware.cas@1.1-service", + vintf_fragments: ["android.hardware.cas@1.1-service.xml"], + defaults: ["cas_service_defaults@1.1"], + init_rc: ["android.hardware.cas@1.1-service.rc"], +} + +cc_binary { + name: "android.hardware.cas@1.1-service-lazy", + vintf_fragments: ["android.hardware.cas@1.1-service-lazy.xml"], + overrides: ["android.hardware.cas@1.1-service"], + defaults: ["cas_service_defaults@1.1"], + init_rc: ["android.hardware.cas@1.1-service-lazy.rc"], + cflags: ["-DLAZY_SERVICE"], +} diff --git a/cas/1.1/default/CasImpl.cpp b/cas/1.1/default/CasImpl.cpp new file mode 100644 index 0000000000..4cc6017028 --- /dev/null +++ b/cas/1.1/default/CasImpl.cpp @@ -0,0 +1,222 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-CasImpl" + +#include +#include +#include + +#include "CasImpl.h" +#include "SharedLibrary.h" +#include "TypeConvert.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +CasImpl::CasImpl(const sp& listener) : mListener(listener) { + ALOGV("CTOR"); +} + +CasImpl::~CasImpl() { + ALOGV("DTOR"); + release(); +} + +// static +void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) { + if (appData == NULL) { + ALOGE("Invalid appData!"); + return; + } + CasImpl* casImpl = static_cast(appData); + casImpl->onEvent(event, arg, data, size); +} + +// static +void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size, + const CasSessionId* sessionId) { + if (appData == NULL) { + ALOGE("Invalid appData!"); + return; + } + CasImpl* casImpl = static_cast(appData); + casImpl->onEvent(sessionId, event, arg, data, size); +} + +void CasImpl::init(const sp& library, CasPlugin* plugin) { + mLibrary = library; + std::shared_ptr holder(plugin); + std::atomic_store(&mPluginHolder, holder); +} + +void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) { + if (mListener == NULL) { + return; + } + + HidlCasData eventData; + if (data != NULL) { + eventData.setToExternal(data, size); + } + + mListener->onEvent(event, arg, eventData); +} + +void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data, + size_t size) { + if (mListener == NULL) { + return; + } + + HidlCasData eventData; + if (data != NULL) { + eventData.setToExternal(data, size); + } + + if (sessionId != NULL) { + mListener->onSessionEvent(*sessionId, event, arg, eventData); + } else { + mListener->onEvent(event, arg, eventData); + } +} + +Return CasImpl::setPrivateData(const HidlCasData& pvtData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->setPrivateData(pvtData)); +} + +Return CasImpl::openSession(openSession_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + CasSessionId sessionId; + + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + status_t err = INVALID_OPERATION; + if (holder.get() != nullptr) { + err = holder->openSession(&sessionId); + holder.reset(); + } + + _hidl_cb(toStatus(err), sessionId); + + return Void(); +} + +Return CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId, + const HidlCasData& pvtData) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->setSessionPrivateData(sessionId, pvtData)); +} + +Return CasImpl::closeSession(const HidlCasSessionId& sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->closeSession(sessionId)); +} + +Return CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->processEcm(sessionId, ecm)); +} + +Return CasImpl::processEmm(const HidlCasData& emm) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->processEmm(emm)); +} + +Return CasImpl::sendEvent(int32_t event, int32_t arg, const HidlCasData& eventData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->sendEvent(event, arg, eventData); + return toStatus(err); +} + +Return CasImpl::sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event, + int32_t arg, const HidlCasData& eventData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData); + return toStatus(err); +} + +Return CasImpl::provision(const hidl_string& provisionString) { + ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->provision(String8(provisionString.c_str()))); +} + +Return CasImpl::refreshEntitlements(int32_t refreshType, const HidlCasData& refreshData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->refreshEntitlements(refreshType, refreshData); + return toStatus(err); +} + +Return CasImpl::release() { + ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get()); + + std::shared_ptr holder(nullptr); + std::atomic_store(&mPluginHolder, holder); + + return Status::OK; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/CasImpl.h b/cas/1.1/default/CasImpl.h new file mode 100644 index 0000000000..18aee9e457 --- /dev/null +++ b/cas/1.1/default/CasImpl.h @@ -0,0 +1,98 @@ +/* + * 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_CAS_V1_1_CAS_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_ + +#include +#include + +namespace android { +struct CasPlugin; + +namespace hardware { +namespace cas { +namespace V1_1 { +struct ICasListener; +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasData; +using ::android::hardware::cas::V1_0::HidlCasSessionId; +using ::android::hardware::cas::V1_0::Status; + +class SharedLibrary; + +class CasImpl : public ICas { + public: + CasImpl(const sp& listener); + virtual ~CasImpl(); + + static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size); + + static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size, + const CasSessionId* sessionId); + + void init(const sp& library, CasPlugin* plugin); + void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size); + + void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data, + size_t size); + + // ICas inherits + + virtual Return setPrivateData(const HidlCasData& pvtData) override; + + virtual Return openSession(openSession_cb _hidl_cb) override; + + virtual Return closeSession(const HidlCasSessionId& sessionId) override; + + virtual Return setSessionPrivateData(const HidlCasSessionId& sessionId, + const HidlCasData& pvtData) override; + + virtual Return processEcm(const HidlCasSessionId& sessionId, + const HidlCasData& ecm) override; + + virtual Return processEmm(const HidlCasData& emm) override; + + virtual Return sendEvent(int32_t event, int32_t arg, + const HidlCasData& eventData) override; + + virtual Return sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event, + int32_t arg, const HidlCasData& eventData) override; + + virtual Return provision(const hidl_string& provisionString) override; + + virtual Return refreshEntitlements(int32_t refreshType, + const HidlCasData& refreshData) override; + + virtual Return release() override; + + private: + struct PluginHolder; + sp mLibrary; + std::shared_ptr mPluginHolder; + sp mListener; + + DISALLOW_EVIL_CONSTRUCTORS(CasImpl); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_ diff --git a/cas/1.1/default/DescramblerImpl.cpp b/cas/1.1/default/DescramblerImpl.cpp new file mode 100644 index 0000000000..36dc1a51d0 --- /dev/null +++ b/cas/1.1/default/DescramblerImpl.cpp @@ -0,0 +1,195 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-DescramblerImpl" + +#include +#include +#include +#include +#include + +#include "DescramblerImpl.h" +#include "SharedLibrary.h" +#include "TypeConvert.h" + +namespace android { +using hidl::memory::V1_0::IMemory; + +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +#define CHECK_SUBSAMPLE_DEF(type) \ + static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \ + static_assert(offsetof(SubSample, numBytesOfClearData) == \ + offsetof(type::SubSample, mNumBytesOfClearData), \ + "SubSample: numBytesOfClearData offset doesn't match"); \ + static_assert(offsetof(SubSample, numBytesOfEncryptedData) == \ + offsetof(type::SubSample, mNumBytesOfEncryptedData), \ + "SubSample: numBytesOfEncryptedData offset doesn't match") + +CHECK_SUBSAMPLE_DEF(DescramblerPlugin); +CHECK_SUBSAMPLE_DEF(CryptoPlugin); + +DescramblerImpl::DescramblerImpl(const sp& library, DescramblerPlugin* plugin) + : mLibrary(library), mPluginHolder(plugin) { + ALOGV("CTOR: plugin=%p", mPluginHolder.get()); +} + +DescramblerImpl::~DescramblerImpl() { + ALOGV("DTOR: plugin=%p", mPluginHolder.get()); + release(); +} + +Return DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->setMediaCasSession(sessionId)); +} + +Return DescramblerImpl::requiresSecureDecoderComponent(const hidl_string& mime) { + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return false; + } + + return holder->requiresSecureDecoderComponent(String8(mime.c_str())); +} + +static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) { + return isInRange(0, size, offset, length); +} + +Return DescramblerImpl::descramble(ScramblingControl scramblingControl, + const hidl_vec& subSamples, + const SharedBuffer& srcBuffer, uint64_t srcOffset, + const DestinationBuffer& dstBuffer, uint64_t dstOffset, + descramble_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map + // size in size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed + // but the mapped memory's actual size will be smaller than the reported size. + if (srcBuffer.heapBase.size() > SIZE_MAX) { + ALOGE("Invalid hidl_memory size: %llu", srcBuffer.heapBase.size()); + android_errorWriteLog(0x534e4554, "79376389"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + sp srcMem = mapMemory(srcBuffer.heapBase); + + // Validate if the offset and size in the SharedBuffer is consistent with the + // mapped ashmem, since the offset and size is controlled by client. + if (srcMem == NULL) { + ALOGE("Failed to map src buffer."); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize())) { + ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu", + srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize()); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + // use 64-bit here to catch bad subsample size that might be overflowing. + uint64_t totalBytesInSubSamples = 0; + for (size_t i = 0; i < subSamples.size(); i++) { + totalBytesInSubSamples += + (uint64_t)subSamples[i].numBytesOfClearData + subSamples[i].numBytesOfEncryptedData; + } + // Further validate if the specified srcOffset and requested total subsample size + // is consistent with the source shared buffer size. + if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) { + ALOGE("Invalid srcOffset and subsample size: " + "srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu", + srcOffset, totalBytesInSubSamples, srcBuffer.size); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + void* srcPtr = (uint8_t*)(void*)srcMem->getPointer() + srcBuffer.offset; + void* dstPtr = NULL; + if (dstBuffer.type == BufferType::SHARED_MEMORY) { + // When using shared memory, src buffer is also used as dst, + // we don't map it again here. + dstPtr = srcPtr; + + // In this case the dst and src would be the same buffer, need to validate + // dstOffset against the buffer size too. + if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) { + ALOGE("Invalid dstOffset and subsample size: " + "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu", + dstOffset, totalBytesInSubSamples, srcBuffer.size); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + } else { + native_handle_t* handle = + const_cast(dstBuffer.secureMemory.getNativeHandle()); + dstPtr = static_cast(handle); + } + + // Get a local copy of the shared_ptr for the plugin. Note that before + // calling the HIDL callback, this shared_ptr must be manually reset, + // since the client side could proceed as soon as the callback is called + // without waiting for this method to go out of scope. + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL); + return Void(); + } + + // Casting hidl SubSample to DescramblerPlugin::SubSample, but need + // to ensure structs are actually idential + + int32_t result = + holder->descramble(dstBuffer.type != BufferType::SHARED_MEMORY, + (DescramblerPlugin::ScramblingControl)scramblingControl, + subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(), + srcPtr, srcOffset, dstPtr, dstOffset, NULL); + + holder.reset(); + _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL); + return Void(); +} + +Return DescramblerImpl::release() { + ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get()); + + std::shared_ptr holder(nullptr); + std::atomic_store(&mPluginHolder, holder); + + return Status::OK; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/DescramblerImpl.h b/cas/1.1/default/DescramblerImpl.h new file mode 100644 index 0000000000..a1f66ae464 --- /dev/null +++ b/cas/1.1/default/DescramblerImpl.h @@ -0,0 +1,67 @@ +/* + * 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_CAS_V1_1_DESCRAMBLER_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_ + +#include +#include + +namespace android { +struct DescramblerPlugin; +using namespace hardware::cas::native::V1_0; + +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasSessionId; +using ::android::hardware::cas::V1_0::Status; + +class SharedLibrary; + +class DescramblerImpl : public IDescrambler { + public: + DescramblerImpl(const sp& library, DescramblerPlugin* plugin); + virtual ~DescramblerImpl(); + + virtual Return setMediaCasSession(const HidlCasSessionId& sessionId) override; + + virtual Return requiresSecureDecoderComponent(const hidl_string& mime) override; + + virtual Return descramble(ScramblingControl scramblingControl, + const hidl_vec& subSamples, + const SharedBuffer& srcBuffer, uint64_t srcOffset, + const DestinationBuffer& dstBuffer, uint64_t dstOffset, + descramble_cb _hidl_cb) override; + + virtual Return release() override; + + private: + sp mLibrary; + std::shared_ptr mPluginHolder; + + DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_ diff --git a/cas/1.1/default/FactoryLoader.h b/cas/1.1/default/FactoryLoader.h new file mode 100644 index 0000000000..c4a48e2852 --- /dev/null +++ b/cas/1.1/default/FactoryLoader.h @@ -0,0 +1,217 @@ +/* + * 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_CAS_V1_1_FACTORY_LOADER_H_ +#define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ + +#include +#include +#include +#include +#include +#include "SharedLibrary.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor; + +template +class FactoryLoader { + public: + FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {} + + virtual ~FactoryLoader() { closeFactory(); } + + bool findFactoryForScheme(int32_t CA_system_id, sp* library = NULL, + T** factory = NULL); + + bool enumeratePlugins(vector* results); + + private: + typedef T* (*CreateFactoryFunc)(); + + Mutex mMapLock; + T* mFactory; + const char* mCreateFactoryFuncName; + sp mLibrary; + KeyedVector mCASystemIdToLibraryPathMap; + KeyedVector > mLibraryPathToOpenLibraryMap; + + bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, + sp* library, T** factory); + + bool queryPluginsFromPath(const String8& path, vector* results); + + bool openFactory(const String8& path); + void closeFactory(); +}; + +template +bool FactoryLoader::findFactoryForScheme(int32_t CA_system_id, sp* library, + T** factory) { + if (library != NULL) { + library->clear(); + } + if (factory != NULL) { + *factory = NULL; + } + + Mutex::Autolock autoLock(mMapLock); + + // first check cache + ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id); + if (index >= 0) { + return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id, + library, factory); + } + + // no luck, have to search + String8 dirPath("/vendor/lib/mediacas"); + DIR* pDir = opendir(dirPath.string()); + + if (pDir == NULL) { + ALOGE("Failed to open plugin directory %s", dirPath.string()); + return false; + } + + struct dirent* pEntry; + while ((pEntry = readdir(pDir))) { + String8 pluginPath = dirPath + "/" + pEntry->d_name; + if (pluginPath.getPathExtension() == ".so") { + if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) { + mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath); + closedir(pDir); + + return true; + } + } + } + + closedir(pDir); + + ALOGE("Failed to find plugin"); + return false; +} + +template +bool FactoryLoader::enumeratePlugins(vector* results) { + ALOGI("enumeratePlugins"); + + results->clear(); + + String8 dirPath("/vendor/lib/mediacas"); + DIR* pDir = opendir(dirPath.string()); + + if (pDir == NULL) { + ALOGE("Failed to open plugin directory %s", dirPath.string()); + return false; + } + + Mutex::Autolock autoLock(mMapLock); + + struct dirent* pEntry; + while ((pEntry = readdir(pDir))) { + String8 pluginPath = dirPath + "/" + pEntry->d_name; + if (pluginPath.getPathExtension() == ".so") { + queryPluginsFromPath(pluginPath, results); + } + } + return true; +} + +template +bool FactoryLoader::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, + sp* library, T** factory) { + closeFactory(); + + if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) { + closeFactory(); + return false; + } + + if (library != NULL) { + *library = mLibrary; + } + if (factory != NULL) { + *factory = mFactory; + } + return true; +} + +template +bool FactoryLoader::queryPluginsFromPath(const String8& path, + vector* results) { + closeFactory(); + + vector descriptors; + if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) { + closeFactory(); + return false; + } + + for (auto it = descriptors.begin(); it != descriptors.end(); it++) { + results->push_back( + HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()}); + } + return true; +} + +template +bool FactoryLoader::openFactory(const String8& path) { + // get strong pointer to open shared library + ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); + if (index >= 0) { + mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); + } else { + index = mLibraryPathToOpenLibraryMap.add(path, NULL); + } + + if (!mLibrary.get()) { + mLibrary = new SharedLibrary(path); + if (!*mLibrary) { + return false; + } + + mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); + } + + CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName); + if (createFactory == NULL || (mFactory = createFactory()) == NULL) { + return false; + } + return true; +} + +template +void FactoryLoader::closeFactory() { + delete mFactory; + mFactory = NULL; + mLibrary.clear(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ diff --git a/cas/1.1/default/MediaCasService.cpp b/cas/1.1/default/MediaCasService.cpp new file mode 100644 index 0000000000..eb3fa6b599 --- /dev/null +++ b/cas/1.1/default/MediaCasService.cpp @@ -0,0 +1,147 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-MediaCasService" + +#include +#include +#include +#include + +#include "CasImpl.h" +#include "DescramblerImpl.h" +#include "MediaCasService.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +class Wrapper : public V1_1::ICasListener { + public: + static sp wrap(sp impl) { + sp cast = V1_1::ICasListener::castFrom(impl); + if (cast == NULL) { + cast = new Wrapper(impl); + } + return cast; + } + + virtual Return onEvent(int32_t event, int32_t arg, + const hidl_vec& data) override { + mImpl->onEvent(event, arg, data); + return Void(); + } + + virtual Return onSessionEvent(const hidl_vec& /* sessionId */, + int32_t /* event */, int32_t /* arg */, + const hidl_vec& /*data*/) override { + ALOGV("Do nothing on Session Event for cas@1.0 client in cas@1.1"); + return Void(); + } + + private: + Wrapper(sp impl) : mImpl(impl){}; + sp mImpl; +}; + +MediaCasService::MediaCasService() + : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {} + +MediaCasService::~MediaCasService() {} + +Return MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + vector results; + mCasLoader.enumeratePlugins(&results); + + _hidl_cb(results); + return Void(); +} + +Return MediaCasService::isSystemIdSupported(int32_t CA_system_id) { + ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id); + + return mCasLoader.findFactoryForScheme(CA_system_id); +} + +Return> MediaCasService::createPlugin(int32_t CA_system_id, + const sp& listener) { + ALOGV("%s:Use createPluginExt to create plugin in cas@1.1", __FUNCTION__); + + sp result; + + sp listenerV1_1 = Wrapper::wrap(listener); + + result = createPluginExt(CA_system_id, listenerV1_1); + + return result; +} + +Return> MediaCasService::createPluginExt(int32_t CA_system_id, + const sp& listener) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__); + + sp result; + + CasFactory* factory; + sp library; + if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) { + CasPlugin* plugin = NULL; + sp casImpl = new CasImpl(listener); + if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) == + OK && + plugin != NULL) { + casImpl->init(library, plugin); + result = casImpl; + } + } + + return result; +} + +Return MediaCasService::isDescramblerSupported(int32_t CA_system_id) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + + return mDescramblerLoader.findFactoryForScheme(CA_system_id); +} + +Return> MediaCasService::createDescrambler(int32_t CA_system_id) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + + sp result; + + DescramblerFactory* factory; + sp library; + if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) { + DescramblerPlugin* plugin = NULL; + if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) { + result = new DescramblerImpl(library, plugin); + } + } + + return result; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/MediaCasService.h b/cas/1.1/default/MediaCasService.h new file mode 100644 index 0000000000..ec5a86d9b3 --- /dev/null +++ b/cas/1.1/default/MediaCasService.h @@ -0,0 +1,66 @@ +/* + * 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_CAS_V1_1_MEDIA_CAS_SERVICE_H_ +#define ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_ + +#include + +#include "FactoryLoader.h" + +namespace android { +struct CasFactory; +struct DescramblerFactory; +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor; +using ::android::hardware::cas::V1_0::IDescramblerBase; + +class MediaCasService : public IMediaCasService { + public: + MediaCasService(); + + virtual Return enumeratePlugins(enumeratePlugins_cb _hidl_cb) override; + + virtual Return isSystemIdSupported(int32_t CA_system_id) override; + + virtual Return> createPlugin(int32_t CA_system_id, + const sp& listener) override; + + virtual Return> createPluginExt(int32_t CA_system_id, + const sp& listener) override; + + virtual Return isDescramblerSupported(int32_t CA_system_id) override; + + virtual Return> createDescrambler(int32_t CA_system_id) override; + + private: + FactoryLoader mCasLoader; + FactoryLoader mDescramblerLoader; + + virtual ~MediaCasService(); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_ diff --git a/cas/1.1/default/SharedLibrary.cpp b/cas/1.1/default/SharedLibrary.cpp new file mode 100644 index 0000000000..ffe4bb977a --- /dev/null +++ b/cas/1.1/default/SharedLibrary.cpp @@ -0,0 +1,65 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-SharedLibrary" + +#include "SharedLibrary.h" +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +SharedLibrary::SharedLibrary(const String8& path) { + mLibHandle = dlopen(path.string(), RTLD_NOW); +} + +SharedLibrary::~SharedLibrary() { + if (mLibHandle != NULL) { + dlclose(mLibHandle); + mLibHandle = NULL; + } +} + +bool SharedLibrary::operator!() const { + return mLibHandle == NULL; +} + +void* SharedLibrary::lookup(const char* symbol) const { + if (!mLibHandle) { + return NULL; + } + // Clear last error before we load the symbol again, + // in case the caller didn't retrieve it. + (void)dlerror(); + return dlsym(mLibHandle, symbol); +} + +const char* SharedLibrary::lastError() const { + const char* error = dlerror(); + return error ? error : "No errors or unknown error"; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/SharedLibrary.h b/cas/1.1/default/SharedLibrary.h new file mode 100644 index 0000000000..f4d2ff6b9d --- /dev/null +++ b/cas/1.1/default/SharedLibrary.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ +#define ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ + +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +class SharedLibrary : public RefBase { + public: + explicit SharedLibrary(const String8& path); + ~SharedLibrary(); + + bool operator!() const; + void* lookup(const char* symbol) const; + const char* lastError() const; + + private: + void* mLibHandle; + DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ diff --git a/cas/1.1/default/TypeConvert.cpp b/cas/1.1/default/TypeConvert.cpp new file mode 100644 index 0000000000..09ef41ae8f --- /dev/null +++ b/cas/1.1/default/TypeConvert.cpp @@ -0,0 +1,94 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "android.hardware.cas@1.1-TypeConvert" + +#include "TypeConvert.h" +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +Status toStatus(status_t legacyStatus) { + Status status; + switch (legacyStatus) { + case android::OK: + status = Status::OK; + break; + case android::ERROR_CAS_NO_LICENSE: + status = Status::ERROR_CAS_NO_LICENSE; + break; + case android::ERROR_CAS_LICENSE_EXPIRED: + status = Status::ERROR_CAS_LICENSE_EXPIRED; + break; + case android::ERROR_CAS_SESSION_NOT_OPENED: + status = Status::ERROR_CAS_SESSION_NOT_OPENED; + break; + case android::ERROR_CAS_CANNOT_HANDLE: + status = Status::ERROR_CAS_CANNOT_HANDLE; + break; + case android::ERROR_CAS_TAMPER_DETECTED: + status = Status::ERROR_CAS_INVALID_STATE; + break; + case android::BAD_VALUE: + status = Status::BAD_VALUE; + break; + case android::ERROR_CAS_NOT_PROVISIONED: + status = Status::ERROR_CAS_NOT_PROVISIONED; + break; + case android::ERROR_CAS_RESOURCE_BUSY: + status = Status::ERROR_CAS_RESOURCE_BUSY; + break; + case android::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION: + status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION; + break; + case android::ERROR_CAS_DEVICE_REVOKED: + status = Status::ERROR_CAS_DEVICE_REVOKED; + break; + case android::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED: + status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED; + break; + case android::ERROR_CAS_DECRYPT: + status = Status::ERROR_CAS_DECRYPT; + break; + default: + ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus); + status = Status::ERROR_CAS_UNKNOWN; + break; + } + return status; +} + +String8 sessionIdToString(const CasSessionId& sessionId) { + String8 result; + for (size_t i = 0; i < sessionId.size(); i++) { + result.appendFormat("%02x ", sessionId[i]); + } + if (result.isEmpty()) { + result.append("(null)"); + } + return result; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/TypeConvert.h b/cas/1.1/default/TypeConvert.h new file mode 100644 index 0000000000..c4a0119926 --- /dev/null +++ b/cas/1.1/default/TypeConvert.h @@ -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. + */ + +#ifndef ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H +#define ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::Status; + +Status toStatus(status_t legacyStatus); + +String8 sessionIdToString(const CasSessionId& sessionId); + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc new file mode 100644 index 0000000000..9227b6f7e4 --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc @@ -0,0 +1,9 @@ +service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service-lazy + interface android.hardware.cas@1.1::IMediaCasService default + oneshot + disabled + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml new file mode 100644 index 0000000000..c9f13ba34a --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml @@ -0,0 +1,11 @@ + + + android.hardware.cas + hwbinder + 1.1 + + IMediaCasService + default + + + diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.rc b/cas/1.1/default/android.hardware.cas@1.1-service.rc new file mode 100644 index 0000000000..4081fe1e64 --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service.rc @@ -0,0 +1,6 @@ +service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.xml b/cas/1.1/default/android.hardware.cas@1.1-service.xml new file mode 100644 index 0000000000..c9f13ba34a --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.cas + hwbinder + 1.1 + + IMediaCasService + default + + + diff --git a/cas/1.1/default/service.cpp b/cas/1.1/default/service.cpp new file mode 100644 index 0000000000..962530370c --- /dev/null +++ b/cas/1.1/default/service.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 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_NDEBUG 0 +#ifdef LAZY_SERVICE +#define LOG_TAG "android.hardware.cas@1.1-service-lazy" +#else +#define LOG_TAG "android.hardware.cas@1.1-service" +#endif + +#include +#include +#include + +#include "MediaCasService.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::LazyServiceRegistrar; +using android::hardware::cas::V1_1::IMediaCasService; +using android::hardware::cas::V1_1::implementation::MediaCasService; + +#ifdef LAZY_SERVICE +const bool kLazyService = true; +#else +const bool kLazyService = false; +#endif + +int main() { + configureRpcThreadpool(8, true /* callerWillJoin */); + + // Setup hwbinder service + android::sp service = new MediaCasService(); + android::status_t status; + if (kLazyService) { + auto serviceRegistrar = std::make_shared(); + status = serviceRegistrar->registerService(service); + } else { + status = service->registerAsService(); + } + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering cas service: %d", status); + + joinRpcThreadpool(); + return 0; +} diff --git a/audio/effect/2.0/vts/functional/Android.bp b/cas/1.1/vts/functional/Android.bp similarity index 65% rename from audio/effect/2.0/vts/functional/Android.bp rename to cas/1.1/vts/functional/Android.bp index 57887200eb..8afd19abda 100644 --- a/audio/effect/2.0/vts/functional/Android.bp +++ b/cas/1.1/vts/functional/Android.bp @@ -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. @@ -15,20 +15,21 @@ // cc_test { - name: "VtsHalAudioEffectV2_0TargetTest", + name: "VtsHalCasV1_1TargetTest", defaults: ["VtsHalTargetTestDefaults"], - srcs: [ - "VtsHalAudioEffectV2_0TargetTest.cpp", - "ValidateAudioEffectsConfiguration.cpp" - ], + srcs: ["VtsHalCasV1_1TargetTest.cpp"], static_libs: [ - "android.hardware.audio.common.test.utility", - "android.hardware.audio.common@2.0", - "android.hardware.audio.effect@2.0", + "android.hardware.cas@1.0", + "android.hardware.cas@1.1", + "android.hardware.cas.native@1.0", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", - "libeffectsconfig", - "libxml2", + "libhidlallocatorutils", + "libhidlmemory", + ], + shared_libs: [ + "libbinder", ], test_suites: ["general-tests"], } + diff --git a/cas/1.1/vts/functional/OWNERS b/cas/1.1/vts/functional/OWNERS new file mode 100644 index 0000000000..29246edc81 --- /dev/null +++ b/cas/1.1/vts/functional/OWNERS @@ -0,0 +1,3 @@ +nchalko@google.com +chz@google.com +quxiangfang@google.com diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp new file mode 100644 index 0000000000..88f1fb01d6 --- /dev/null +++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp @@ -0,0 +1,571 @@ +/* + * 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 "mediacas_hidl_hal_test" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLEAR_KEY_SYSTEM_ID 0xF6D8 +#define INVALID_SYSTEM_ID 0 +#define WAIT_TIMEOUT 3000000000 + +#define PROVISION_STR \ + "{ " \ + " \"id\": 21140844, " \ + " \"name\": \"Test Title\", " \ + " \"lowercase_organization_name\": \"Android\", " \ + " \"asset_key\": { " \ + " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " \ + " }, " \ + " \"cas_type\": 1, " \ + " \"track_types\": [ ] " \ + "} " + +using android::Condition; +using android::IMemory; +using android::IMemoryHeap; +using android::MemoryDealer; +using android::Mutex; +using android::sp; +using android::hardware::fromHeap; +using android::hardware::hidl_string; +using android::hardware::hidl_vec; +using android::hardware::HidlMemory; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::cas::native::V1_0::BufferType; +using android::hardware::cas::native::V1_0::DestinationBuffer; +using android::hardware::cas::native::V1_0::IDescrambler; +using android::hardware::cas::native::V1_0::ScramblingControl; +using android::hardware::cas::native::V1_0::SharedBuffer; +using android::hardware::cas::native::V1_0::SubSample; +using android::hardware::cas::V1_0::HidlCasPluginDescriptor; +using android::hardware::cas::V1_0::IDescramblerBase; +using android::hardware::cas::V1_0::Status; +using android::hardware::cas::V1_1::ICas; +using android::hardware::cas::V1_1::ICasListener; +using android::hardware::cas::V1_1::IMediaCasService; + +namespace { + +const uint8_t kEcmBinaryBuffer[] = { + 0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00, + 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f, + 0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c, + 0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48, +}; + +const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}}; + +const uint8_t kInBinaryBuffer[] = { + 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, + 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, + 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, + 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, + 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, + 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, + 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, + 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, + 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21, + 0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5, + 0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b, + 0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb, + 0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3, + 0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80, + 0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c, + 0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7, + 0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03, + 0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49, + 0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e, + 0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72, + 0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d, + 0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e, + 0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a, + 0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46, + 0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33, + 0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d, + 0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c, + 0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53, + 0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4, + 0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80, + 0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0, + 0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46, + 0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0, + 0xc5, 0x4c, 0x24, 0x0e, 0x65, +}; + +const uint8_t kOutRefBinaryBuffer[] = { + 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, + 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, + 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, + 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, + 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, + 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, + 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, + 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, + 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, + 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, + 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, + 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, + 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, + 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, + 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, + 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, + 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, + 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, + 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, + 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, + 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, + 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, + 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, + 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, + 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, + 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, + 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, + 0x73, 0x63, 0x65, 0x6e, 0x65, +}; + +class MediaCasListener : public ICasListener { + public: + virtual Return onEvent(int32_t event, int32_t arg, + const hidl_vec& data) override { + android::Mutex::Autolock autoLock(mMsgLock); + mEvent = event; + mEventArg = arg; + mEventData = data; + + mEventReceived = true; + mMsgCondition.signal(); + return Void(); + } + + virtual Return onSessionEvent(const hidl_vec& sessionId, int32_t event, + int32_t arg, const hidl_vec& data) override { + android::Mutex::Autolock autoLock(mMsgLock); + mSessionId = sessionId; + mEvent = event; + mEventArg = arg; + mEventData = data; + + mEventReceived = true; + mMsgCondition.signal(); + return Void(); + } + + void testEventEcho(sp& mediaCas, int32_t& event, int32_t& eventArg, + hidl_vec& eventData); + + void testSessionEventEcho(sp& mediaCas, const hidl_vec& sessionId, + int32_t& event, int32_t& eventArg, hidl_vec& eventData); + + private: + int32_t mEvent = -1; + int32_t mEventArg = -1; + bool mEventReceived = false; + hidl_vec mEventData; + hidl_vec mSessionId; + android::Mutex mMsgLock; + android::Condition mMsgCondition; +}; + +void MediaCasListener::testEventEcho(sp& mediaCas, int32_t& event, int32_t& eventArg, + hidl_vec& eventData) { + mEventReceived = false; + auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "event not received within timeout"; + return; + } + } + + EXPECT_EQ(mEvent, event); + EXPECT_EQ(mEventArg, eventArg); + EXPECT_TRUE(mEventData == eventData); +} + +void MediaCasListener::testSessionEventEcho(sp& mediaCas, const hidl_vec& sessionId, + int32_t& event, int32_t& eventArg, + hidl_vec& eventData) { + mEventReceived = false; + auto returnStatus = mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "event not received within timeout"; + return; + } + } + + EXPECT_TRUE(mSessionId == sessionId); + EXPECT_EQ(mEvent, event); + EXPECT_EQ(mEventArg, eventArg); + EXPECT_TRUE(mEventData == eventData); +} + +// Test environment for Cas HIDL HAL. +class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static CasHidlEnvironment* Instance() { + static CasHidlEnvironment* instance = new CasHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService(); } +}; + +class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + mService = ::testing::VtsHalHidlTargetTestBase::getService( + CasHidlEnvironment::Instance()->getServiceName()); + ASSERT_NE(mService, nullptr); + } + + sp mService; + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mMediaCas; + sp mDescramblerBase; + sp mCasListener; + typedef struct _OobInputTestParams { + const SubSample* subSamples; + uint32_t numSubSamples; + size_t imemSizeActual; + uint64_t imemOffset; + uint64_t imemSize; + uint64_t srcOffset; + uint64_t dstOffset; + } OobInputTestParams; + + ::testing::AssertionResult createCasPlugin(int32_t caSystemId); + ::testing::AssertionResult openCasSession(std::vector* sessionId); + ::testing::AssertionResult descrambleTestInputBuffer(const sp& descrambler, + Status* descrambleStatus, + sp* hidlInMemory); + ::testing::AssertionResult descrambleTestOobInput(const sp& descrambler, + Status* descrambleStatus, + const OobInputTestParams& params); +}; + +::testing::AssertionResult MediaCasHidlTest::createCasPlugin(int32_t caSystemId) { + auto status = mService->isSystemIdSupported(caSystemId); + if (!status.isOk() || !status) { + return ::testing::AssertionFailure(); + } + status = mService->isDescramblerSupported(caSystemId); + if (!status.isOk() || !status) { + return ::testing::AssertionFailure(); + } + + mCasListener = new MediaCasListener(); + auto pluginStatus = mService->createPluginExt(caSystemId, mCasListener); + if (!pluginStatus.isOk()) { + return ::testing::AssertionFailure(); + } + mMediaCas = pluginStatus; + if (mMediaCas == nullptr) { + return ::testing::AssertionFailure(); + } + + auto descramblerStatus = mService->createDescrambler(caSystemId); + if (!descramblerStatus.isOk()) { + return ::testing::AssertionFailure(); + } + mDescramblerBase = descramblerStatus; + return ::testing::AssertionResult(mDescramblerBase != nullptr); +} + +::testing::AssertionResult MediaCasHidlTest::openCasSession(std::vector* sessionId) { + Status sessionStatus; + auto returnVoid = mMediaCas->openSession([&](Status status, const hidl_vec& id) { + sessionStatus = status; + *sessionId = id; + }); + return ::testing::AssertionResult(returnVoid.isOk() && (Status::OK == sessionStatus)); +} + +::testing::AssertionResult MediaCasHidlTest::descrambleTestInputBuffer( + const sp& descrambler, Status* descrambleStatus, sp* inMemory) { + hidl_vec hidlSubSamples; + hidlSubSamples.setToExternal(const_cast(kSubSamples), + (sizeof(kSubSamples) / sizeof(SubSample)), false /*own*/); + + sp dealer = new MemoryDealer(sizeof(kInBinaryBuffer), "vts-cas"); + if (nullptr == dealer.get()) { + ALOGE("couldn't get MemoryDealer!"); + return ::testing::AssertionFailure(); + } + + sp mem = dealer->allocate(sizeof(kInBinaryBuffer)); + if (nullptr == mem.get()) { + ALOGE("couldn't allocate IMemory!"); + return ::testing::AssertionFailure(); + } + *inMemory = mem; + + // build HidlMemory from memory heap + ssize_t offset; + size_t size; + sp heap = mem->getMemory(&offset, &size); + if (nullptr == heap.get()) { + ALOGE("couldn't get memory heap!"); + return ::testing::AssertionFailure(); + } + + uint8_t* ipBuffer = static_cast(static_cast(mem->pointer())); + memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer)); + + // hidlMemory is not to be passed out of scope! + sp hidlMemory = fromHeap(heap); + + SharedBuffer srcBuffer = { + .heapBase = *hidlMemory, .offset = (uint64_t)offset, .size = (uint64_t)size}; + + DestinationBuffer dstBuffer; + dstBuffer.type = BufferType::SHARED_MEMORY; + dstBuffer.nonsecureMemory = srcBuffer; + + uint32_t outBytes; + hidl_string detailedError; + auto returnVoid = descrambler->descramble( + ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, 0, dstBuffer, 0, + [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) { + *descrambleStatus = status; + outBytes = bytesWritten; + detailedError = detailedErr; + }); + if (!returnVoid.isOk() || *descrambleStatus != Status::OK) { + ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s", + returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str()); + } + return ::testing::AssertionResult(returnVoid.isOk()); +} + +::testing::AssertionResult MediaCasHidlTest::descrambleTestOobInput( + const sp& descrambler, Status* descrambleStatus, + const OobInputTestParams& params) { + hidl_vec hidlSubSamples; + hidlSubSamples.setToExternal(const_cast(params.subSamples), params.numSubSamples, + false /*own*/); + + sp dealer = new MemoryDealer(params.imemSizeActual, "vts-cas"); + if (nullptr == dealer.get()) { + ALOGE("couldn't get MemoryDealer!"); + return ::testing::AssertionFailure(); + } + + sp mem = dealer->allocate(params.imemSizeActual); + if (nullptr == mem.get()) { + ALOGE("couldn't allocate IMemory!"); + return ::testing::AssertionFailure(); + } + + // build HidlMemory from memory heap + ssize_t offset; + size_t size; + sp heap = mem->getMemory(&offset, &size); + if (nullptr == heap.get()) { + ALOGE("couldn't get memory heap!"); + return ::testing::AssertionFailure(); + } + + // hidlMemory is not to be passed out of scope! + sp hidlMemory = fromHeap(heap); + + SharedBuffer srcBuffer = { + .heapBase = *hidlMemory, + .offset = (uint64_t)offset + params.imemOffset, + .size = (uint64_t)params.imemSize, + }; + + DestinationBuffer dstBuffer; + dstBuffer.type = BufferType::SHARED_MEMORY; + dstBuffer.nonsecureMemory = srcBuffer; + + uint32_t outBytes; + hidl_string detailedError; + auto returnVoid = descrambler->descramble( + ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, params.srcOffset, + dstBuffer, params.dstOffset, + [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) { + *descrambleStatus = status; + outBytes = bytesWritten; + detailedError = detailedErr; + }); + if (!returnVoid.isOk() || *descrambleStatus != Status::OK) { + ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s", + returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str()); + } + return ::testing::AssertionResult(returnVoid.isOk()); +} + +TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) { + description("Test that valid call sequences with SessionEvent send and receive"); + + ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID)); + + auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR)); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec hidlPvtData; + hidlPvtData.resize(256); + returnStatus = mMediaCas->setPrivateData(hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + std::vector sessionId; + ASSERT_TRUE(openCasSession(&sessionId)); + returnStatus = mMediaCas->setSessionPrivateData(sessionId, hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + std::vector streamSessionId; + ASSERT_TRUE(openCasSession(&streamSessionId)); + returnStatus = mMediaCas->setSessionPrivateData(streamSessionId, hidlPvtData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mDescramblerBase->setMediaCasSession(sessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mDescramblerBase->setMediaCasSession(streamSessionId); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec hidlNullPtr; + hidlNullPtr.setToExternal(static_cast(nullptr), 0); + returnStatus = mMediaCas->refreshEntitlements(3, hidlNullPtr); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + uint8_t refreshData[] = {0, 1, 2, 3}; + hidl_vec hidlRefreshData; + hidlRefreshData.setToExternal(static_cast(refreshData), sizeof(refreshData)); + returnStatus = mMediaCas->refreshEntitlements(10, hidlRefreshData); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + int32_t eventID = 1; + int32_t eventArg = 2; + mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlNullPtr); + mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlNullPtr); + + eventID = 3; + eventArg = 4; + uint8_t eventData[] = {'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'}; + hidl_vec hidlEventData; + hidlEventData.setToExternal(static_cast(eventData), sizeof(eventData)); + mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlEventData); + mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlEventData); + + uint8_t clearKeyEmmData[] = {'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'}; + hidl_vec hidlClearKeyEmm; + hidlClearKeyEmm.setToExternal(static_cast(clearKeyEmmData), sizeof(clearKeyEmmData)); + returnStatus = mMediaCas->processEmm(hidlClearKeyEmm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + hidl_vec hidlEcm; + hidlEcm.setToExternal(const_cast(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer)); + returnStatus = mMediaCas->processEcm(sessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + returnStatus = mMediaCas->processEcm(streamSessionId, hidlEcm); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("video/avc")); + + sp descrambler; + descrambler = IDescrambler::castFrom(mDescramblerBase); + ASSERT_NE(descrambler, nullptr); + + Status descrambleStatus = Status::OK; + sp dataMemory; + + ASSERT_TRUE(descrambleTestInputBuffer(descrambler, &descrambleStatus, &dataMemory)); + EXPECT_EQ(Status::OK, descrambleStatus); + + ASSERT_NE(nullptr, dataMemory.get()); + uint8_t* opBuffer = static_cast(static_cast(dataMemory->pointer())); + + int compareResult = + memcmp(static_cast(opBuffer), + static_cast(kOutRefBinaryBuffer), sizeof(kOutRefBinaryBuffer)); + EXPECT_EQ(0, compareResult); + + returnStatus = mDescramblerBase->release(); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); + + returnStatus = mMediaCas->release(); + EXPECT_TRUE(returnStatus.isOk()); + EXPECT_EQ(Status::OK, returnStatus); +} + +} // anonymous namespace + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + CasHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/compatibility_matrices/compatibility_matrix.3.xml b/compatibility_matrices/compatibility_matrix.3.xml index e13d293b75..9933b337bd 100644 --- a/compatibility_matrices/compatibility_matrix.3.xml +++ b/compatibility_matrices/compatibility_matrix.3.xml @@ -302,7 +302,8 @@ android.hardware.radio - 1.0-2 + + 1.0-3 IRadio slot1 diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml index 3a2fd48a6b..01ec172d89 100644 --- a/compatibility_matrices/compatibility_matrix.4.xml +++ b/compatibility_matrices/compatibility_matrix.4.xml @@ -9,7 +9,7 @@ android.hardware.audio - 4.0 + 5.0 IDevicesFactory default @@ -17,7 +17,7 @@ android.hardware.audio.effect - 4.0 + 5.0 IEffectsFactory default @@ -55,6 +55,14 @@ default + + android.hardware.biometrics.face + 1.0 + + IBiometricsFace + default + + android.hardware.biometrics.fingerprint 2.1 @@ -95,9 +103,17 @@ default + + android.hardware.broadcastradio + 2.0 + + IBroadcastRadio + .* + + android.hardware.camera.provider - 2.4 + 2.4-5 ICameraProvider [^/]+/[0-9]+ @@ -105,13 +121,13 @@ android.hardware.cas - 1.0 + 1.1 IMediaCasService default - + android.hardware.configstore 1.1 @@ -137,19 +153,7 @@ android.hardware.drm - 1.0 - - ICryptoFactory - .* - - - IDrmFactory - .* - - - - android.hardware.drm - 1.1 + 1.0-2 ICryptoFactory .* @@ -177,7 +181,13 @@ android.hardware.gnss - 1.0-1 + + 1.1 + 2.0 IGnss default @@ -186,6 +196,7 @@ android.hardware.graphics.allocator 2.0 + 3.0 IAllocator default @@ -193,7 +204,7 @@ android.hardware.graphics.composer - 2.1 + 2.1-3 IComposer default @@ -201,7 +212,8 @@ android.hardware.graphics.mapper - 2.0 + 2.1 + 3.0 IMapper default @@ -216,16 +228,28 @@ - android.hardware.health.filesystem + android.hardware.health.storage 1.0 - IFileSystem + IStorage default android.hardware.ir 1.0 + + IConsumerIr + default + + + + android.hardware.input.classifier + 1.0 + + IInputClassifier + default + android.hardware.keymaster @@ -252,7 +276,16 @@ default - + + android.hardware.media.c2 + 1.0 + + IComponentStore + default[0-9]* + vendor[0-9]*_software + + + android.hardware.media.omx 1.0 @@ -314,14 +347,17 @@ android.hardware.radio - - 1.3-4 + 1.4 IRadio slot1 slot2 slot3 + + + android.hardware.radio + 1.2 ISap slot1 @@ -329,7 +365,13 @@ android.hardware.radio.config - 1.2 + + 1.1 IRadioConfig default @@ -355,6 +397,7 @@ android.hardware.sensors 1.0 + 2.0 ISensors default @@ -362,7 +405,7 @@ android.hardware.soundtrigger - 2.0-1 + 2.0-2 ISoundTriggerHw default @@ -387,6 +430,7 @@ android.hardware.thermal 1.0-1 + 2.0 IThermal default @@ -410,7 +454,7 @@ android.hardware.usb - 1.0-1 + 1.0-2 IUsb default @@ -426,7 +470,7 @@ android.hardware.vibrator - 1.0-2 + 1.0-3 IVibrator default @@ -450,7 +494,7 @@ android.hardware.wifi - 1.0-2 + 1.0-3 IWifi default @@ -458,23 +502,15 @@ android.hardware.wifi.hostapd - 1.0 + 1.0-1 IHostapd default - - android.hardware.wifi.offload - 1.0 - - IOffload - default - - android.hardware.wifi.supplicant - 1.0-1 + 1.0-2 ISupplicant default diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index c3f1870959..2284723f0a 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -9,7 +9,7 @@ android.hardware.audio - 4.0 + 5.0 IDevicesFactory default @@ -17,7 +17,7 @@ android.hardware.audio.effect - 4.0 + 5.0 IEffectsFactory default @@ -55,6 +55,14 @@ default + + android.hardware.biometrics.face + 1.0 + + IBiometricsFace + default + + android.hardware.biometrics.fingerprint 2.1 @@ -95,9 +103,17 @@ default + + android.hardware.broadcastradio + 2.0 + + IBroadcastRadio + .* + + android.hardware.camera.provider - 2.4 + 2.4-5 ICameraProvider [^/]+/[0-9]+ @@ -105,13 +121,13 @@ android.hardware.cas - 1.0 + 1.1 IMediaCasService default - + android.hardware.configstore 1.1 @@ -137,19 +153,7 @@ android.hardware.drm - 1.0 - - ICryptoFactory - .* - - - IDrmFactory - .* - - - - android.hardware.drm - 1.1 + 1.0-2 ICryptoFactory .* @@ -177,7 +181,13 @@ android.hardware.gnss - 1.0-1 + + 1.1 + 2.0 IGnss default @@ -186,6 +196,7 @@ android.hardware.graphics.allocator 2.0 + 3.0 IAllocator default @@ -193,7 +204,7 @@ android.hardware.graphics.composer - 2.1 + 2.1-3 IComposer default @@ -201,7 +212,8 @@ android.hardware.graphics.mapper - 2.0 + 2.1 + 3.0 IMapper default @@ -216,16 +228,28 @@ - android.hardware.health.filesystem + android.hardware.health.storage 1.0 - IFileSystem + IStorage default android.hardware.ir 1.0 + + IConsumerIr + default + + + + android.hardware.input.classifier + 1.0 + + IInputClassifier + default + android.hardware.keymaster @@ -252,7 +276,16 @@ default - + + android.hardware.media.c2 + 1.0 + + IComponentStore + default[0-9]* + vendor[0-9]*_software + + + android.hardware.media.omx 1.0 @@ -282,7 +315,7 @@ android.hardware.nfc - 1.1 + 1.2 INfc default @@ -314,14 +347,17 @@ android.hardware.radio - - 1.3-4 + 1.4 IRadio slot1 slot2 slot3 + + + android.hardware.radio + 1.2 ISap slot1 @@ -355,6 +391,7 @@ android.hardware.sensors 1.0 + 2.0 ISensors default @@ -362,7 +399,7 @@ android.hardware.soundtrigger - 2.0-1 + 2.0-2 ISoundTriggerHw default @@ -387,6 +424,7 @@ android.hardware.thermal 1.0-1 + 2.0 IThermal default @@ -410,7 +448,7 @@ android.hardware.usb - 1.0-1 + 1.0-2 IUsb default @@ -426,7 +464,7 @@ android.hardware.vibrator - 1.0-2 + 1.0-3 IVibrator default @@ -450,7 +488,7 @@ android.hardware.wifi - 1.0-2 + 1.0-3 IWifi default @@ -458,23 +496,15 @@ android.hardware.wifi.hostapd - 1.0 + 1.0-1 IHostapd default - - android.hardware.wifi.offload - 1.0 - - IOffload - default - - android.hardware.wifi.supplicant - 1.0-1 + 1.0-2 ISupplicant default 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 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/Android.mk b/configstore/1.1/default/Android.mk index 40f621b3ad..104e15eee2 100644 --- a/configstore/1.1/default/Android.mk +++ b/configstore/1.1/default/Android.mk @@ -7,7 +7,7 @@ LOCAL_MODULE := android.hardware.configstore@1.1-service ifneq ($(NATIVE_COVERAGE),true) LOCAL_REQUIRED_MODULES_arm64 := configstore@1.1.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 diff --git a/configstore/1.1/default/SurfaceFlingerConfigs.cpp b/configstore/1.1/default/SurfaceFlingerConfigs.cpp index da3081c12f..377e467864 100644 --- a/configstore/1.1/default/SurfaceFlingerConfigs.cpp +++ b/configstore/1.1/default/SurfaceFlingerConfigs.cpp @@ -25,8 +25,7 @@ namespace configstore { namespace V1_1 { namespace implementation { -// Methods from ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs -// follow. +// ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs implementation. Return SurfaceFlingerConfigs::vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) { #ifdef VSYNC_EVENT_PHASE_OFFSET_NS _hidl_cb({true, VSYNC_EVENT_PHASE_OFFSET_NS}); @@ -55,7 +54,7 @@ Return SurfaceFlingerConfigs::useContextPriority(useContextPriority_cb _hi } Return SurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers( - maxFrameBufferAcquiredBuffers_cb _hidl_cb) { + maxFrameBufferAcquiredBuffers_cb _hidl_cb) { #ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS _hidl_cb({true, NUM_FRAMEBUFFER_SURFACE_BUFFERS}); #else @@ -92,7 +91,7 @@ Return SurfaceFlingerConfigs::hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) { } Return SurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs( - presentTimeOffsetFromVSyncNs_cb _hidl_cb) { + presentTimeOffsetFromVSyncNs_cb _hidl_cb) { #ifdef PRESENT_TIME_OFFSET_FROM_VSYNC_NS _hidl_cb({true, PRESENT_TIME_OFFSET_FROM_VSYNC_NS}); #else @@ -133,7 +132,7 @@ Return SurfaceFlingerConfigs::useVrFlinger(useVrFlinger_cb _hidl_cb) { } Return SurfaceFlingerConfigs::startGraphicsAllocatorService( - startGraphicsAllocatorService_cb _hidl_cb) { + startGraphicsAllocatorService_cb _hidl_cb) { bool value = false; #ifdef START_GRAPHICS_ALLOCATOR_SERVICE value = true; @@ -142,17 +141,16 @@ Return 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 || - PRIMARY_DISPLAY_ORIENTATION == 180 || PRIMARY_DISPLAY_ORIENTATION == 270, + PRIMARY_DISPLAY_ORIENTATION == 180 || PRIMARY_DISPLAY_ORIENTATION == 270, "Primary display orientation must be 0/90/180/270"); #endif Return SurfaceFlingerConfigs::primaryDisplayOrientation( - primaryDisplayOrientation_cb _hidl_cb) { + primaryDisplayOrientation_cb _hidl_cb) { using ::android::hardware::configstore::V1_1::DisplayOrientation; bool specified = false; @@ -191,8 +189,6 @@ Return SurfaceFlingerConfigs::primaryDisplayOrientation( return Void(); } -// Methods from ::android::hidl::base::V1_0::IBase follow. - } // namespace implementation } // namespace V1_1 } // namespace configstore diff --git a/configstore/1.1/default/SurfaceFlingerConfigs.h b/configstore/1.1/default/SurfaceFlingerConfigs.h index 3714e81697..c2f5fef056 100644 --- a/configstore/1.1/default/SurfaceFlingerConfigs.h +++ b/configstore/1.1/default/SurfaceFlingerConfigs.h @@ -1,3 +1,19 @@ +/* + * 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. + */ + #ifndef ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H #define ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H @@ -11,14 +27,13 @@ namespace configstore { namespace V1_1 { 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_1::ISurfaceFlingerConfigs; struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs { - // Methods from - // ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs follow. + // ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs implementation. Return vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override; Return vsyncSfEventPhaseOffsetNs(vsyncSfEventPhaseOffsetNs_cb _hidl_cb) override; Return useContextPriority(useContextPriority_cb _hidl_cb) override; @@ -32,11 +47,8 @@ struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs { Return maxFrameBufferAcquiredBuffers(maxFrameBufferAcquiredBuffers_cb _hidl_cb) override; Return startGraphicsAllocatorService(startGraphicsAllocatorService_cb _hidl_cb) override; - // Methods from - // ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs follow. + // ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs follow implementation. Return primaryDisplayOrientation(primaryDisplayOrientation_cb _hidl_cb) override; - - // Methods from ::android::hidl::base::V1_0::IBase follow. }; } // namespace implementation diff --git a/configstore/1.1/default/service.cpp b/configstore/1.1/default/service.cpp index 3b4e7745ee..e21de0bdce 100644 --- a/configstore/1.1/default/service.cpp +++ b/configstore/1.1/default/service.cpp @@ -22,14 +22,14 @@ #include "SurfaceFlingerConfigs.h" -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::OK; using android::sp; using android::status_t; -using android::OK; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::SetupMinijail; +using android::hardware::configstore::V1_1::ISurfaceFlingerConfigs; +using android::hardware::configstore::V1_1::implementation::SurfaceFlingerConfigs; int main() { configureRpcThreadpool(10, true); 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 ce3d7b5deb..eb1b1ca2ce 100644 --- a/current.txt +++ b/current.txt @@ -386,16 +386,21 @@ cd4330c3196bda1d642a32abfe23a7d64ebfbda721940643af6867af3b3f0aa9 android.hardwar # ABI preserving changes to HALs during Android Q 2a55e224aa9bc62c0387cd85ad3c97e33f0c33a4e1489cbae86b2523e6f9df35 android.hardware.camera.device@3.2::ICameraDevice +17e878cb11ea602c08af04a09182e6265498be16edf26605058383b9a7628261 android.hardware.camera.device@3.2::ICameraDeviceCallback 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 -f4aca082ad436f00b3bed8b9b9dfdc01f6460afdbee7ca10fedb5e34bddcc96f android.hardware.camera.metadata@3.3::types +23780340c686ee86986aa5a9755c2d8566224fed177bbb22a5ebf06be574b60c android.hardware.camera.metadata@3.3::types +05d1ee760d81cdd2dc7a70ce0241af9fa830edae33b4be83d9bf5fffe05ddc6f android.hardware.camera.provider@2.4::ICameraProvider da33234403ff5d60f3473711917b9948e6484a4260b5247acdafb111193a9de2 android.hardware.configstore@1.0::ISurfaceFlingerConfigs +ede69710c3a95c2cbe818e6c8bb72c7816823face5fc21c17731b26f41d94d65 android.hardware.gnss@1.0::IGnss 21165b8e30c4b2d52980e4728f661420adc16e38bbe73476c06b2085be908f4c android.hardware.gnss@1.0::IGnssCallback d702fb01dc2a0733aa820b7eb65435ee3334f75632ef880bafd2fb8803a20a58 android.hardware.gnss@1.0::IGnssMeasurementCallback +b5f1f4c1bd6de71a8e71d70f57cdab904ac024a12f3dee3e2173770a4583bcc2 android.hardware.gnss@1.1::IGnss 7c7721c0f773fcf422b71a4f558545e9e36acc973e58ca51e5bd53905cf46bc0 android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer d4fea995378bb4f421b4e24ccf68cad2734ab07fe4f874a126ba558b99df5766 android.hardware.graphics.composer@2.1::IComposerClient +f7d7cb747dc01a9fdb2d39a80003b4d8df9be733d65f5842198802eb6209db69 android.hardware.graphics.mapper@2.0::IMapper 65a021fa89085b62fc96b2b6d3bef2f9103cf4d63379c68bc154fd9eef672852 android.hardware.health@1.0::types b7ecf29927055ec422ec44bf776223f07d79ad9f92ccf9becf167e62c2607e7a android.hardware.keymaster@4.0::IKeymasterDevice 574e8f1499436fb4075894dcae0b36682427956ecb114f17f1fe22d116a83c6b android.hardware.neuralnetworks@1.0::IPreparedModel @@ -407,6 +412,8 @@ ed9da80ec0c96991fd03f0a46107815d0e50f764656e49dba4980fa5c31d5bc3 android.hardwar cd1757867a5e3a3faa362e785239515870d1a3c9ce756c6f0cf0f0fd8aac2547 android.hardware.radio@1.2::types 722b3595548ed7f1953b6e0143dc842d4d6e290ff009a134eb518d7c17a09347 android.hardware.radio@1.2::types # b/112486807 e78cf871f9fd1c072874e481e06e18e2681763cf2aa38c1fd777d53bab4eb69b android.hardware.sensors@1.0::types +c28859a334c1f540dea0a7d4f0baef0551ba76a3232f53c936196543ee35bc4d android.hardware.sensors@1.0::types # b/133264933 +3d01e29e8129186f7567c4f9c8bee7480a0768e587b1be9b28adb0a6cbec6bf2 android.hardware.tv.cec@1.0::types 1722ad002317b1fae1400de709e90f442d94ef22864e05f7a12af48c32e8edc8 android.hardware.usb@1.1::types 29c8da7a13c40d488f569c812441d5754ee45bdcdb8ce6564f524b708d10a057 android.hardware.vibrator@1.1::types @@ -417,11 +424,12 @@ dfdb4d04b65dc363e5621c85bfdf3023c277b75c31d821d8e71b3f44f198e214 android.hardwar 0a911297821854985cfcdb17b63d7948af0f0f51ce8c68cc86367c185bbc772e android.hardware.audio@5.0::IDevicesFactory ce2e8c6c8559fd42bd69e0dee27b4d9c93cd9b2eff487b4e6b6395b6a1a993d6 android.hardware.audio@5.0::IPrimaryDevice 4a4e5e5d9357004a1256bde8d36010ee00c51cea811a1c1e0dd969a9fc0bf862 android.hardware.audio@5.0::IStream -e05e48c583de14c1e5a6fa9d48ea50244e3e0924b76b342374e7471dc8007ba9 android.hardware.audio@5.0::IStreamIn +b9d41ff4031266de1ecef394a8a64de7d857634dd08dc6be855fca2fe3075975 android.hardware.audio@5.0::IStreamIn 9471b12b1c255bb530695720bc4174bd74987b75b1f820854af8944bc8c215c9 android.hardware.audio@5.0::IStreamOut 1b0500367ed2b32a841667ac3200edf3d3a164e8004aca445ff1b085ac831e93 android.hardware.audio@5.0::IStreamOutCallback 83e365479cc77d8717c155e1787ee668cd2ae4c557b467cf75b8e7cd53697ad8 android.hardware.audio@5.0::types -894af04bebfe7da5b6791eefeb6eb3627da63d5efea735f16876d11d8ca4f61d android.hardware.audio.common@5.0::types +07d17800b298331e90d4ea5d8ba19a1ae3fe9c1dbff08d9f75fd3ade09496d67 android.hardware.audio.common@5.0::types +b3c1ec989f317b9a36eac10f4e7b66aad2997302156899481553a67476e148dd android.hardware.audio.common@5.0::types # b/133453897 f269297866765b95ddd1825676cc8a772f0c7c9863286df596fc302781a42ff5 android.hardware.audio.effect@5.0::IAcousticEchoCancelerEffect fa187b602d8939644ef708ed7627f2e3deac97899a4bda1de07f2ff126abe243 android.hardware.audio.effect@5.0::IAutomaticGainControlEffect e1bf864ccb8458c0da1dcc74a2e748b1dca8ac360df590591cf82d98292d7981 android.hardware.audio.effect@5.0::IBassBoostEffect @@ -437,15 +445,77 @@ ca15a738dedc2f4981925f7d7ff29c22bc3f8a848403dcf0c592c167de09d9af android.hardwar 443659bb9e27221e5da0d16c7a0ecb2dc3a9a03acc8a0b2196b47c50735e2d2e android.hardware.audio.effect@5.0::IVirtualizerEffect 78fed26a781cdca1b3bcb37520bff705d7764ee81db9cfd37014953c7ad2596e android.hardware.audio.effect@5.0::IVisualizerEffect 6385b6accab8a544e2ee54ba7bf5aa55dff6153bcedd80fdaae16fe9e0be7050 android.hardware.audio.effect@5.0::types +e18ff318f3fc43db37f554696dc4e551abb9b119bde53950f73e28ce33a97a40 android.hardware.biometrics.face@1.0::IBiometricsFace +b6e55d7795bbafd011fb95a3b6d3954bf66c349e14cf107f3b72032ce3ceb448 android.hardware.biometrics.face@1.0::IBiometricsFaceClientCallback +95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types ecedc58dbcdb13503c19c0ab160ac1dd0530bb1471164149282dd1463c684185 android.hardware.bluetooth.audio@2.0::IBluetoothAudioPort fb9c40e4deab40be5476477078fe3d8a4a4495fd9deef4321878d169d675c633 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvider f7431f3e3e4e3387fc6f27a6cf423eddcd824a395dc4349d302c995ab44a9895 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory 447a5c9bb0f1a5ed3f1dfe5216afe4be2f4362111d95479670eec4cae4d7d5f7 android.hardware.bluetooth.audio@2.0::types +09ab9b24994429d9bb32a3fb420b6f6be3e47eb655139a2c08c4e80d3f33ff95 android.hardware.camera.device@3.5::ICameraDevice +06237de53c42890029e3f8fe7d1480d078469c0d07608e51c37b4d485d342992 android.hardware.camera.device@3.5::ICameraDeviceCallback +08c68b196e2fc4e5ba67ba0d0917bde828a87cbe2cffec19d04733972da9eb49 android.hardware.camera.device@3.5::ICameraDeviceSession +feabf0b7caa947757bf74375aceb4919a5aa99dd6a36216843553b6adec7eb5d android.hardware.camera.device@3.5::ICameraDeviceSession # b/131864007 +f9b8b388c0c76669e4b9189e4943efd2982f9bda5c10e276f96cc91bc8e818d6 android.hardware.camera.device@3.5::types +f727d5f350f55a6d3354aad2feb64e43200de77c10d9d642465566bc260bb8ec android.hardware.camera.metadata@3.4::types +0fb39a7809ad1c52b3efbbed5ef4749b06c2a4f1f19cdc3efa2e3d9b28f1205c android.hardware.camera.provider@2.5::ICameraProvider +f5777403d65135a5407723671bc7a864cdca83aea13ee3ce2894b95e6588ca3a android.hardware.camera.provider@2.5::types +44c88954b3c201b26f64fcdb6f278024ab3aae864a9e1ec70e8a74274ae9d6aa android.hardware.cas@1.1::ICas +25012d1778f7396f967bbc0231397d544bde421ba5b98706c9e48ac790612683 android.hardware.cas@1.1::ICasListener +dffacdbe0bcf8443013de5bdc56a83479ad979d4919ed15a5585539f46091f07 android.hardware.cas@1.1::IMediaCasService +5b1f4a4fb88c239e07d76026467a1f2ee0d08f4d52c1805bd93bd7c05e3fe69c android.hardware.drm@1.2::ICryptoFactory +4895f98e9ef210e9acb01982f5d07b654538377e1404b8db5e19e7858835e9d8 android.hardware.drm@1.2::ICryptoPlugin +976116b9033b2c222b940109fdf0ffcc29b77cbe631ef6b4fcc2ad5ce8e605f7 android.hardware.drm@1.2::IDrmFactory +8ef1caf921c3e83a00180f770e3b8e8ff65d8a5c806482e51aa45e6d55f1aec1 android.hardware.drm@1.2::IDrmPlugin +b778fcce93eb6294446a940e1bae0200da7bd97b91b91977be2dcd31ca58374f android.hardware.drm@1.2::IDrmPluginListener +564732cbfe5c0895cfbd2bdf84c3f2b0f760ea20f2237c0d388aaeeaef2dd0a9 android.hardware.drm@1.2::types 44480c912e4ab90b9ed17e56569cd5ca98413a8a2372efb028f4181204b6b73e android.hardware.fastboot@1.0::IFastboot 7b2989744e3c555292d4b5b829acd09a7b40f96ead62ce54174cd959503b64bb android.hardware.fastboot@1.0::types +7f460e795f5d1ed5e378935f98c6db4d39497de988aef1b4c2a4a07a6c400392 android.hardware.gnss@2.0::IAGnss +2e5ad983734069e84a760004b32da0d09e4170c05380abe27e6eb80e4aa70d5a android.hardware.gnss@2.0::IAGnssCallback +1f4ac068a88a72360280d94a7f6fd7c63813c1eea4891a0eb01394d3e7e775f2 android.hardware.gnss@2.0::IAGnssRil +f5605f48c2fb9f231615dd932bf730ae9540f4f98b5b7ae2b269975f452f6d73 android.hardware.gnss@2.0::IGnss +db6bdf6dfc5edf6c85d2944976db899227abb51079c893874353c322342c50b6 android.hardware.gnss@2.0::IGnssBatching +1f89392f1ebb693d8fa6f50324b1635fc79fab246d31900e63998e1b0e17511c android.hardware.gnss@2.0::IGnssBatchingCallback +64232037109a5e5f53ab0377e755ec494ae93fcb5279e6eea71dec2e7ac6fbfc android.hardware.gnss@2.0::IGnssCallback +ecc966c68bddbd95c8dae782b84204cf01c75734675e8769963f3b5106ec128b android.hardware.gnss@2.0::IGnssConfiguration +b670bae2ab8517336290532e364502b4db9120340d75474ccc8442b1b15d6ab7 android.hardware.gnss@2.0::IGnssDebug +c67759f5d6387d273b66729180d03690e827f0b6b8d4e13ce2ff42d31b224065 android.hardware.gnss@2.0::IGnssMeasurement +15e09903748857f4beb5f485784606931fa5a6277cd070baa6d584df485b7948 android.hardware.gnss@2.0::IGnssMeasurementCallback +a49c973f21ddf41bc402de55d7c8dffacf4dce06b0bbca4f5ffd3b09a471317e android.hardware.gnss@2.0::types +d4cc8d91930d5a1a62deb0d97d398510a115ce3ede2d2978738651b9d01b11c3 android.hardware.gnss.measurement_corrections@1.0::IMeasurementCorrections +3eec9763db9b101644f14175b77c9954047445a468e9c743fd402d472d4aa97e android.hardware.gnss.measurement_corrections@1.0::IMeasurementCorrectionsCallback +6ef12cd95df73f8f80c25eb035d98ca4594f9cee571fdabea838a0b6016dd908 android.hardware.gnss.measurement_corrections@1.0::types +0d278956d7fc6fdf9ca9c42962ff2d73967bbb1c9f0b3e0b58d71b7095c286bc android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControl +0d99e34500cfc2d40b684cb4dea7ebd89d4aff9f5315ed36b33442a7a88c138c android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControlCallback +6b2d8dfa3db505c34a3a19082d8737c86bd859ec00f0e6c5fd19cce3c1ef95d1 android.hardware.graphics.allocator@3.0::IAllocator +eb3bcf4e8afacc72fd09821920f277fbbe8b9837513c1f5549fb42588580cbe4 android.hardware.graphics.bufferqueue@2.0::IGraphicBufferProducer +b826892686850a9cf2b60ca5845db7185c2196ea4dd765cd80cd163169678a78 android.hardware.graphics.bufferqueue@2.0::IProducerListener +01c6398c90fc6be0640810e2c5d8a4863b457280132bb3f97dd5682e19632b62 android.hardware.graphics.bufferqueue@2.0::types +7a2d64095252f85781b2d521f4f11d04ce774544feececcec2088c568656e93c android.hardware.graphics.common@1.2::types +3dff04a36b86660b5807414587e530bb0c294ed56fdff06f8915ba0a9b73f974 android.hardware.graphics.composer@2.3::IComposer +b2b0ef3e6f5e9bb4aa6e978bc62e017b3fd64dba95a2152e8b07e3b7c4581d4f android.hardware.graphics.composer@2.3::IComposerClient +033e096cb65e5093ee1d0e473892b9a487911d4611dbb65ebecb5cef18338923 android.hardware.graphics.mapper@3.0::IMapper +7183d9d9acfa41a61a64bdfed548e98299265a7bb1821a3ed204173b5c2cfd4a android.hardware.graphics.mapper@3.0::types c3f831a66d5815baf74f5b82fe79cf099542ddae4dfab3f388e1d41828e794fc android.hardware.health.storage@1.0::IGarbageCollectCallback dd1ec219f5d2e2b33c6c0bcb92e63bbedb36f7c716413462848f6b6ae74fc864 android.hardware.health.storage@1.0::IStorage 2b4a14661e6a38617b7dd0c6ebb66a56a90e564674ac7697a14cb8a0cab92b2f android.hardware.health.storage@1.0::types +30006fde4cb1f255f2530208728bff692100411b20af5b66fa31a9196d51f00b android.hardware.input.classifier@1.0::IInputClassifier +0300c7667030da36c3de585f176ce18ff4b0d2615446d4930f331097378c06ef android.hardware.input.common@1.0::types +24ae089981d58bc4cc74d75a6055bf357338ae6744ce1b467c5b4a9c470aba6d android.hardware.media.bufferpool@2.0::IAccessor +897f45ee7db24ef227dea83ca3e4de72d53ff6bb7adc7983c90a650a1a6ff576 android.hardware.media.bufferpool@2.0::IClientManager +aee53b2865b4f7939fb3df6fae758d9750c14f93dd454b479fc74aa7978fda4f android.hardware.media.bufferpool@2.0::IConnection +0bf3758eeeb05767830ea87041214be80968c4679fb73577ac5b3091841ee71f android.hardware.media.bufferpool@2.0::IObserver +82255e252ae215382473ad2e5ac7a2814a439a24f0092551aad7a2f89c6e9546 android.hardware.media.bufferpool@2.0::types +7faa207e2507c6a2617e5ec2554b83383ebe392b6e627dddf2e3b0eae5715ba8 android.hardware.media.c2@1.0::IComponent +389d06e4a4ecf60f828a260045b0c327a5ae883ee0856a3c054556dd22b1f450 android.hardware.media.c2@1.0::IComponentInterface +5ee0c02265c5505ade189796bef46697df4e0563e3544bb0c934855b34694b07 android.hardware.media.c2@1.0::IComponentListener +43d70bcdc63b3d042bac3c3297f5d941dfabbd08f3ceb96b6016cc14f6e34ba3 android.hardware.media.c2@1.0::IComponentStore +d36f747f9c9a8f2f21db2f8323c2d755dd08b34ce813932d7339979f7d490dab android.hardware.media.c2@1.0::IConfigurable +21aa259585caaa27b6470ebcd8509aabde0ef5d039160aa6425d589cb787488b android.hardware.media.c2@1.0::IInputSink +b9422a9aca84df1ff9623dc12c0562abce97716e28d63a965f2bfb88f9ad9607 android.hardware.media.c2@1.0::IInputSurface +0a786a19e6753f9774a7ca7781c2a2edfe5c0b5fa112355dfa0e50ebedeb08b9 android.hardware.media.c2@1.0::IInputSurfaceConnection +7d3c292ca75ec3e22a8fd4ae72d2edb0659d280257e763786e766f3429954dd1 android.hardware.media.c2@1.0::types 5f6b6b99ffd0d51a5713174a3030a2a69273bcd476fc1b5ce814491437685857 android.hardware.neuralnetworks@1.2::IBurstCallback 19877e466ad8c6ed42b38050b77bd010cf7800ff365fdc8574f45bbfda03a758 android.hardware.neuralnetworks@1.2::IBurstContext b83317b66721241887d2770b5ae95fd5af1e77c5daa7530ecb08fae8892f2b43 android.hardware.neuralnetworks@1.2::IDevice @@ -475,6 +545,31 @@ d8e7717e8187dd7453d4142f8f331e7c325e7a6f9e8d44ac0d52b3be502bfe83 android.hardwar 93b8102078e25057ae347ac9704e87529eb26121c2a1b419b362dd36eccefc4d android.hardware.radio.config@1.2::types 08d439c463e4044fa78874037d8e8379aa3cabecde32f08a775897eea5a538af android.hardware.secure_element@1.1::ISecureElement b53ac9d61c24efb16a2d63a861cef20680f6d57adb244a03b9778c675550628b android.hardware.secure_element@1.1::ISecureElementHalCallback +3702b1c52c0bb3427244618e9e7975c05228bf4ceb8720da7a93603a71cb0368 android.hardware.sensors@2.0::ISensors +c36670945ea09d92ae90a557147352ed9bd5223f957d347b367c2acb6f94870f android.hardware.sensors@2.0::ISensors # b/135216821 +ae5faa38538a9f50eb71eb7f9b998271124d2c64b761cb11c4d820c7732b4ddc android.hardware.sensors@2.0::ISensorsCallback +3a98242a57d0820dacaca0f7db52bec433eae1f21c498763c6f1ece611c3967b android.hardware.sensors@2.0::types +ce4b98211959449361146d4b1e5554dc841ceb4d4577154d7b2fb6d1eb504f76 android.hardware.soundtrigger@2.2::ISoundTriggerHw +bd88b48639cae30982021024e22371076c76faa8466e38ca598529452b618eae android.hardware.thermal@2.0::IThermal +cc4d2ef36da776c475ad054f0f3416d8a8865def9d9e2129f10074b28e36d203 android.hardware.thermal@2.0::IThermalChangedCallback +b47f90302595874dfddb19bd05a054727bf18b3a930bc810ea14957b859ae8bf android.hardware.thermal@2.0::types +61bc302e7c974c59b25898c585c6e9685e8a81021b1bed3eedf5224198f2785a android.hardware.usb@1.2::IUsb +46996cd2a1c66261a75a1f6ecada77eeb5861eb264fa39b996548fe0a7f22dd3 android.hardware.usb@1.2::IUsbCallback +3bbaa8cbc5d6b1da21f5509b2b641e05fc7eeca1354751eb1bb3cf37f89aa32f android.hardware.usb@1.2::types +0f7ff73793548d5154014059b7e0fe9ef6355d32218ace157954d02055f5248b android.hardware.vibrator@1.3::IVibrator +2e313dc27a1327a29862ab3e085917f75c9e996f7c8df5a0ce37b9a0ed076b80 android.hardware.vibrator@1.3::types +f19832856a3f53ced5ef91d3cc630a57fb7f4d4ce15f364dbed09099b89f6830 android.hardware.wifi@1.3::IWifi +64be084b6e1ef330b75fa916593dc0b94b0ec7a16d5cfaa5a31e6c9143c8288d android.hardware.wifi@1.3::IWifiChip +3bef30e8b61ab050c0f6fd26572712be5ebb7707d624c9aa6c74bbb9d6a5b4a9 android.hardware.wifi@1.3::IWifiStaIface +f3dbd8dd0d6333c005610288a4785d0ef79a72a7bbe6d0a46d46fa89fc886f1e android.hardware.wifi@1.3::types +2fae61e962f68091335f7ff4581fcfe2e28ce7f6132d7a712fa13d7965543e4d android.hardware.wifi.hostapd@1.1::IHostapd +913e66d8790c4e494950f1cbc259173b45d9e7bf9f1e8fc0c6a3623128290f4d android.hardware.wifi.hostapd@1.1::IHostapdCallback +067b22efc50529a88d650fe7400603429d1164a47ee96a17476fdb0aadd6b4d3 android.hardware.wifi.supplicant@1.2::ISupplicant +120211371fdd29fb134837071d432a302d7b60e9b95af611dd8dde86bd1f77ee android.hardware.wifi.supplicant@1.2::ISupplicantP2pIface +7efe2b057e9f9387b3500e67af97942aa7c8008e6ee7d8dcaae4107fda84016b android.hardware.wifi.supplicant@1.2::ISupplicantStaIface +09e08b5d12b109562ecdd8882532fd1f2c4639588e07769d5c7396b7c5b9f34f android.hardware.wifi.supplicant@1.2::ISupplicantStaIfaceCallback +efbb061c969fa9553d243da6ee23b83fe5d4aa663a7b8896adc52e2b015bc2f3 android.hardware.wifi.supplicant@1.2::ISupplicantStaNetwork +cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardware.wifi.supplicant@1.2::types # ABI preserving changes to HALs during Android R b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice 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 \ +include $(BUILD_EXECUTABLE) -LOCAL_STATIC_LIBRARIES := \ - android.hardware.drm@1.0-helper \ +############# Build legacy drm lazy service ############ -LOCAL_C_INCLUDES := \ - hardware/interfaces/drm +include $(CLEAR_VARS) -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 +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 CryptoPlugin::setSharedBufferBase(const hidl_memory& base, uint32_t bufferId) { sp 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(); + android::status_t status = registerPassthroughServiceImplementation(); 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 +#include + +#include + +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(); + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering drm service: %d", status); + status = registerLazyPassthroughServiceImplementation(); + 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..9104aa9ce8 --- /dev/null +++ b/drm/1.2/Android.bp @@ -0,0 +1,23 @@ +// 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", + ], + gen_java: false, +} diff --git a/audio/effect/4.0/default/AcousticEchoCancelerEffect.h b/drm/1.2/ICryptoFactory.hal similarity index 51% rename from audio/effect/4.0/default/AcousticEchoCancelerEffect.h rename to 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 - -#include "Effect.h" - -#define AUDIO_HAL_VERSION V4_0 -#include -#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 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..df09ccf910 --- /dev/null +++ b/drm/1.2/IDrmPlugin.hal @@ -0,0 +1,247 @@ +/** + * 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. + *

+ * 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 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. + *

+ * 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 removed. + */ + 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 scope, vec initData, + string mimeType, KeyType keyType, KeyedVector optionalParameters) + generates (Status status, vec 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 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); + + /** + * Send a keys change event to the listener. The keys change event + * indicates the status of each key in the session. Keys can be + * indicated as being usable, expired, outputnotallowed or statuspending. + * + * This method only differs from @1.0 version by the addition of new + * KeyStatusType(s) in keyStatusList. + * + * @param sessionId identifies the session the event originated from + * @param keyStatusList indicates the status for each key ID in the + * session. + * @param hasNewUsableKey indicates if the event includes at least one + * key that has become usable. + */ + sendKeysChange_1_2(SessionId sessionId, vec keyStatusList, + bool hasNewUsableKey); + +}; diff --git a/drm/1.2/IDrmPluginListener.hal b/drm/1.2/IDrmPluginListener.hal new file mode 100644 index 0000000000..e8cb91a9c7 --- /dev/null +++ b/drm/1.2/IDrmPluginListener.hal @@ -0,0 +1,57 @@ +/* + * 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); + + /** + * Send a keys change event to the listener. The keys change event + * indicates the status of each key in the session. Keys can be + * indicated as being usable, expired, outputnotallowed or statuspending. + * + * This method only differs from @1.0 version by the addition of new + * KeyStatusType(s) in keyStatusList. + * + * @param sessionId identifies the session the event originated from + * @param keyStatusList indicates the status for each key ID in the + * session. + * @param hasNewUsableKey indicates if the event includes at least one + * key that has become usable. + */ + oneway sendKeysChange_1_2(SessionId sessionId, vec keyStatusList, + bool hasNewUsableKey); + +}; diff --git a/drm/1.2/types.hal b/drm/1.2/types.hal new file mode 100644 index 0000000000..87218a4209 --- /dev/null +++ b/drm/1.2/types.hal @@ -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. + */ + +package android.hardware.drm@1.2; + +import @1.0::KeyStatusType; +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 KeySetId; + +enum KeyStatusType : @1.0::KeyStatusType { + /** + * The key is not yet usable to decrypt media because the start + * time is in the future. The key must become usable when + * its start time is reached. + */ + USABLEINFUTURE +}; + +/** + * Used by sendKeysChange_1_2 to report the usability status of each key to the + * app. + * + * This struct only differs from @1.0 version by the addition of new + * KeyStatusType(s). + * + */ +struct KeyStatus { + KeySetId keyId; + KeyStatusType type; +}; diff --git a/audio/effect/4.0/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp similarity index 59% rename from audio/effect/4.0/vts/functional/Android.bp rename to drm/1.2/vts/functional/Android.bp index f1a3f0aba6..6b4a4c0adf 100644 --- a/audio/effect/4.0/vts/functional/Android.bp +++ b/drm/1.2/vts/functional/Android.bp @@ -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. @@ -15,23 +15,26 @@ // cc_test { - name: "VtsHalAudioEffectV4_0TargetTest", + name: "VtsHalDrmV1_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ - "VtsHalAudioEffectV4_0TargetTest.cpp", - "ValidateAudioEffectsConfiguration.cpp" + "drm_hal_clearkey_module.cpp", + "drm_hal_common.cpp", + "drm_hal_test.cpp", + "vendor_modules.cpp", ], + include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"], static_libs: [ - "android.hardware.audio.common.test.utility", - "android.hardware.audio.common@4.0", - "android.hardware.audio.effect@4.0", + "android.hardware.drm@1.0", + "android.hardware.drm@1.1", + "android.hardware.drm@1.2", + "android.hardware.drm@1.0-helper", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", - "libeffectsconfig", - "libxml2", - ], - header_libs: [ - "android.hardware.audio.common.util@all-versions", + "libhidlmemory", + "libnativehelper", + "libssl", + "libcrypto", ], test_suites: ["general-tests"], } diff --git a/drm/1.2/vts/functional/drm_hal_clearkey_module.cpp b/drm/1.2/vts/functional/drm_hal_clearkey_module.cpp new file mode 100644 index 0000000000..a0dc00155b --- /dev/null +++ b/drm/1.2/vts/functional/drm_hal_clearkey_module.cpp @@ -0,0 +1,130 @@ +/* + * 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 "drm_hal_clearkey_module@1.2" + +#include +#include "drm_hal_clearkey_module.h" + +namespace android { +namespace hardware { +namespace drm { +namespace V1_2 { +namespace vts { + +std::vector DrmHalVTSClearkeyModule::handleProvisioningRequest( + const std::vector& /*provisioningRequest*/, + const std::string& /*url*/) { + EXPECT_TRUE(false) << "Clearkey doesn't support provisioning"; + return {}; +} + +std::vector + DrmHalVTSClearkeyModule::getContentConfigurations() const { + DrmHalVTSClearkeyModule::ContentConfiguration conf = { + .name = "DrmHalVTSClearkeyModule", // name + .serverUrl = "", // serverUrl + .initData = { // initData + // BMFF box header (4 bytes size + 'pssh') + 0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68, + // full box header (version = 1 flags = 0) + 0x01, 0x00, 0x00, 0x00, + // system id + 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, + 0x1e, 0x52, 0xe2, 0xfb, 0x4b, + // number of key ids + 0x00, 0x00, 0x00, 0x01, + // key id + 0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0, + 0x0d, 0x1e, 0xd0, 0x0d, 0x1e, + // size of data, must be zero + 0x00, 0x00, 0x00, 0x00 + }, + .mimeType = "video/mp4", // mimeType + .optionalParameters = {}, // optionalParameters + .policy = { .allowOffline = true }, // allowOffline + .keys = { // keys + { + .isSecure = false, // isSecure + .keyId = { // keyId + 0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, + 0x7e, 0x57, 0xd0, 0x0d, 0x1e, 0xd0, 0x0d, 0x1e + }, + .clearContentKey = { // clearContentKey + 0x1a, 0x8a, 0x20, 0x95, 0xe4, 0xde, 0xb2, 0xd2, + 0x9e, 0xc8, 0x16, 0xac, 0x7b, 0xae, 0x20, 0x82 + } + } + } + }; + return { conf }; +} + +std::vector DrmHalVTSClearkeyModule::handleKeyRequest( + const std::vector& keyRequest, + const std::string& /*serverUrl*/) { + + // {"kids":["YAYeAX5Hfod-V9ANHtANHg"],"type":"temporary"} + std::vector expectedKeyRequest = { + 0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59, 0x41, 0x59, 0x65, + 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41, 0x4e, 0x48, 0x74, + 0x41, 0x4e, 0x48, 0x67, 0x22, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x22, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x22, 0x7d}; + + // {"kids":["YAYeAX5Hfod-V9ANHtANHg"],"type":"persistent-license"} + std::vector expectedKeyRequestPersistent = { + 0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59, 0x41, 0x59, 0x65, + 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41, 0x4e, 0x48, 0x74, + 0x41, 0x4e, 0x48, 0x67, 0x22, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, + 0x22, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x22, 0x7d}; + + // {"keys":[{"kty":"oct","kid":"YAYeAX5Hfod-V9ANHtANHg","k":"GoogleTestKeyBase64ggg"}]} + std::vector knownKeyResponse = { + 0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6b, 0x74, 0x79, 0x22, + 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c, 0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, + 0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41, 0x4e, + 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x22, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, + 0x36, 0x34, 0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d}; + + // {"keys":[{"kty":"oct","kid":"YAYeAX5Hfod-V9ANHtANHg","k":"GoogleTestKeyBase64ggg"}],"type":"persistent-license"} + std::vector knownKeyResponsePersistent = { + 0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6b, 0x74, 0x79, 0x22, + 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c, 0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, + 0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41, 0x4e, + 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x22, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, + 0x36, 0x34, 0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3a, 0x22, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x22, 0x7d}; + + std::string req(keyRequest.begin(), keyRequest.end()); + if (req.find("persistent-license") != std::string::npos) { + EXPECT_EQ(expectedKeyRequestPersistent, keyRequest); + return knownKeyResponsePersistent; + } else { + EXPECT_EQ(expectedKeyRequest, keyRequest); + return knownKeyResponse; + } + +} + +} // namespace vts +} // namespace V1_2 +} // namespace drm +} // namespace hardware +} // namespace android diff --git a/drm/1.2/vts/functional/drm_hal_clearkey_module.h b/drm/1.2/vts/functional/drm_hal_clearkey_module.h new file mode 100644 index 0000000000..7250cf25dd --- /dev/null +++ b/drm/1.2/vts/functional/drm_hal_clearkey_module.h @@ -0,0 +1,61 @@ +/* + * 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 DRM_HAL_CLEARKEY_MODULE_H +#define DRM_HAL_CLEARKEY_MODULE_H + +#include "drm_hal_vendor_module_api.h" + +namespace android { +namespace hardware { +namespace drm { +namespace V1_2 { +namespace vts { + +class DrmHalVTSClearkeyModule : public DrmHalVTSVendorModule_V1 { + public: + DrmHalVTSClearkeyModule() {} + virtual ~DrmHalVTSClearkeyModule() {} + + virtual uint32_t getAPIVersion() const override { return 1; } + + virtual std::string getServiceName() const override { return "clearkey"; } + + virtual std::vector getUUID() const override { + return {0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9, + 0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E }; + } + + + virtual std::vector handleProvisioningRequest( + const std::vector& provisioningRequest, + const std::string& url) override; + + virtual std::vector + getContentConfigurations() const override; + + virtual std::vector handleKeyRequest( + const std::vector& keyRequest, + const std::string& serverUrl) override; +}; + +} // namespace vts +} // namespace V1_2 +} // namespace drm +} // namespace hardware +} // namespace android + +#endif // DRM_HAL_CLEARKEY_MODULE_H diff --git a/drm/1.2/vts/functional/drm_hal_common.cpp b/drm/1.2/vts/functional/drm_hal_common.cpp new file mode 100644 index 0000000000..bfffbe8d22 --- /dev/null +++ b/drm/1.2/vts/functional/drm_hal_common.cpp @@ -0,0 +1,496 @@ +/* + * 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 "drm_hal_common@1.2" + +#include +#include +#include +#include +#include +#include +#include + +#include "drm_hal_clearkey_module.h" +#include "drm_hal_common.h" + +using ::android::hardware::drm::V1_0::BufferType; +using ::android::hardware::drm::V1_0::DestinationBuffer; +using ICryptoPluginV1_0 = ::android::hardware::drm::V1_0::ICryptoPlugin; +using IDrmPluginV1_0 = ::android::hardware::drm::V1_0::IDrmPlugin; +using ::android::hardware::drm::V1_0::KeyValue; +using ::android::hardware::drm::V1_0::SharedBuffer; +using StatusV1_0 = ::android::hardware::drm::V1_0::Status; + +using ::android::hardware::drm::V1_1::KeyRequestType; + +using ::android::hardware::drm::V1_2::KeySetId; +using ::android::hardware::drm::V1_2::OfflineLicenseState; +using StatusV1_2 = ::android::hardware::drm::V1_2::Status; + +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_memory; + +using ::android::hidl::allocator::V1_0::IAllocator; + +using std::random_device; +using std::mt19937; + +namespace android { +namespace hardware { +namespace drm { +namespace V1_2 { +namespace vts { + +const char *kCallbackLostState = "LostState"; +const char *kCallbackKeysChange = "KeysChange"; + +drm_vts::VendorModules *DrmHalTest::gVendorModules = nullptr; + +/** + * DrmHalPluginListener + */ + +Return DrmHalPluginListener::sendSessionLostState(const hidl_vec& sessionId) { + ListenerEventArgs args; + args.sessionId = sessionId; + NotifyFromCallback(kCallbackLostState, args); + return Void(); +} + +Return DrmHalPluginListener::sendKeysChange_1_2(const hidl_vec& sessionId, + const hidl_vec& keyStatusList, bool hasNewUsableKey) { + ListenerEventArgs args; + args.sessionId = sessionId; + args.keyStatusList = keyStatusList; + args.hasNewUsableKey = hasNewUsableKey; + NotifyFromCallback(kCallbackKeysChange, args); + return Void(); +} + +/** + * DrmHalTest + */ + +DrmHalTest::DrmHalTest() + : vendorModule(GetParam() == "clearkey" + ? new DrmHalVTSClearkeyModule() + : static_cast(gVendorModules->getModule(GetParam()))), + contentConfigurations(vendorModule->getContentConfigurations()) { +} + +void DrmHalTest::SetUp() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + ALOGD("Running test %s.%s from (vendor) module %s", + test_info->test_case_name(), test_info->name(), + GetParam().c_str()); + + string name = vendorModule->getServiceName(); + drmFactory = VtsHalHidlTargetTestBase::getService(name); + if (drmFactory == nullptr) { + drmFactory = VtsHalHidlTargetTestBase::getService(); + } + if (drmFactory != nullptr) { + drmPlugin = createDrmPlugin(); + } + + cryptoFactory = VtsHalHidlTargetTestBase::getService(name); + if (cryptoFactory == nullptr) { + cryptoFactory = VtsHalHidlTargetTestBase::getService(); + } + if (cryptoFactory != nullptr) { + cryptoPlugin = createCryptoPlugin(); + } + + // If drm scheme not installed skip subsequent tests + if (!drmFactory->isCryptoSchemeSupported(getVendorUUID())) { + vendorModule->setInstalled(false); + return; + } + + ASSERT_NE(nullptr, drmPlugin.get()) << "Can't find " << vendorModule->getServiceName() << " drm@1.2 plugin"; + ASSERT_NE(nullptr, cryptoPlugin.get()) << "Can't find " << vendorModule->getServiceName() << " crypto@1.2 plugin"; + +} + +sp DrmHalTest::createDrmPlugin() { + if (drmFactory == nullptr) { + return nullptr; + } + sp plugin = nullptr; + hidl_string packageName("android.hardware.drm.test"); + auto res = drmFactory->createPlugin( + getVendorUUID(), packageName, + [&](StatusV1_0 status, const sp& pluginV1_0) { + EXPECT_EQ(StatusV1_0::OK, status); + plugin = IDrmPlugin::castFrom(pluginV1_0); + }); + + if (!res.isOk()) { + ALOGE("createDrmPlugin remote call failed"); + } + return plugin; +} + +sp DrmHalTest::createCryptoPlugin() { + if (cryptoFactory == nullptr) { + return nullptr; + } + sp plugin = nullptr; + hidl_vec initVec; + auto res = cryptoFactory->createPlugin( + getVendorUUID(), initVec, + [&](StatusV1_0 status, const sp& pluginV1_0) { + EXPECT_EQ(StatusV1_0::OK, status); + plugin = ICryptoPlugin::castFrom(pluginV1_0); + }); + if (!res.isOk()) { + ALOGE("createCryptoPlugin remote call failed"); + } + return plugin; +} + +hidl_array DrmHalTest::getVendorUUID() { + vector uuid = vendorModule->getUUID(); + return hidl_array(&uuid[0]); +} + +/** + * Helper method to open a session and verify that a non-empty + * session ID is returned + */ +SessionId DrmHalTest::openSession() { + SessionId sessionId; + + auto res = drmPlugin->openSession([&](StatusV1_0 status, const hidl_vec &id) { + EXPECT_EQ(StatusV1_0::OK, status); + EXPECT_NE(id.size(), 0u); + sessionId = id; + }); + EXPECT_OK(res); + return sessionId; +} + +/** + * Helper method to close a session + */ +void DrmHalTest::closeSession(const SessionId& sessionId) { + StatusV1_0 status = drmPlugin->closeSession(sessionId); + EXPECT_EQ(StatusV1_0::OK, status); +} + +hidl_vec DrmHalTest::getKeyRequest( + const SessionId& sessionId, + const DrmHalVTSVendorModule_V1::ContentConfiguration& configuration, + const KeyType& type = KeyType::STREAMING) { + hidl_vec keyRequest; + auto res = drmPlugin->getKeyRequest_1_2( + sessionId, configuration.initData, configuration.mimeType, type, + toHidlKeyedVector(configuration.optionalParameters), + [&](Status status, const hidl_vec& request, + KeyRequestType requestType, const hidl_string&) { + EXPECT_EQ(Status::OK, status) << "Failed to get " + "key request for configuration " + << configuration.name; + if (type == KeyType::RELEASE) { + EXPECT_EQ(KeyRequestType::RELEASE, requestType); + } else { + EXPECT_EQ(KeyRequestType::INITIAL, requestType); + } + EXPECT_NE(request.size(), 0u) << "Expected key request size" + " to have length > 0 bytes"; + keyRequest = request; + }); + EXPECT_OK(res); + return keyRequest; +} + +DrmHalVTSVendorModule_V1::ContentConfiguration DrmHalTest::getContent(const KeyType& type) const { + for (const auto& config : contentConfigurations) { + if (type != KeyType::OFFLINE || config.policy.allowOffline) { + return config; + } + } + EXPECT_TRUE(false) << "no content configurations found"; + return {}; +} + +hidl_vec DrmHalTest::provideKeyResponse( + const SessionId& sessionId, + const hidl_vec& keyResponse) { + hidl_vec keySetId; + auto res = drmPlugin->provideKeyResponse( + sessionId, keyResponse, + [&](StatusV1_0 status, const hidl_vec& myKeySetId) { + EXPECT_EQ(StatusV1_0::OK, status) << "Failure providing " + "key response for configuration "; + keySetId = myKeySetId; + }); + EXPECT_OK(res); + return keySetId; +} + +/** + * Helper method to load keys for subsequent decrypt tests. + * These tests use predetermined key request/response to + * avoid requiring a round trip to a license server. + */ +hidl_vec DrmHalTest::loadKeys( + const SessionId& sessionId, + const DrmHalVTSVendorModule_V1::ContentConfiguration& configuration, + const KeyType& type) { + hidl_vec keyRequest = getKeyRequest(sessionId, configuration, type); + + /** + * Get key response from vendor module + */ + hidl_vec keyResponse = + vendorModule->handleKeyRequest(keyRequest, configuration.serverUrl); + EXPECT_NE(keyResponse.size(), 0u) << "Expected key response size " + "to have length > 0 bytes"; + + return provideKeyResponse(sessionId, keyResponse); +} + +hidl_vec DrmHalTest::loadKeys( + const SessionId& sessionId, + const KeyType& type) { + return loadKeys(sessionId, getContent(type), type); +} + +KeyedVector DrmHalTest::toHidlKeyedVector( + const map& params) { + std::vector stdKeyedVector; + for (auto it = params.begin(); it != params.end(); ++it) { + KeyValue keyValue; + keyValue.key = it->first; + keyValue.value = it->second; + stdKeyedVector.push_back(keyValue); + } + return KeyedVector(stdKeyedVector); +} + +hidl_array DrmHalTest::toHidlArray(const vector& vec) { + EXPECT_EQ(16u, vec.size()); + return hidl_array(&vec[0]); +} + +/** + * getDecryptMemory allocates memory for decryption, then sets it + * as a shared buffer base in the crypto hal. The allocated and + * mapped IMemory is returned. + * + * @param size the size of the memory segment to allocate + * @param the index of the memory segment which will be used + * to refer to it for decryption. + */ +sp DrmHalTest::getDecryptMemory(size_t size, size_t index) { + sp ashmemAllocator = IAllocator::getService("ashmem"); + EXPECT_NE(nullptr, ashmemAllocator.get()); + + hidl_memory hidlMemory; + auto res = ashmemAllocator->allocate( + size, [&](bool success, const hidl_memory& memory) { + EXPECT_EQ(success, true); + EXPECT_EQ(memory.size(), size); + hidlMemory = memory; + }); + + EXPECT_OK(res); + + sp mappedMemory = mapMemory(hidlMemory); + EXPECT_NE(nullptr, mappedMemory.get()); + res = cryptoPlugin->setSharedBufferBase(hidlMemory, index); + EXPECT_OK(res); + return mappedMemory; +} + +void DrmHalTest::fillRandom(const sp& memory) { + random_device rd; + mt19937 rand(rd()); + for (size_t i = 0; i < memory->getSize() / sizeof(uint32_t); i++) { + auto p = static_cast( + static_cast(memory->getPointer())); + p[i] = rand(); + } +} + +uint32_t DrmHalTest::decrypt(Mode mode, bool isSecure, + const hidl_array& keyId, uint8_t* iv, + const hidl_vec& subSamples, const Pattern& pattern, + const vector& key, StatusV1_2 expectedStatus) { + const size_t kSegmentIndex = 0; + + uint8_t localIv[AES_BLOCK_SIZE]; + memcpy(localIv, iv, AES_BLOCK_SIZE); + + size_t totalSize = 0; + for (size_t i = 0; i < subSamples.size(); i++) { + totalSize += subSamples[i].numBytesOfClearData; + totalSize += subSamples[i].numBytesOfEncryptedData; + } + + // The first totalSize bytes of shared memory is the encrypted + // input, the second totalSize bytes (if exists) is the decrypted output. + size_t factor = expectedStatus == StatusV1_2::ERROR_DRM_FRAME_TOO_LARGE ? 1 : 2; + sp sharedMemory = + getDecryptMemory(totalSize * factor, kSegmentIndex); + + const SharedBuffer sourceBuffer = { + .bufferId = kSegmentIndex, .offset = 0, .size = totalSize}; + fillRandom(sharedMemory); + + const DestinationBuffer destBuffer = {.type = BufferType::SHARED_MEMORY, + {.bufferId = kSegmentIndex, + .offset = totalSize, + .size = totalSize}, + .secureMemory = nullptr}; + const uint64_t offset = 0; + uint32_t bytesWritten = 0; + auto res = cryptoPlugin->decrypt_1_2(isSecure, keyId, localIv, mode, pattern, + subSamples, sourceBuffer, offset, destBuffer, + [&](StatusV1_2 status, uint32_t count, string detailedError) { + EXPECT_EQ(expectedStatus, status) << "Unexpected decrypt status " << + detailedError; + bytesWritten = count; + }); + EXPECT_OK(res); + + if (bytesWritten != totalSize) { + return bytesWritten; + } + uint8_t* base = static_cast( + static_cast(sharedMemory->getPointer())); + + // generate reference vector + vector reference(totalSize); + + memcpy(localIv, iv, AES_BLOCK_SIZE); + switch (mode) { + case Mode::UNENCRYPTED: + memcpy(&reference[0], base, totalSize); + break; + case Mode::AES_CTR: + aes_ctr_decrypt(&reference[0], base, localIv, subSamples, key); + break; + case Mode::AES_CBC: + aes_cbc_decrypt(&reference[0], base, localIv, subSamples, key); + break; + case Mode::AES_CBC_CTS: + EXPECT_TRUE(false) << "AES_CBC_CTS mode not supported"; + break; + } + + // compare reference to decrypted data which is at base + total size + EXPECT_EQ(0, memcmp(static_cast(&reference[0]), + static_cast(base + totalSize), totalSize)) + << "decrypt data mismatch"; + return totalSize; +} + +/** + * Decrypt a list of clear+encrypted subsamples using the specified key + * in AES-CTR mode + */ +void DrmHalTest::aes_ctr_decrypt(uint8_t* dest, uint8_t* src, + uint8_t* iv, const hidl_vec& subSamples, + const vector& key) { + AES_KEY decryptionKey; + AES_set_encrypt_key(&key[0], 128, &decryptionKey); + + size_t offset = 0; + unsigned int blockOffset = 0; + uint8_t previousEncryptedCounter[AES_BLOCK_SIZE]; + memset(previousEncryptedCounter, 0, AES_BLOCK_SIZE); + + for (size_t i = 0; i < subSamples.size(); i++) { + const SubSample& subSample = subSamples[i]; + + if (subSample.numBytesOfClearData > 0) { + memcpy(dest + offset, src + offset, subSample.numBytesOfClearData); + offset += subSample.numBytesOfClearData; + } + + if (subSample.numBytesOfEncryptedData > 0) { + AES_ctr128_encrypt(src + offset, dest + offset, + subSample.numBytesOfEncryptedData, &decryptionKey, + iv, previousEncryptedCounter, &blockOffset); + offset += subSample.numBytesOfEncryptedData; + } + } +} + +/** + * Decrypt a list of clear+encrypted subsamples using the specified key + * in AES-CBC mode + */ +void DrmHalTest::aes_cbc_decrypt(uint8_t* dest, uint8_t* src, + uint8_t* iv, const hidl_vec& subSamples, + const vector& key) { + AES_KEY decryptionKey; + AES_set_encrypt_key(&key[0], 128, &decryptionKey); + + size_t offset = 0; + for (size_t i = 0; i < subSamples.size(); i++) { + memcpy(dest + offset, src + offset, subSamples[i].numBytesOfClearData); + offset += subSamples[i].numBytesOfClearData; + + AES_cbc_encrypt(src + offset, dest + offset, subSamples[i].numBytesOfEncryptedData, + &decryptionKey, iv, 0 /* decrypt */); + offset += subSamples[i].numBytesOfEncryptedData; + } +} + +/** + * Helper method to test decryption with invalid keys is returned + */ +void DrmHalClearkeyTest::decryptWithInvalidKeys( + hidl_vec& invalidResponse, + vector& iv, + const Pattern& noPattern, + const vector& subSamples) { + DrmHalVTSVendorModule_V1::ContentConfiguration content = getContent(); + if (content.keys.empty()) { + FAIL() << "no keys"; + } + + const auto& key = content.keys[0]; + auto sessionId = openSession(); + auto res = drmPlugin->provideKeyResponse( + sessionId, invalidResponse, + [&](StatusV1_0 status, const hidl_vec& myKeySetId) { + EXPECT_EQ(StatusV1_0::OK, status); + EXPECT_EQ(0u, myKeySetId.size()); + }); + EXPECT_OK(res); + + EXPECT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk()); + + uint32_t byteCount = decrypt(Mode::AES_CTR, key.isSecure, + toHidlArray(key.keyId), &iv[0], subSamples, noPattern, + key.clearContentKey, Status::ERROR_DRM_NO_LICENSE); + EXPECT_EQ(0u, byteCount); + + closeSession(sessionId); +} + +} // namespace vts +} // namespace V1_2 +} // namespace drm +} // namespace hardware +} // namespace android diff --git a/drm/1.2/vts/functional/drm_hal_common.h b/drm/1.2/vts/functional/drm_hal_common.h new file mode 100644 index 0000000000..e34866474b --- /dev/null +++ b/drm/1.2/vts/functional/drm_hal_common.h @@ -0,0 +1,204 @@ +/* + * 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 DRM_HAL_COMMON_H +#define DRM_HAL_COMMON_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "drm_hal_vendor_module_api.h" +#include "vendor_modules.h" +#include "VtsHalHidlTargetCallbackBase.h" +#include "VtsHalHidlTargetTestBase.h" + +using ::android::hardware::drm::V1_0::EventType; +using ::android::hardware::drm::V1_0::KeyedVector; +using KeyStatusV1_0 = ::android::hardware::drm::V1_0::KeyStatus; +using ::android::hardware::drm::V1_0::KeyType; +using ::android::hardware::drm::V1_0::Mode; +using ::android::hardware::drm::V1_0::Pattern; +using ::android::hardware::drm::V1_0::SessionId; +using ::android::hardware::drm::V1_0::SubSample; + +using ::android::hardware::drm::V1_1::ICryptoFactory; + +using StatusV1_2 = ::android::hardware::drm::V1_2::Status; + +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +using ::android::hidl::memory::V1_0::IMemory; +using ::android::sp; + +using ::testing::VtsHalHidlTargetTestBase; + +using std::map; +using std::string; +using std::unique_ptr; +using std::vector; + +#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) + +#define RETURN_IF_SKIPPED \ + if (!vendorModule->isInstalled()) { \ + std::cout << "[ SKIPPED ] This drm scheme not supported." << \ + " library:" << GetParam() << " service-name:" << \ + vendorModule->getServiceName() << std::endl; \ + return; \ + } + +namespace android { +namespace hardware { +namespace drm { +namespace V1_2 { +namespace vts { + +class DrmHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static DrmHidlEnvironment* Instance() { + static DrmHidlEnvironment* instance = new DrmHidlEnvironment; + return instance; + } + + void registerTestServices() override { + registerTestService(); + registerTestService(); + setServiceCombMode(::testing::HalServiceCombMode::NO_COMBINATION); + } + + private: + DrmHidlEnvironment() {} + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DrmHidlEnvironment); +}; + +class DrmHalTest : public ::testing::TestWithParam { + public: + static drm_vts::VendorModules* gVendorModules; + DrmHalTest(); + virtual void SetUp() override; + virtual void TearDown() override {} + + protected: + hidl_array getVendorUUID(); + SessionId openSession(); + void closeSession(const SessionId& sessionId); + hidl_vec loadKeys(const SessionId& sessionId, + const KeyType& type = KeyType::STREAMING); + hidl_vec loadKeys(const SessionId& sessionId, + const DrmHalVTSVendorModule_V1::ContentConfiguration&, + const KeyType& type = KeyType::STREAMING); + hidl_vec getKeyRequest(const SessionId& sessionId, + const DrmHalVTSVendorModule_V1::ContentConfiguration&, + const KeyType& type); + hidl_vec provideKeyResponse(const SessionId& sessionId, + const hidl_vec& keyResponse); + DrmHalVTSVendorModule_V1::ContentConfiguration getContent( + const KeyType& type = KeyType::STREAMING) const; + + KeyedVector toHidlKeyedVector(const map& params); + hidl_array toHidlArray(const vector& vec); + + void fillRandom(const sp& memory); + sp getDecryptMemory(size_t size, size_t index); + uint32_t decrypt(Mode mode, bool isSecure, + const hidl_array& keyId, uint8_t* iv, + const hidl_vec& subSamples, const Pattern& pattern, + const vector& key, StatusV1_2 expectedStatus); + void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv, + const hidl_vec& subSamples, const vector& key); + void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv, + const hidl_vec& subSamples, const vector& key); + + sp drmFactory; + sp cryptoFactory; + sp drmPlugin; + sp cryptoPlugin; + unique_ptr vendorModule; + const vector contentConfigurations; + + private: + sp createDrmPlugin(); + sp createCryptoPlugin(); + +}; + +class DrmHalClearkeyTest : public DrmHalTest { + public: + virtual void SetUp() override { DrmHalTest::SetUp(); } + virtual void TearDown() override {} + void decryptWithInvalidKeys(hidl_vec& invalidResponse, + vector& iv, const Pattern& noPattern, const vector& subSamples); +}; + +/** + * Event Handling tests + */ +extern const char *kCallbackLostState; +extern const char *kCallbackKeysChange; + +struct ListenerEventArgs { + SessionId sessionId; + hidl_vec keyStatusList; + bool hasNewUsableKey; +}; + +class DrmHalPluginListener + : public ::testing::VtsHalHidlTargetCallbackBase, + public IDrmPluginListener { +public: + DrmHalPluginListener() { + SetWaitTimeoutDefault(std::chrono::milliseconds(500)); + } + virtual ~DrmHalPluginListener() {} + + virtual Return sendEvent(EventType, const hidl_vec&, + const hidl_vec& ) override { return Void(); } + + virtual Return sendExpirationUpdate(const hidl_vec&, + int64_t) override { return Void(); } + + virtual Return sendKeysChange(const hidl_vec&, + const hidl_vec&, bool) override { return Void(); } + + virtual Return sendSessionLostState(const hidl_vec& sessionId) override; + + virtual Return sendKeysChange_1_2(const hidl_vec&, + const hidl_vec&, bool) override; + +}; + +} // namespace vts +} // namespace V1_2 +} // namespace drm +} // namespace hardware +} // namespace android + +#endif // DRM_HAL_COMMON_H diff --git a/drm/1.2/vts/functional/drm_hal_test.cpp b/drm/1.2/vts/functional/drm_hal_test.cpp new file mode 100644 index 0000000000..37ecc25430 --- /dev/null +++ b/drm/1.2/vts/functional/drm_hal_test.cpp @@ -0,0 +1,591 @@ +/* + * 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 "drm_hal_test@1.2" + +#include +#include +#include +#include + +#include "drm_hal_common.h" + +using ::android::hardware::drm::V1_0::Status; +using ::android::hardware::drm::V1_1::KeyRequestType; +using ::android::hardware::drm::V1_1::SecurityLevel; +using ::android::hardware::drm::V1_2::HdcpLevel; +using ::android::hardware::drm::V1_2::KeySetId; +using ::android::hardware::drm::V1_2::KeyStatus; +using ::android::hardware::drm::V1_2::KeyStatusType; +using ::android::hardware::drm::V1_2::OfflineLicenseState; + +using ::android::hardware::drm::V1_2::vts::DrmHalClearkeyTest; +using ::android::hardware::drm::V1_2::vts::DrmHalPluginListener; +using ::android::hardware::drm::V1_2::vts::DrmHalTest; +using ::android::hardware::drm::V1_2::vts::DrmHidlEnvironment; +using ::android::hardware::drm::V1_2::vts::kCallbackLostState; +using ::android::hardware::drm::V1_2::vts::kCallbackKeysChange; + +using ::android::hardware::hidl_string; + +static const char* const kVideoMp4 = "video/mp4"; +static const char* const kBadMime = "video/unknown"; +static const char* const kDrmErrorTestKey = "drmErrorTest"; +static const char* const kDrmErrorInvalidState = "invalidState"; +static const char* const kDrmErrorResourceContention = "resourceContention"; +static const SecurityLevel kSwSecureCrypto = SecurityLevel::SW_SECURE_CRYPTO; + +/** + * Ensure drm factory supports module UUID Scheme + */ +TEST_P(DrmHalTest, VendorUuidSupported) { + auto res = drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kVideoMp4, kSwSecureCrypto); + ALOGI("kVideoMp4 = %s res %d", kVideoMp4, (bool)res); + EXPECT_TRUE(res); +} + +/** + * Ensure drm factory doesn't support an invalid scheme UUID + */ +TEST_P(DrmHalTest, InvalidPluginNotSupported) { + const uint8_t kInvalidUUID[16] = { + 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, + 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80}; + EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(kInvalidUUID, kVideoMp4, kSwSecureCrypto)); +} + +/** + * Ensure drm factory doesn't support an empty UUID + */ +TEST_P(DrmHalTest, EmptyPluginUUIDNotSupported) { + hidl_array emptyUUID; + memset(emptyUUID.data(), 0, 16); + EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(emptyUUID, kVideoMp4, kSwSecureCrypto)); +} + +/** + * Ensure drm factory doesn't support an invalid mime type + */ +TEST_P(DrmHalTest, BadMimeNotSupported) { + EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kBadMime, kSwSecureCrypto)); +} + +/** + * DrmPlugin tests + */ + +/** + * Test that a DRM plugin can handle provisioning. While + * it is not required that a DRM scheme require provisioning, + * it should at least return appropriate status values. If + * a provisioning request is returned, it is passed to the + * vendor module which should provide a provisioning response + * that is delivered back to the HAL. + */ +TEST_P(DrmHalTest, DoProvisioning) { + RETURN_IF_SKIPPED; + hidl_string certificateType; + hidl_string certificateAuthority; + hidl_vec provisionRequest; + hidl_string defaultUrl; + auto res = drmPlugin->getProvisionRequest_1_2( + certificateType, certificateAuthority, + [&](StatusV1_2 status, const hidl_vec& request, + const hidl_string& url) { + if (status == StatusV1_2::OK) { + EXPECT_NE(request.size(), 0u); + provisionRequest = request; + defaultUrl = url; + } else if (status == StatusV1_2::ERROR_DRM_CANNOT_HANDLE) { + EXPECT_EQ(0u, request.size()); + } + }); + EXPECT_OK(res); + + if (provisionRequest.size() > 0) { + vector response = vendorModule->handleProvisioningRequest( + provisionRequest, defaultUrl); + ASSERT_NE(0u, response.size()); + + auto res = drmPlugin->provideProvisionResponse( + response, [&](Status status, const hidl_vec&, + const hidl_vec&) { + EXPECT_EQ(Status::OK, status); + }); + EXPECT_OK(res); + } +} + +/** + * A get key request should fail if no sessionId is provided + */ +TEST_P(DrmHalTest, GetKeyRequestNoSession) { + SessionId invalidSessionId; + hidl_vec initData; + KeyedVector optionalParameters; + auto res = drmPlugin->getKeyRequest_1_2( + invalidSessionId, initData, kVideoMp4, KeyType::STREAMING, + optionalParameters, + [&](StatusV1_2 status, const hidl_vec&, KeyRequestType, + const hidl_string&) { EXPECT_EQ(StatusV1_2::BAD_VALUE, status); }); + EXPECT_OK(res); +} + +/** + * Test that the plugin returns the documented error for the + * case of attempting to generate a key request using an + * invalid mime type + */ +TEST_P(DrmHalTest, GetKeyRequestBadMime) { + auto sessionId = openSession(); + hidl_vec initData; + KeyedVector optionalParameters; + auto res = drmPlugin->getKeyRequest_1_2( + sessionId, initData, kBadMime, KeyType::STREAMING, + optionalParameters, [&](StatusV1_2 status, const hidl_vec&, + KeyRequestType, const hidl_string&) { + EXPECT_NE(StatusV1_2::OK, status); + }); + EXPECT_OK(res); + closeSession(sessionId); +} + +template +void checkKeySetIds(Status status, const hidl_vec& keySetIds) { + EXPECT_EQ(S, status); + if (S == Status::OK) { + EXPECT_EQ(N, keySetIds.size()); + } +} + +template +void checkKeySetIdState(Status status, OfflineLicenseState state) { + if (S == Status::OK) { + EXPECT_TRUE(T == OfflineLicenseState::USABLE || T == OfflineLicenseState::INACTIVE); + } else { + EXPECT_TRUE(T == OfflineLicenseState::UNKNOWN); + } + EXPECT_EQ(S, status); + EXPECT_EQ(T, state); +} + +/** + * Test drm plugin offline key support + */ +TEST_P(DrmHalTest, OfflineLicenseTest) { + auto sessionId = openSession(); + hidl_vec keySetId = loadKeys(sessionId, KeyType::OFFLINE); + + auto res = drmPlugin->getOfflineLicenseKeySetIds( + [&](Status status, const hidl_vec& keySetIds) { + bool found = false; + EXPECT_EQ(Status::OK, status); + for (KeySetId keySetId2: keySetIds) { + if (keySetId == keySetId2) { + found = true; + break; + } + } + EXPECT_TRUE(found) << "keySetId not found"; + }); + EXPECT_OK(res); + + Status err = drmPlugin->removeOfflineLicense(keySetId); + EXPECT_EQ(Status::OK, err); + + res = drmPlugin->getOfflineLicenseKeySetIds( + [&](Status status, const hidl_vec& keySetIds) { + EXPECT_EQ(Status::OK, status); + for (KeySetId keySetId2: keySetIds) { + EXPECT_NE(keySetId, keySetId2); + } + }); + EXPECT_OK(res); + + err = drmPlugin->removeOfflineLicense(keySetId); + EXPECT_EQ(Status::BAD_VALUE, err); + + closeSession(sessionId); +} + +/** + * Test drm plugin offline key state + */ +TEST_P(DrmHalTest, OfflineLicenseStateTest) { + auto sessionId = openSession(); + DrmHalVTSVendorModule_V1::ContentConfiguration content = getContent(KeyType::OFFLINE); + hidl_vec keySetId = loadKeys(sessionId, content, KeyType::OFFLINE); + drmPlugin->getOfflineLicenseState(keySetId, checkKeySetIdState); + + hidl_vec keyRequest = getKeyRequest(keySetId, content, KeyType::RELEASE); + drmPlugin->getOfflineLicenseState(keySetId, checkKeySetIdState); + + /** + * Get key response from vendor module + */ + hidl_vec keyResponse = + vendorModule->handleKeyRequest(keyRequest, content.serverUrl); + EXPECT_GT(keyResponse.size(), 0u); + + provideKeyResponse(keySetId, keyResponse); + drmPlugin->getOfflineLicenseState(keySetId, checkKeySetIdState); + closeSession(sessionId); +} + +/** + * Negative offline license test. Remove empty keySetId + */ +TEST_P(DrmHalTest, RemoveEmptyKeySetId) { + KeySetId emptyKeySetId; + Status err = drmPlugin->removeOfflineLicense(emptyKeySetId); + EXPECT_EQ(Status::BAD_VALUE, err); +} + +/** + * Negative offline license test. Get empty keySetId state + */ +TEST_P(DrmHalTest, GetEmptyKeySetIdState) { + KeySetId emptyKeySetId; + auto res = drmPlugin->getOfflineLicenseState(emptyKeySetId, checkKeySetIdState); + EXPECT_OK(res); +} + +/** + * Test that the plugin returns valid connected and max HDCP levels + */ +TEST_P(DrmHalTest, GetHdcpLevels) { + auto res = drmPlugin->getHdcpLevels_1_2( + [&](StatusV1_2 status, const HdcpLevel &connectedLevel, + const HdcpLevel &maxLevel) { + EXPECT_EQ(StatusV1_2::OK, status); + EXPECT_GE(connectedLevel, HdcpLevel::HDCP_NONE); + EXPECT_LE(maxLevel, HdcpLevel::HDCP_V2_3); + }); + EXPECT_OK(res); +} + +/** + * Simulate the plugin sending keys change and make sure + * the listener gets them. + */ +TEST_P(DrmHalTest, ListenerKeysChange) { + RETURN_IF_SKIPPED; + sp listener = new DrmHalPluginListener(); + auto res = drmPlugin->setListener(listener); + EXPECT_OK(res); + + auto sessionId = openSession(); + const hidl_vec keyStatusList = { + {{1}, KeyStatusType::USABLE}, + {{2}, KeyStatusType::EXPIRED}, + {{3}, KeyStatusType::OUTPUTNOTALLOWED}, + {{4}, KeyStatusType::STATUSPENDING}, + {{5}, KeyStatusType::INTERNALERROR}, + {{6}, KeyStatusType::USABLEINFUTURE}, + }; + + drmPlugin->sendKeysChange_1_2(sessionId, keyStatusList, true); + auto result = listener->WaitForCallback(kCallbackKeysChange); + EXPECT_TRUE(result.no_timeout); + EXPECT_TRUE(result.args); + EXPECT_EQ(sessionId, result.args->sessionId); + EXPECT_EQ(keyStatusList, result.args->keyStatusList); + closeSession(sessionId); +} + +/** + * CryptoPlugin Decrypt tests + */ + +/** + * Positive decrypt test. "Decrypt" a single clear segment + */ +TEST_P(DrmHalTest, ClearSegmentTest) { + RETURN_IF_SKIPPED; + for (const auto& config : contentConfigurations) { + for (const auto& key : config.keys) { + const size_t kSegmentSize = 1024; + vector iv(AES_BLOCK_SIZE, 0); + const Pattern noPattern = {0, 0}; + const vector subSamples = {{.numBytesOfClearData = kSegmentSize, + .numBytesOfEncryptedData = 0}}; + auto sessionId = openSession(); + loadKeys(sessionId, config); + + Status status = cryptoPlugin->setMediaDrmSession(sessionId); + EXPECT_EQ(Status::OK, status); + + uint32_t byteCount = decrypt(Mode::UNENCRYPTED, key.isSecure, toHidlArray(key.keyId), + &iv[0], subSamples, noPattern, key.clearContentKey, StatusV1_2::OK); + EXPECT_EQ(kSegmentSize, byteCount); + + closeSession(sessionId); + } + } +} + +/** + * Positive decrypt test. Decrypt a single segment using aes_ctr. + * Verify data matches. + */ +TEST_P(DrmHalTest, EncryptedAesCtrSegmentTest) { + RETURN_IF_SKIPPED; + for (const auto& config : contentConfigurations) { + for (const auto& key : config.keys) { + const size_t kSegmentSize = 1024; + vector iv(AES_BLOCK_SIZE, 0); + const Pattern noPattern = {0, 0}; + const vector subSamples = {{.numBytesOfClearData = kSegmentSize, + .numBytesOfEncryptedData = 0}}; + auto sessionId = openSession(); + loadKeys(sessionId, config); + + Status status = cryptoPlugin->setMediaDrmSession(sessionId); + EXPECT_EQ(Status::OK, status); + + uint32_t byteCount = decrypt(Mode::AES_CTR, key.isSecure, toHidlArray(key.keyId), + &iv[0], subSamples, noPattern, key.clearContentKey, StatusV1_2::OK); + EXPECT_EQ(kSegmentSize, byteCount); + + closeSession(sessionId); + } + } +} + +/** + * Negative decrypt test. Decrypted frame too large to fit in output buffer + */ +TEST_P(DrmHalTest, ErrorFrameTooLarge) { + RETURN_IF_SKIPPED; + for (const auto& config : contentConfigurations) { + for (const auto& key : config.keys) { + const size_t kSegmentSize = 1024; + vector iv(AES_BLOCK_SIZE, 0); + const Pattern noPattern = {0, 0}; + const vector subSamples = {{.numBytesOfClearData = kSegmentSize, + .numBytesOfEncryptedData = 0}}; + auto sessionId = openSession(); + loadKeys(sessionId, config); + + Status status = cryptoPlugin->setMediaDrmSession(sessionId); + EXPECT_EQ(Status::OK, status); + + decrypt(Mode::UNENCRYPTED, key.isSecure, toHidlArray(key.keyId), + &iv[0], subSamples, noPattern, key.clearContentKey, StatusV1_2::ERROR_DRM_FRAME_TOO_LARGE); + + closeSession(sessionId); + } + } +} + +/** + * Negative decrypt test. Decrypt without loading keys. + */ +TEST_P(DrmHalTest, EncryptedAesCtrSegmentTestNoKeys) { + RETURN_IF_SKIPPED; + for (const auto& config : contentConfigurations) { + for (const auto& key : config.keys) { + vector iv(AES_BLOCK_SIZE, 0); + const Pattern noPattern = {0, 0}; + const vector subSamples = {{.numBytesOfClearData = 256, + .numBytesOfEncryptedData = 256}}; + auto sessionId = openSession(); + + Status status = cryptoPlugin->setMediaDrmSession(sessionId); + EXPECT_EQ(Status::OK, status); + + uint32_t byteCount = decrypt(Mode::AES_CTR, key.isSecure, + toHidlArray(key.keyId), &iv[0], subSamples, noPattern, + key.clearContentKey, StatusV1_2::ERROR_DRM_NO_LICENSE); + EXPECT_EQ(0u, byteCount); + + closeSession(sessionId); + } + } +} + +/** + * Ensure clearkey drm factory doesn't support security level higher than supported + */ +TEST_P(DrmHalClearkeyTest, BadLevelNotSupported) { + const SecurityLevel kHwSecureAll = SecurityLevel::HW_SECURE_ALL; + EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kVideoMp4, kHwSecureAll)); +} + +/** + * Test resource contention during attempt to generate key request + */ +TEST_P(DrmHalClearkeyTest, GetKeyRequestResourceContention) { + Status status = drmPlugin->setPropertyString(kDrmErrorTestKey, kDrmErrorResourceContention); + EXPECT_EQ(Status::OK, status); + auto sessionId = openSession(); + hidl_vec initData; + KeyedVector optionalParameters; + auto res = drmPlugin->getKeyRequest_1_2( + sessionId, initData, kVideoMp4, KeyType::STREAMING, + optionalParameters, [&](StatusV1_2 status, const hidl_vec&, + KeyRequestType, const hidl_string&) { + EXPECT_EQ(StatusV1_2::ERROR_DRM_RESOURCE_CONTENTION, status); + }); + EXPECT_OK(res); + + status = drmPlugin->closeSession(sessionId); + EXPECT_NE(Status::OK, status); +} + +/** + * Test clearkey plugin offline key with mock error + */ +TEST_P(DrmHalClearkeyTest, OfflineLicenseInvalidState) { + auto sessionId = openSession(); + hidl_vec keySetId = loadKeys(sessionId, KeyType::OFFLINE); + Status status = drmPlugin->setPropertyString(kDrmErrorTestKey, kDrmErrorInvalidState); + EXPECT_EQ(Status::OK, status); + + // everything should start failing + const Status kInvalidState = Status::ERROR_DRM_INVALID_STATE; + const OfflineLicenseState kUnknownState = OfflineLicenseState::UNKNOWN; + auto res = drmPlugin->getOfflineLicenseKeySetIds(checkKeySetIds); + EXPECT_OK(res); + res = drmPlugin->getOfflineLicenseState(keySetId, checkKeySetIdState); + EXPECT_OK(res); + Status err = drmPlugin->removeOfflineLicense(keySetId); + EXPECT_EQ(kInvalidState, err); + closeSession(sessionId); +} + +/** + * Test SessionLostState is triggered on error + */ +TEST_P(DrmHalClearkeyTest, SessionLostState) { + sp listener = new DrmHalPluginListener(); + auto res = drmPlugin->setListener(listener); + EXPECT_OK(res); + + Status status = drmPlugin->setPropertyString(kDrmErrorTestKey, kDrmErrorInvalidState); + EXPECT_EQ(Status::OK, status); + + auto sessionId = openSession(); + drmPlugin->closeSession(sessionId); + + auto result = listener->WaitForCallback(kCallbackLostState); + EXPECT_TRUE(result.no_timeout); + EXPECT_TRUE(result.args); + EXPECT_EQ(sessionId, result.args->sessionId); +} + +/** + * Negative decrypt test. Decrypt with invalid key. + */ +TEST_P(DrmHalClearkeyTest, DecryptWithEmptyKey) { + vector iv(AES_BLOCK_SIZE, 0); + const Pattern noPattern = {0, 0}; + const uint32_t kClearBytes = 512; + const uint32_t kEncryptedBytes = 512; + const vector subSamples = { + {.numBytesOfClearData = kClearBytes, + .numBytesOfEncryptedData = kEncryptedBytes}}; + + // base 64 encoded JSON response string, must not contain padding character '=' + const hidl_string emptyKeyResponse = + "{\"keys\":[" \ + "{" \ + "\"kty\":\"oct\"" \ + "\"alg\":\"A128KW2\"" \ + "\"k\":\"SGVsbG8gRnJpZW5kIQ\"" \ + "\"kid\":\"Y2xlYXJrZXlrZXlpZDAyAy\"" \ + "}" \ + "{" \ + "\"kty\":\"oct\"," \ + "\"alg\":\"A128KW2\"" \ + "\"kid\":\"Y2xlYXJrZXlrZXlpZDAzAy\"," \ + // empty key follows + "\"k\":\"R\"" \ + "}]" \ + "}"; + const size_t kEmptyKeyResponseSize = emptyKeyResponse.size(); + + hidl_vec invalidResponse; + invalidResponse.resize(kEmptyKeyResponseSize); + memcpy(invalidResponse.data(), emptyKeyResponse.c_str(), kEmptyKeyResponseSize); + decryptWithInvalidKeys(invalidResponse, iv, noPattern, subSamples); +} + +/** + * Negative decrypt test. Decrypt with a key exceeds AES_BLOCK_SIZE. + */ +TEST_P(DrmHalClearkeyTest, DecryptWithKeyTooLong) { + vector iv(AES_BLOCK_SIZE, 0); + const Pattern noPattern = {0, 0}; + const uint32_t kClearBytes = 512; + const uint32_t kEncryptedBytes = 512; + const vector subSamples = { + {.numBytesOfClearData = kClearBytes, + .numBytesOfEncryptedData = kEncryptedBytes}}; + + // base 64 encoded JSON response string, must not contain padding character '=' + const hidl_string keyTooLongResponse = + "{\"keys\":[" \ + "{" \ + "\"kty\":\"oct\"," \ + "\"alg\":\"A128KW2\"" \ + "\"kid\":\"Y2xlYXJrZXlrZXlpZDAzAy\"," \ + // key too long + "\"k\":\"V2lubmllIHRoZSBwb29oIVdpbm5pZSB0aGUgcG9vaCE=\"" \ + "}]" \ + "}"; + const size_t kKeyTooLongResponseSize = keyTooLongResponse.size(); + + hidl_vec invalidResponse; + invalidResponse.resize(kKeyTooLongResponseSize); + memcpy(invalidResponse.data(), keyTooLongResponse.c_str(), kKeyTooLongResponseSize); + decryptWithInvalidKeys(invalidResponse, iv, noPattern, subSamples); +} + +/** + * Instantiate the set of test cases for each vendor module + */ + +INSTANTIATE_TEST_CASE_P( + DrmHalTestClearkey, DrmHalTest, + testing::Values("clearkey")); + +INSTANTIATE_TEST_CASE_P( + DrmHalTestClearkeyExtended, DrmHalClearkeyTest, + testing::Values("clearkey")); + +INSTANTIATE_TEST_CASE_P( + DrmHalTestVendor, DrmHalTest, + testing::ValuesIn(DrmHalTest::gVendorModules->getPathList())); + +int main(int argc, char** argv) { +#if defined(__LP64__) + const char* kModulePath = "/data/local/tmp/64/lib"; +#else + const char* kModulePath = "/data/local/tmp/32/lib"; +#endif + DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath); + if (DrmHalTest::gVendorModules->getPathList().size() == 0) { + std::cerr << "WARNING: No vendor modules found in " << kModulePath << + ", all vendor tests will be skipped" << std::endl; + } + ::testing::AddGlobalTestEnvironment(DrmHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + DrmHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} diff --git a/drm/1.2/vts/functional/vendor_modules.cpp b/drm/1.2/vts/functional/vendor_modules.cpp new file mode 100644 index 0000000000..efcb90a91a --- /dev/null +++ b/drm/1.2/vts/functional/vendor_modules.cpp @@ -0,0 +1,72 @@ +/* + * 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 "drm-vts-vendor-modules" + +#include +#include +#include +#include +#include +#include + +#include "vendor_modules.h" + +using std::string; +using std::vector; +using std::unique_ptr; +using ::android::String8; +using ::android::hardware::drm::V1_0::helper::SharedLibrary; + +namespace drm_vts { +void VendorModules::scanModules(const std::string &directory) { + DIR* dir = opendir(directory.c_str()); + if (dir == NULL) { + ALOGE("Unable to open drm VTS vendor directory %s", directory.c_str()); + } else { + struct dirent* entry; + while ((entry = readdir(dir))) { + ALOGD("checking file %s", entry->d_name); + string fullpath = directory + "/" + entry->d_name; + if (endsWith(fullpath, ".so")) { + mPathList.push_back(fullpath); + } + } + closedir(dir); + } +} + +DrmHalVTSVendorModule* VendorModules::getModule(const string& path) { + if (mOpenLibraries.find(path) == mOpenLibraries.end()) { + auto library = std::make_unique(String8(path.c_str())); + if (!library) { + ALOGE("failed to map shared library %s", path.c_str()); + return NULL; + } + mOpenLibraries[path] = std::move(library); + } + const unique_ptr& library = mOpenLibraries[path]; + void* symbol = library->lookup("vendorModuleFactory"); + if (symbol == NULL) { + ALOGE("getVendorModule failed to lookup 'vendorModuleFactory' in %s: " + "%s", path.c_str(), library->lastError()); + return NULL; + } + typedef DrmHalVTSVendorModule* (*ModuleFactory)(); + ModuleFactory moduleFactory = reinterpret_cast(symbol); + return (*moduleFactory)(); +} +}; diff --git a/drm/1.2/vts/functional/vendor_modules.h b/drm/1.2/vts/functional/vendor_modules.h new file mode 100644 index 0000000000..9b730adcd9 --- /dev/null +++ b/drm/1.2/vts/functional/vendor_modules.h @@ -0,0 +1,73 @@ +/* + * 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 VENDOR_MODULES_H +#define VENDOR_MODULES_H + +#include +#include +#include + +#include + +using ::android::hardware::drm::V1_0::helper::SharedLibrary; + +class DrmHalVTSVendorModule; + +namespace drm_vts { +class VendorModules { + public: + /** + * Initialize with a file system path where the shared libraries + * are to be found. + */ + explicit VendorModules(const std::string& dir) { + scanModules(dir); + } + ~VendorModules() {} + + /** + * Retrieve a DrmHalVTSVendorModule given its full path. The + * getAPIVersion method can be used to determine the versioned + * subclass type. + */ + DrmHalVTSVendorModule* getModule(const std::string& path); + + /** + * Return the list of paths to available vendor modules. + */ + std::vector getPathList() const {return mPathList;} + + private: + std::vector mPathList; + std::map> mOpenLibraries; + + /** + * Scan the list of paths to available vendor modules. + */ + void scanModules(const std::string& dir); + + inline bool endsWith(const std::string& str, const std::string& suffix) const { + if (suffix.size() > str.size()) return false; + return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin()); + } + + VendorModules(const VendorModules&) = delete; + void operator=(const VendorModules&) = delete; +}; +}; + +#endif // VENDOR_MODULES_H diff --git a/gnss/1.0/IGnss.hal b/gnss/1.0/IGnss.hal index 602c615af9..d32bc63940 100644 --- a/gnss/1.0/IGnss.hal +++ b/gnss/1.0/IGnss.hal @@ -75,8 +75,13 @@ interface IGnss { }; /** - * Opens the interface and provides the callback routines - * to the implementation of this interface. + * Opens the interface and provides the callback routines to the implementation of this + * interface. + * + * The framework calls this method to instruct the GPS engine to prepare for serving requests + * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the + * framework upon successful return from this method until cleanup() method is called to + * close this interface. * * @param callback Callback interface for IGnss. * @@ -105,6 +110,18 @@ interface IGnss { /** * Closes the interface. + * + * The cleanup() method is called by the framework to tell the GNSS HAL implementation to + * not expect any GNSS requests in the immediate future - e.g. this may be called when + * location is disabled by a user setting or low battery conditions. The GNSS HAL + * implementation must immediately stop responding to any existing requests until the + * setCallback() method is called again and the requests are re-initiated by the framework. + * + * After this method is called, the GNSS HAL implementation may choose to modify GNSS hardware + * states to save power. It is expected that when setCallback() method is called again to + * reopen this interface, to serve requests, there may be some minor delays in GNSS response + * requests as hardware readiness states are restored, not to exceed those that occur on normal + * device boot up. */ cleanup(); @@ -153,7 +170,7 @@ interface IGnss { * @param mode Parameter must be one of MS_BASED or STANDALONE. * It is allowed by the platform (and it is recommended) to fallback to * MS_BASED if MS_ASSISTED is passed in, and MS_BASED is supported. - * @recurrence GNSS postion recurrence value, either periodic or single. + * @recurrence GNSS position recurrence value, either periodic or single. * @param minIntervalMs Represents the time between fixes in milliseconds. * @param preferredAccuracyMeters Represents the requested fix accuracy in meters. * @param preferredTimeMs Represents the requested time to first fix in milliseconds. diff --git a/gnss/1.1/IGnss.hal b/gnss/1.1/IGnss.hal index 672f74236d..3400807d23 100644 --- a/gnss/1.1/IGnss.hal +++ b/gnss/1.1/IGnss.hal @@ -29,6 +29,11 @@ interface IGnss extends @1.0::IGnss { * Opens the interface and provides the callback routines to the implementation of this * interface. * + * The framework calls this method to instruct the GPS engine to prepare for serving requests + * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the + * framework upon successful return from this method until cleanup() method is called to + * close this interface. + * * @param callback Callback interface for IGnss. * * @return success Returns true on success. @@ -42,7 +47,7 @@ interface IGnss extends @1.0::IGnss { * @param mode Parameter must be one of MS_BASED or STANDALONE. It is allowed by the platform * (and it is recommended) to fallback to MS_BASED if MS_ASSISTED is passed in, and MS_BASED * is supported. - * @param recurrence GNSS postion recurrence value, either periodic or single. + * @param recurrence GNSS position recurrence value, either periodic or single. * @param minIntervalMs Represents the time between fixes in milliseconds. * @param preferredAccuracyMeters Represents the requested fix accuracy in meters. * @param preferredTimeMs Represents the requested time to first fix in milliseconds. diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp index 44aed2b069..8c3aac4278 100644 --- a/gnss/1.1/default/Android.bp +++ b/gnss/1.1/default/Android.bp @@ -18,4 +18,7 @@ cc_binary { "android.hardware.gnss@1.1", "android.hardware.gnss@1.0", ], + static_libs: [ + "android.hardware.gnss@common-default-lib", + ], } diff --git a/gnss/1.1/default/Gnss.cpp b/gnss/1.1/default/Gnss.cpp index bbf1cd31de..4abe707d4a 100644 --- a/gnss/1.1/default/Gnss.cpp +++ b/gnss/1.1/default/Gnss.cpp @@ -4,9 +4,9 @@ #include #include "Gnss.h" -#include "GnssConstants.h" #include "GnssDebug.h" #include "GnssMeasurement.h" +#include "Utils.h" namespace android { namespace hardware { @@ -14,6 +14,7 @@ namespace gnss { namespace V1_1 { namespace implementation { +using ::android::hardware::gnss::common::Utils; using GnssSvFlags = IGnssCallback::GnssSvFlags; const uint32_t MIN_INTERVAL_MILLIS = 100; @@ -43,7 +44,7 @@ Return Gnss::start() { auto svStatus = this->getMockSvStatus(); this->reportSvStatus(svStatus); - auto location = this->getMockLocation(); + auto location = Utils::getMockLocation(); this->reportLocation(location); std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs)); @@ -193,44 +194,17 @@ Return Gnss::injectBestLocation(const GnssLocation&) { return true; } -Return Gnss::getMockLocation() const { - GnssLocation location = {.gnssLocationFlags = 0xFF, - .latitudeDegrees = kMockLatitudeDegrees, - .longitudeDegrees = kMockLongitudeDegrees, - .altitudeMeters = kMockAltitudeMeters, - .speedMetersPerSec = kMockSpeedMetersPerSec, - .bearingDegrees = kMockBearingDegrees, - .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters, - .verticalAccuracyMeters = kMockVerticalAccuracyMeters, - .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond, - .bearingAccuracyDegrees = kMockBearingAccuracyDegrees, - .timestamp = kMockTimestamp}; - return location; -} - -Return Gnss::getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz, - float elevationDegrees, float azimuthDegrees) const { - GnssSvInfo svInfo = {.svid = svid, - .constellation = type, - .cN0Dbhz = cN0DbHz, - .elevationDegrees = elevationDegrees, - .azimuthDegrees = azimuthDegrees, - .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA | - GnssSvFlags::HAS_ALMANAC_DATA}; - return svInfo; -} - Return Gnss::getMockSvStatus() const { std::unique_lock lock(mGnssConfiguration->getMutex()); GnssSvInfo mockGnssSvInfoList[] = { - getSvInfo(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5), - getSvInfo(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5), - getSvInfo(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0), - getSvInfo(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0), - getSvInfo(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0), - getSvInfo(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0), - getSvInfo(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0), - getSvInfo(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)}; + Utils::getSvInfo(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5), + Utils::getSvInfo(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5), + Utils::getSvInfo(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0), + Utils::getSvInfo(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0), + Utils::getSvInfo(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0), + Utils::getSvInfo(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0), + Utils::getSvInfo(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0), + Utils::getSvInfo(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)}; GnssSvStatus svStatus = {.numSvs = sizeof(mockGnssSvInfoList) / sizeof(GnssSvInfo)}; for (uint32_t i = 0; i < svStatus.numSvs; i++) { diff --git a/gnss/1.1/default/Gnss.h b/gnss/1.1/default/Gnss.h index 99af34cdcf..21b66a213f 100644 --- a/gnss/1.1/default/Gnss.h +++ b/gnss/1.1/default/Gnss.h @@ -84,10 +84,7 @@ struct Gnss : public IGnss { // Methods from ::android::hidl::base::V1_0::IBase follow. private: - Return getMockLocation() const; Return getMockSvStatus() const; - Return getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz, - float elevationDegress, float azimuthDegress) const; Return reportLocation(const GnssLocation&) const; Return reportSvStatus(const GnssSvStatus&) const; diff --git a/gnss/1.1/default/GnssDebug.cpp b/gnss/1.1/default/GnssDebug.cpp index 62870e4c53..471ed2421d 100644 --- a/gnss/1.1/default/GnssDebug.cpp +++ b/gnss/1.1/default/GnssDebug.cpp @@ -18,9 +18,11 @@ #include -#include "GnssConstants.h" +#include "Constants.h" #include "GnssDebug.h" +using namespace ::android::hardware::gnss::common; + namespace android { namespace hardware { namespace gnss { diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp index 9892eca129..cc34290fa8 100644 --- a/gnss/1.1/vts/functional/Android.bp +++ b/gnss/1.1/vts/functional/Android.bp @@ -25,6 +25,10 @@ cc_test { static_libs: [ "android.hardware.gnss@1.0", "android.hardware.gnss@1.1", + "android.hardware.gnss@common-vts-lib", + ], + shared_libs: [ + "android.hardware.gnss.measurement_corrections@1.0", ], test_suites: ["general-tests"], } diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp index 433f5cb4ea..381ac1d3af 100644 --- a/gnss/1.1/vts/functional/gnss_hal_test.cpp +++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp @@ -17,8 +17,10 @@ #define LOG_TAG "GnssHalTest" #include - #include +#include "Utils.h" + +using ::android::hardware::gnss::common::Utils; // Implementations for the main test class for GNSS HAL GnssHalTest::GnssHalTest() @@ -124,69 +126,7 @@ bool GnssHalTest::StartAndCheckFirstLocation() { void GnssHalTest::CheckLocation(GnssLocation& location, bool check_speed) { bool check_more_accuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017); - EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG); - EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE); - if (check_speed) { - EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED); - } - EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY); - // New uncertainties available in O must be provided, - // at least when paired with modern hardware (2017+) - if (check_more_accuracies) { - EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY); - if (check_speed) { - EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY); - if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) { - EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY); - } - } - } - EXPECT_GE(location.latitudeDegrees, -90.0); - EXPECT_LE(location.latitudeDegrees, 90.0); - EXPECT_GE(location.longitudeDegrees, -180.0); - EXPECT_LE(location.longitudeDegrees, 180.0); - EXPECT_GE(location.altitudeMeters, -1000.0); - EXPECT_LE(location.altitudeMeters, 30000.0); - if (check_speed) { - EXPECT_GE(location.speedMetersPerSec, 0.0); - EXPECT_LE(location.speedMetersPerSec, 5.0); // VTS tests are stationary. - - // Non-zero speeds must be reported with an associated bearing - if (location.speedMetersPerSec > 0.0) { - EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING); - } - } - - /* - * Tolerating some especially high values for accuracy estimate, in case of - * first fix with especially poor geometry (happens occasionally) - */ - EXPECT_GT(location.horizontalAccuracyMeters, 0.0); - EXPECT_LE(location.horizontalAccuracyMeters, 250.0); - - /* - * Some devices may define bearing as -180 to +180, others as 0 to 360. - * Both are okay & understandable. - */ - if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) { - EXPECT_GE(location.bearingDegrees, -180.0); - EXPECT_LE(location.bearingDegrees, 360.0); - } - if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) { - EXPECT_GT(location.verticalAccuracyMeters, 0.0); - EXPECT_LE(location.verticalAccuracyMeters, 500.0); - } - if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) { - EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0); - EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0); - } - if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) { - EXPECT_GT(location.bearingAccuracyDegrees, 0.0); - EXPECT_LE(location.bearingAccuracyDegrees, 360.0); - } - - // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+) - EXPECT_GT(location.timestamp, 1.48e12); + Utils::checkLocation(location, check_speed, check_more_accuracies); } void GnssHalTest::StartAndCheckLocations(int count) { diff --git a/gnss/2.0/Android.bp b/gnss/2.0/Android.bp new file mode 100644 index 0000000000..db5075f862 --- /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", + "IGnssBatching.hal", + "IGnssBatchingCallback.hal", + "IGnssCallback.hal", + "IGnssConfiguration.hal", + "IGnssDebug.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", + ], + 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 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..9935bf914d --- /dev/null +++ b/gnss/2.0/IGnss.hal @@ -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. + */ + +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 GnssLocation; +import IGnssCallback; +import IGnssConfiguration; +import IGnssDebug; +import IGnssMeasurement; +import IAGnss; +import IAGnssRil; +import IGnssBatching; + +/** + * 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. + * + * The framework calls this method to instruct the GPS engine to prepare for serving requests + * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the + * framework upon successful return from this method until cleanup() method is called to + * close 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 IGnssDebug interface. + * + * @return gnssDebugIface Handle to the IGnssDebug interface. + */ + getExtensionGnssDebug_2_0() generates (IGnssDebug gnssDebugIface); + + /** + * 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(), getExtensionGnssMeasurement_1_1(), and + * getExtensionGnssMeasurement_2_0() methods must return a non-null handle, and the other + * methods 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); + + /** + * This method returns the IGnssBatching interface. + * + * @return batchingIface Handle to the IGnssBatching interface. + */ + getExtensionGnssBatching_2_0() generates (IGnssBatching batchingIface); + + /** + * Injects current location from the best available location provider. + * + * Unlike injectLocation, this method may inject a recent GNSS location from the HAL + * implementation, if that is the best available location known to the framework. + * + * @param location Location information from the best available location provider. + * + * @return success Returns true if successful. + */ + injectBestLocation_2_0(GnssLocation location) generates (bool success); +}; \ No newline at end of file diff --git a/gnss/2.0/IGnssBatching.hal b/gnss/2.0/IGnssBatching.hal new file mode 100644 index 0000000000..961fa69548 --- /dev/null +++ b/gnss/2.0/IGnssBatching.hal @@ -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. + */ + +package android.hardware.gnss@2.0; + +import @1.0::IGnssBatching; +import IGnssBatchingCallback; + +/** + * Extended interface for GNSS Batching support. + * + * If this interface is supported, this batching request must be able to run in + * parallel with, or without, non-batched location requested by the + * IGnss start() & stop() - i.e. both requests must be handled independently, + * and not interfere with each other. + * + * For example, if a 1Hz continuous output is underway on the IGnssCallback, + * due to an IGnss start() operation, + * and then a IGnssBatching start() is called for a location every 10 + * seconds, the newly added batching request must not disrupt the 1Hz + * continuous location output on the IGnssCallback. + * + * As with GNSS Location outputs, source of location must be GNSS satellite + * measurements, optionally using interial and baro sensors to improve + * relative motion filtering. No additional absolute positioning information, + * such as WiFi derived location, may be mixed with the GNSS information. + */ +interface IGnssBatching extends @1.0::IGnssBatching { + /** + * Opens the interface and provides the callback routines + * to the implementation of this interface. + * + * @param callback Callback interface for IGnssBatching. + * + * @return success Returns true on success. + */ + init_2_0(IGnssBatchingCallback callback) generates (bool success); +}; \ No newline at end of file diff --git a/gnss/2.0/IGnssBatchingCallback.hal b/gnss/2.0/IGnssBatchingCallback.hal new file mode 100644 index 0000000000..4f8b4ecbba --- /dev/null +++ b/gnss/2.0/IGnssBatchingCallback.hal @@ -0,0 +1,36 @@ +/* + * 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.gnss@2.0; + +/** The callback interface to report measurements from the HAL. */ +interface IGnssBatchingCallback { + /** + * Called when a batch of locations is output, by various means, including + * a flush request, as well as the buffer becoming full (if appropriate option + * is set.) + * + * All locations returned by this callback must be cleared from the hardware + * buffer, such the sequential calls of this callback do not return any + * redundant locations. (Same lat/lon, at a new time, is acceptable.) + * + * The GnssLocation struct in gnss@2.0 is extended to include elapsed realtime + * information. + * + * @param locations GNSS Location information from HAL. + */ + gnssLocationBatchCb(vec locations); +}; diff --git a/gnss/2.0/IGnssCallback.hal b/gnss/2.0/IGnssCallback.hal new file mode 100644 index 0000000000..d6db9cce11 --- /dev/null +++ b/gnss/2.0/IGnssCallback.hal @@ -0,0 +1,101 @@ +/* + * 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; +import GnssLocation; +import GnssConstellationType; + +/** + * This 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 low power mode */ + LOW_POWER_MODE = 1 << 8, + /** GNSS supports blacklisting satellites */ + SATELLITE_BLACKLIST = 1 << 9, + /** GNSS supports measurement corrections */ + MEASUREMENT_CORRECTIONS = 1 << 10 + }; + + /** + * Callback to inform framework of the GNSS HAL implementation's capabilities. + * + * @param capabilities Capability parameter is a bit field of the Capabilities enum. + */ + gnssSetCapabilitiesCb_2_0(bitfield capabilities); + + /** + * Called when a GNSS location is available. + * + * @param location Location information from HAL. + */ + gnssLocationCb_2_0(GnssLocation location); + + /** + * Callback for requesting Location. + * + * HAL implementation must call this when it wants the framework to provide locations to assist + * with GNSS HAL operation, for example, to assist with time to first fix, error recovery, or to + * supplement GNSS location for other clients of the GNSS HAL. + * + * If a request is made with independentFromGnss set to true, the framework must avoid + * providing locations derived from GNSS locations (such as "fused" location), to help improve + * information independence for situations such as error recovery. + * + * In response to this method call, GNSS HAL can expect zero, one, or more calls to + * IGnss::injectLocation or IGnss::injectBestLocation, dependent on availability of location + * from other sources, which may happen at some arbitrary delay. Generally speaking, HAL + * implementations must be able to handle calls to IGnss::injectLocation or + * IGnss::injectBestLocation at any time. + * + * @param independentFromGnss True if requesting a location that is independent from GNSS. + * @param isUserEmergency True if the location request is for delivery of this location to an + * emergency services endpoint, during a user-initiated emergency session (e.g. + * during-call to E911, or up to 5 minutes after end-of-call or text to E911). + */ + gnssRequestLocationCb_2_0(bool independentFromGnss, bool isUserEmergency); + + /** Extends a GnssSvInfo, replacing the GnssConstellationType. */ + struct GnssSvInfo { + /** + * GNSS satellite information for a single satellite and frequency. + * + * In this version of the HAL, the field 'constellation' in the v1_0 struct is deprecated, + * and is no longer used by the framework. The constellation type is instead reported in + * @2.0::IGnssCallback.GnssSvInfo.constellation. + */ + @1.0::IGnssCallback.GnssSvInfo v1_0; + + /** Defines the constellation of the given SV. */ + GnssConstellationType constellation; + }; + + /** + * Callback for the HAL to pass a vector of GnssSvInfo back to the client. + * + * @param svInfo SV status information from HAL. + */ + gnssSvStatusCb_2_0(vec svInfoList); +}; 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 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/IGnssDebug.hal b/gnss/2.0/IGnssDebug.hal new file mode 100644 index 0000000000..a3138ba6da --- /dev/null +++ b/gnss/2.0/IGnssDebug.hal @@ -0,0 +1,66 @@ +/* + * 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.gnss@2.0; + +import @1.0::IGnssDebug; + +/** Extended interface for DEBUG support. */ +interface IGnssDebug extends @1.0::IGnssDebug { + + /** Extending SatelliteData, replacing the GnssConstellationType. */ + struct SatelliteData { + /** + * GNSS Satellite info. + * + * In this version of the HAL, the field 'constellation' in the v1_0 struct is deprecated, + * and is no longer used by the framework. The constellation type is instead reported in + * @2.0::IGnssDebug.SatelliteData.constellation. + */ + @1.0::IGnssDebug.SatelliteData v1_0; + + /** Defines the constellation type of the given SV. */ + GnssConstellationType constellation; + }; + + /** + * Provides a set of debug information that is filled by the GNSS chipset when the method + * getDebugData() is invoked. + */ + struct DebugData { + /** Current best known position. */ + @1.0::IGnssDebug.PositionDebug position; + + /** Current best know time estimate. */ + @1.0::IGnssDebug.TimeDebug time; + + /** + * Provides a list of the available satellite data, for all + * satellites and constellations the device can track, + * including GnssConstellationType UNKNOWN. + */ + vec satelliteDataArray; + }; + + /** + * This methods requests position, time and satellite ephemeris debug information from the HAL. + * + * @return ret debugData information from GNSS Hal that contains the current best known + * position, best known time estimate and a complete list of constellations that the device can + * track. + */ + getDebugData_2_0() generates (DebugData debugData); +}; 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..e055f7aa45 --- /dev/null +++ b/gnss/2.0/IGnssMeasurementCallback.hal @@ -0,0 +1,481 @@ +/* + * 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; +import ElapsedRealtime; +import GnssConstellationType; + +/** The callback interface to report measurements from the HAL. */ +interface IGnssMeasurementCallback extends @1.1::IGnssMeasurementCallback { + + /** + * Flags indicating the GNSS measurement state. + * + *

The expected behavior here is for GNSS HAL to set all the flags that apply. For example, + * if the state for a satellite is only C/A code locked and bit synchronized, and there is still + * millisecond ambiguity, the state must be set as: + * + * STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_MSEC_AMBIGUOUS + * + *

If GNSS is still searching for a satellite, the corresponding state must be set to + * STATE_UNKNOWN(0). + * + *

In @2.0::IGnssMeasurementCallback.GnssMeasurement, v1_1.v1_0.receivedSvTimeInNs, the + * received satellite time, is relative to the beginning of the system week for all + * constellations except for Glonass where it is relative to the beginning of the Glonass system + * day. + * + *

The table below indicates the valid range of the received GNSS satellite time. These + * ranges depend on the constellation and code being tracked and the state of the tracking + * algorithms given by the getState method. If the state flag is set, then the valid measurement + * range is zero to the value in the table. The state flag with the widest range indicates the + * range of the received GNSS satellite time value. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * GPS/QZSSGLNSBDSGALSBAS
State FlagL1 C/AL5IL5QL1OFB1I (D1)B1I  (D2)E1BE1CE5AQL1 C/A
+ * STATE_UNKNOWN + * 0000000000
+ * STATE_CODE_LOCK + * 1 ms1 ms1 ms1 ms1 ms1 ms--1 ms1 ms
+ * STATE_SYMBOL_SYNC + * 20 ms (optional)10 ms1 ms (optional)10 ms20 ms (optional)2 ms4 ms (optional)4 ms (optional)1 ms (optional)2 ms
+ * STATE_BIT_SYNC + * 20 ms20 ms1 ms (optional)20 ms20 ms-8 ms-1 ms (optional)4 ms
+ * STATE_SUBFRAME_SYNC + * 6s6s-2 s6 s---100 ms-
+ * STATE_TOW_DECODED + * 1 week-1 day1 week1 week-1 week
+ * STATE_TOW_KNOWN + * 1 week1 day1 week1 week1 week
+ * STATE_GLO_STRING_SYNC + * ---2 s------
+ * STATE_GLO_TOD_DECODED + * ---1 day------
+ * STATE_GLO_TOD_KNOWN + * ---1 day------
+ * STATE_BDS_D2_BIT_SYNC + * -----2 ms----
+ * STATE_BDS_D2_SUBFRAME_SYNC + * -----600 ms----
+ * STATE_GAL_E1BC_CODE_LOCK + * ------4 ms4 ms--
+ * STATE_GAL_E1C_2ND_CODE_LOCK + * -------100 ms--
+ * STATE_2ND_CODE_LOCK + * -10 ms (optional)20 ms----100 ms (optional)100 ms-
+ * STATE_GAL_E1B_PAGE_SYNC + * ------2 s---
+ * STATE_SBAS_SYNC + * ---------1 s
+ * + *

Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has + * been determined from other sources. If TOW decoded is set then TOW Known must also be set. + * + *

Note well: if there is any ambiguity in integer millisecond, STATE_MSEC_AMBIGUOUS must be + * set accordingly, in the 'state' field. This value must be populated if 'state' != + * STATE_UNKNOWN. + * + *

Note on optional flags: + *

    + *
  • For L1 C/A and B1I, STATE_SYMBOL_SYNC is optional since the symbol length is the + * same as the bit length. + *
  • For L5Q and E5aQ, STATE_BIT_SYNC and STATE_SYMBOL_SYNC are optional since they are + * implied by STATE_CODE_LOCK. + *
  • STATE_2ND_CODE_LOCK for L5I is optional since it is implied by STATE_SYMBOL_SYNC. + *
  • STATE_2ND_CODE_LOCK for E1C is optional since it is implied by + * STATE_GAL_E1C_2ND_CODE_LOCK. + *
  • For E1B and E1C, STATE_SYMBOL_SYNC is optional, because it is implied by + * STATE_GAL_E1BC_CODE_LOCK. + *
+ * + */ + @export(name="", value_prefix="GNSS_MEASUREMENT_") + enum GnssMeasurementState : uint32_t { + STATE_UNKNOWN = 0, + STATE_CODE_LOCK = 1 << 0, + STATE_BIT_SYNC = 1 << 1, + STATE_SUBFRAME_SYNC = 1 << 2, + STATE_TOW_DECODED = 1 << 3, + STATE_MSEC_AMBIGUOUS = 1 << 4, + STATE_SYMBOL_SYNC = 1 << 5, + STATE_GLO_STRING_SYNC = 1 << 6, + STATE_GLO_TOD_DECODED = 1 << 7, + STATE_BDS_D2_BIT_SYNC = 1 << 8, + STATE_BDS_D2_SUBFRAME_SYNC = 1 << 9, + STATE_GAL_E1BC_CODE_LOCK = 1 << 10, + STATE_GAL_E1C_2ND_CODE_LOCK = 1 << 11, + STATE_GAL_E1B_PAGE_SYNC = 1 << 12, + STATE_SBAS_SYNC = 1 << 13, + STATE_TOW_KNOWN = 1 << 14, + STATE_GLO_TOD_KNOWN = 1 << 15, + STATE_2ND_CODE_LOCK = 1 << 16, + }; + + /** + * Extends a GNSS Measurement, adding a GnssMeasurementCodeType, a GnssMeasurementState, and + * replacing the GnssConstellationType. + */ + 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. + * + * In this version of the HAL, the field 'state' in the v1_1.v1_0 struct is deprecated, and + * is no longer used by the framework. The satellite sync state is instead reported in + * @2.0::IGnssMeasurementCallback.GnssMeasurement.state. + * + * In this version of the HAL, the field 'constellation' in the v1_1.v1_0 struct is + * deprecated, and is no longer used by the framework. The constellation type is instead + * reported in @2.0::IGnssMeasurementCallback.GnssMeasurement.constellation. + */ + @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 pseudorange measurements. + * + * Value "A" represents GALILEO E1A, GALILEO E6A, IRNSS L5A, IRNSS SA. + * + * Value "B" represents GALILEO E1B, GALILEO E6B, IRNSS L5B, IRNSS SB. + * + * Value "C" represents 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. + * + * Value "I" represents 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. + * + * Value "L" represents GPS L1C (P), GPS L2C (L), QZSS L1C (P), QZSS L2C (L), LEX(6) L. + * + * Value "M" represents GPS L1M, GPS L2M. + * + * Value "N" represents GPS L1 codeless, GPS L2 codeless. + * + * Value "P" represents GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P. + * + * Value "Q" represents 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. + * + * Value "S" represents GPS L1C (D), GPS L2C (M), QZSS L1C (D), QZSS L2C (M), LEX(6) S. + * + * Value "W" represents GPS L1 Z-tracking, GPS L2 Z-tracking. + * + * Value "X" represents 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). + * + * Value "Y" represents GPS L1Y, GPS L2Y. + * + * Value "Z" represents GALILEO E1 (A+B+C), GALILEO E6 (A+B+C), QZSS L1-SAIF. + * + * Value "UNKNOWN" represents the GNSS Measurement's code type is unknown. + * + * This is used to specify the observation descriptor defined in GNSS Observation Data File + * Header Section Description in the RINEX standard (Version 3.XX). In RINEX Version 3.03, + * in Appendix Table A2 Attributes are listed as uppercase letters (for instance, "A" for + * "A channel"). In the future, if for instance a code "G" was added in the official RINEX + * standard, "G" could be specified here. + */ + string codeType; + + /** + * Per satellite sync state. It represents the current sync state for the associated + * satellite. + * + * Based on the sync state, the receivedSvTimeInNs field must be interpreted accordingly. + * + * This value is mandatory. + */ + bitfield state; + + /** + * The constellation type of the GNSS measurement. + */ + GnssConstellationType constellation; + }; + + /** + * 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 measurements; + + /** The GNSS clock time reading. */ + GnssClock clock; + + /** + * Timing information of the GNSS data synchronized with SystemClock.elapsedRealtimeNanos() + * clock. + */ + ElapsedRealtime elapsedRealtime; + }; + + /** + * 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 + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +// Methods from ::android::hardware::gnss::V2_0::IAGnss follow. +Return AGnss::setCallback(const sp&) { + // TODO implement + return Void(); +} + +Return AGnss::dataConnClosed() { + // TODO implement + return bool{}; +} + +Return AGnss::dataConnFailed() { + // TODO implement + return bool{}; +} + +Return 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 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 +#include +#include + +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 setCallback(const sp& callback) override; + Return dataConnClosed() override; + Return dataConnFailed() override; + Return setServer(V2_0::IAGnssCallback::AGnssType type, const hidl_string& hostname, + int32_t port) override; + Return 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 + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +// Methods from V1_0::IAGnssRil follow. +Return AGnssRil::setCallback(const sp&) { + // TODO implement + return Void(); +} + +Return AGnssRil::setRefLocation(const V1_0::IAGnssRil::AGnssRefLocation&) { + // TODO implement + return Void(); +} + +Return AGnssRil::setSetId(V1_0::IAGnssRil::SetIDType, const hidl_string&) { + // TODO implement + return bool{}; +} + +Return AGnssRil::updateNetworkState(bool, V1_0::IAGnssRil::NetworkType, bool) { + // TODO implement + return bool{}; +} + +Return AGnssRil::updateNetworkAvailability(bool, const hidl_string&) { + // TODO implement + return bool{}; +} + +// Methods from ::android::hardware::gnss::V2_0::IAGnssRil follow. +Return 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 +#include +#include + +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 setCallback(const sp& callback) override; + Return setRefLocation(const V1_0::IAGnssRil::AGnssRefLocation& agnssReflocation) override; + Return setSetId(V1_0::IAGnssRil::SetIDType type, const hidl_string& setid) override; + Return updateNetworkState(bool connected, V1_0::IAGnssRil::NetworkType type, + bool roaming) override; + Return updateNetworkAvailability(bool available, const hidl_string& apn) override; + + // Methods from ::android::hardware::gnss::V2_0::IAGnssRil follow. + Return 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..0fcd76495c --- /dev/null +++ b/gnss/2.0/default/Android.bp @@ -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. + */ + +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", + "GnssBatching.cpp", + "GnssMeasurement.cpp", + "GnssMeasurementCorrections.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", + ], + static_libs: [ + "android.hardware.gnss@common-default-lib", + ], +} diff --git a/gnss/2.0/default/Gnss.cpp b/gnss/2.0/default/Gnss.cpp new file mode 100644 index 0000000000..3d64fc30cc --- /dev/null +++ b/gnss/2.0/default/Gnss.cpp @@ -0,0 +1,325 @@ +/* + * 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 +#include + +#include "AGnss.h" +#include "AGnssRil.h" +#include "GnssBatching.h" +#include "GnssConfiguration.h" +#include "GnssMeasurement.h" +#include "GnssMeasurementCorrections.h" +#include "GnssVisibilityControl.h" +#include "Utils.h" + +using ::android::hardware::Status; +using ::android::hardware::gnss::common::Utils; +using ::android::hardware::gnss::measurement_corrections::V1_0::implementation:: + GnssMeasurementCorrections; +using ::android::hardware::gnss::visibility_control::V1_0::implementation::GnssVisibilityControl; + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +using GnssSvFlags = IGnssCallback::GnssSvFlags; + +sp Gnss::sGnssCallback_2_0 = nullptr; +sp Gnss::sGnssCallback_1_1 = nullptr; + +namespace { + +V2_0::GnssLocation getMockLocationV2_0() { + const ElapsedRealtime timestamp = { + .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, + .timestampNs = static_cast(::android::elapsedRealtimeNano()), + // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. + // In an actual implementation provide an estimate of the synchronization uncertainty + // or don't set the field. + .timeUncertaintyNs = 1000000}; + + V2_0::GnssLocation location = {.v1_0 = Utils::getMockLocation(), .elapsedRealtime = timestamp}; + return location; +} + +} // namespace + +Gnss::Gnss() : mMinIntervalMs(1000) {} + +Gnss::~Gnss() { + stop(); +} + +// Methods from V1_0::IGnss follow. +Return Gnss::setCallback(const sp&) { + // TODO(b/124012850): Implement function. + return bool{}; +} + +Return Gnss::start() { + if (mIsActive) { + ALOGW("Gnss has started. Restarting..."); + stop(); + } + + mIsActive = true; + mThread = std::thread([this]() { + while (mIsActive == true) { + const auto location = getMockLocationV2_0(); + this->reportLocation(location); + + std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs)); + } + }); + return true; +} + +Return Gnss::stop() { + mIsActive = false; + if (mThread.joinable()) { + mThread.join(); + } + return true; +} + +Return Gnss::cleanup() { + // TODO(b/124012850): Implement function. + return Void(); +} + +Return Gnss::injectTime(int64_t, int64_t, int32_t) { + // TODO(b/124012850): Implement function. + return bool{}; +} + +Return Gnss::injectLocation(double, double, float) { + // TODO(b/124012850): Implement function. + return bool{}; +} + +Return Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) { + // TODO(b/124012850): Implement function. + return Void(); +} + +Return Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode, + V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t, + uint32_t) { + return true; +} + +Return> Gnss::getExtensionAGnssRil() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionGnssGeofencing() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionAGnss() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionGnssNi() { + // The IGnssNi.hal interface is deprecated in 2.0. + return nullptr; +} + +Return> Gnss::getExtensionGnssMeasurement() { + // Not supported + return nullptr; +} + +Return> Gnss::getExtensionGnssNavigationMessage() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionXtra() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionGnssConfiguration() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionGnssDebug() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionGnssBatching() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +// Methods from V1_1::IGnss follow. +Return Gnss::setCallback_1_1(const sp& 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 Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode, + V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t, + uint32_t, bool) { + return true; +} + +Return> Gnss::getExtensionGnssConfiguration_1_1() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionGnssMeasurement_1_1() { + ALOGD("Gnss::getExtensionGnssMeasurement_1_1"); + return new GnssMeasurement(); +} + +Return Gnss::injectBestLocation(const V1_0::GnssLocation&) { + // TODO(b/124012850): Implement function. + return bool{}; +} + +// Methods from V2_0::IGnss follow. +Return> Gnss::getExtensionGnssConfiguration_2_0() { + return new GnssConfiguration{}; +} + +Return> Gnss::getExtensionGnssDebug_2_0() { + // TODO(b/124012850): Implement function. + return sp{}; +} + +Return> Gnss::getExtensionAGnss_2_0() { + return new AGnss{}; +} + +Return> Gnss::getExtensionAGnssRil_2_0() { + return new AGnssRil{}; +} + +Return> Gnss::getExtensionGnssMeasurement_2_0() { + ALOGD("Gnss::getExtensionGnssMeasurement_2_0"); + return new GnssMeasurement(); +} + +Return> +Gnss::getExtensionMeasurementCorrections() { + ALOGD("Gnss::getExtensionMeasurementCorrections"); + return new GnssMeasurementCorrections(); +} + +Return> Gnss::getExtensionVisibilityControl() { + ALOGD("Gnss::getExtensionVisibilityControl"); + return new GnssVisibilityControl(); +} + +Return> Gnss::getExtensionGnssBatching_2_0() { + return new GnssBatching(); +} + +Return Gnss::setCallback_2_0(const sp& callback) { + ALOGD("Gnss::setCallback_2_0"); + if (callback == nullptr) { + ALOGE("%s: Null callback ignored", __func__); + return false; + } + + sGnssCallback_2_0 = callback; + + using Capabilities = V2_0::IGnssCallback::Capabilities; + const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | + Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST; + auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(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; +} + +Return Gnss::reportLocation(const V2_0::GnssLocation& location) const { + std::unique_lock lock(mMutex); + if (sGnssCallback_2_0 == nullptr) { + ALOGE("%s: sGnssCallback 2.0 is null.", __func__); + return Void(); + } + sGnssCallback_2_0->gnssLocationCb_2_0(location); + return Void(); +} + +Return Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) { + // TODO(b/124012850): Implement function. + return bool{}; +} + +} // 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..72f77976e5 --- /dev/null +++ b/gnss/2.0/default/Gnss.h @@ -0,0 +1,114 @@ +/* + * 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 +#include +#include +#include +#include +#include + +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 GnssConstellationType = V1_0::GnssConstellationType; +using GnssLocation = V1_0::GnssLocation; +using GnssSvInfo = V1_0::IGnssCallback::GnssSvInfo; +using GnssSvStatus = V1_0::IGnssCallback::GnssSvStatus; + +struct Gnss : public IGnss { + Gnss(); + ~Gnss(); + // Methods from V1_0::IGnss follow. + Return setCallback(const sp& callback) override; + Return start() override; + Return stop() override; + Return cleanup() override; + Return injectTime(int64_t timeMs, int64_t timeReferenceMs, + int32_t uncertaintyMs) override; + Return injectLocation(double latitudeDegrees, double longitudeDegrees, + float accuracyMeters) override; + Return deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override; + Return setPositionMode(V1_0::IGnss::GnssPositionMode mode, + V1_0::IGnss::GnssPositionRecurrence recurrence, + uint32_t minIntervalMs, uint32_t preferredAccuracyMeters, + uint32_t preferredTimeMs) override; + Return> getExtensionAGnssRil() override; + Return> getExtensionGnssGeofencing() override; + Return> getExtensionAGnss() override; + Return> getExtensionGnssNi() override; + Return> getExtensionGnssMeasurement() override; + Return> getExtensionGnssNavigationMessage() override; + Return> getExtensionXtra() override; + Return> getExtensionGnssConfiguration() override; + Return> getExtensionGnssDebug() override; + Return> getExtensionGnssBatching() override; + + // Methods from V1_1::IGnss follow. + Return setCallback_1_1(const sp& callback) override; + Return 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> getExtensionGnssConfiguration_1_1() override; + Return> getExtensionGnssMeasurement_1_1() override; + Return injectBestLocation(const GnssLocation& location) override; + + // Methods from V2_0::IGnss follow. + Return> getExtensionGnssConfiguration_2_0() override; + Return> getExtensionGnssDebug_2_0() override; + Return> getExtensionAGnss_2_0() override; + Return> getExtensionAGnssRil_2_0() override; + Return> getExtensionGnssMeasurement_2_0() override; + Return setCallback_2_0(const sp& callback) override; + Return> + getExtensionMeasurementCorrections() override; + Return> getExtensionVisibilityControl() + override; + Return> getExtensionGnssBatching_2_0() override; + Return injectBestLocation_2_0(const V2_0::GnssLocation& location) override; + + private: + Return reportLocation(const V2_0::GnssLocation&) const; + static sp sGnssCallback_2_0; + static sp sGnssCallback_1_1; + std::atomic mMinIntervalMs; + std::atomic 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_GNSS_H diff --git a/gnss/2.0/default/GnssBatching.cpp b/gnss/2.0/default/GnssBatching.cpp new file mode 100644 index 0000000000..d56cdfb33f --- /dev/null +++ b/gnss/2.0/default/GnssBatching.cpp @@ -0,0 +1,70 @@ +/* + * 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 "GnssBatching" + +#include "GnssBatching.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +sp GnssBatching::sCallback = nullptr; + +// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow. +Return GnssBatching::init(const sp&) { + // TODO implement + return bool{}; +} + +Return GnssBatching::getBatchSize() { + // TODO implement + return uint16_t{}; +} + +Return GnssBatching::start(const V1_0::IGnssBatching::Options&) { + // TODO implement + return bool{}; +} + +Return GnssBatching::flush() { + // TODO implement + return Void(); +} + +Return GnssBatching::stop() { + // TODO implement + return bool{}; +} + +Return GnssBatching::cleanup() { + // TODO implement + return Void(); +} + +// Methods from V2_0::IGnssBatching follow. +Return GnssBatching::init_2_0(const sp& callback) { + sCallback = callback; + return true; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.0/default/GnssBatching.h b/gnss/2.0/default/GnssBatching.h new file mode 100644 index 0000000000..62ac580897 --- /dev/null +++ b/gnss/2.0/default/GnssBatching.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. + */ + +#pragma once + +#include +#include +#include + +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 GnssBatching : public IGnssBatching { + // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow. + Return init(const sp& callback) override; + Return getBatchSize() override; + Return start(const V1_0::IGnssBatching::Options& options) override; + Return flush() override; + Return stop() override; + Return cleanup() override; + + // Methods from V2_0::IGnssBatching follow. + Return init_2_0(const sp& callback) override; + + private: + static sp sCallback; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.0/default/GnssConfiguration.cpp b/gnss/2.0/default/GnssConfiguration.cpp new file mode 100644 index 0000000000..6bf1712aff --- /dev/null +++ b/gnss/2.0/default/GnssConfiguration.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. + */ + +#define LOG_TAG "GnssConfiguration" + +#include "GnssConfiguration.h" +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow. +Return 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 GnssConfiguration::setSuplVersion(uint32_t) { + return true; +} + +Return GnssConfiguration::setSuplMode(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setGpsLock(hidl_bitfield gpsLock) { + ALOGD("setGpsLock gpsLock: %hhu", static_cast(gpsLock)); + // Method deprecated in 2.0 and not expected to be called by the framework. + return false; +} + +Return GnssConfiguration::setLppProfile(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setGlonassPositioningProtocol(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setEmergencySuplPdn(bool) { + return true; +} + +// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow. +Return GnssConfiguration::setBlacklist( + const hidl_vec&) { + // TODO (b/122463906): Reuse 1.1 implementation. + return bool{}; +} + +// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow. +Return 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 +#include +#include + +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 setSuplEs(bool enabled) override; + Return setSuplVersion(uint32_t version) override; + Return setSuplMode(hidl_bitfield mode) override; + Return setGpsLock(hidl_bitfield lock) override; + Return setLppProfile(hidl_bitfield lppProfile) override; + Return setGlonassPositioningProtocol(hidl_bitfield protocol) override; + Return setEmergencySuplPdn(bool enable) override; + + // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow. + Return setBlacklist( + const hidl_vec& blacklist) override; + + // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow. + Return 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..93de89cdfb --- /dev/null +++ b/gnss/2.0/default/GnssMeasurement.cpp @@ -0,0 +1,167 @@ +/* + * 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 +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_0 { +namespace implementation { + +using GnssConstellationType = V2_0::GnssConstellationType; +using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags; +using GnssMeasurementState = V2_0::IGnssMeasurementCallback::GnssMeasurementState; + +sp GnssMeasurement::sCallback = nullptr; + +GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {} + +GnssMeasurement::~GnssMeasurement() { + stop(); +} + +// Methods from V1_0::IGnssMeasurement follow. +Return GnssMeasurement::setCallback( + const sp&) { + // TODO implement + return V1_0::IGnssMeasurement::GnssMeasurementStatus{}; +} + +Return GnssMeasurement::close() { + ALOGD("close"); + std::unique_lock lock(mMutex); + stop(); + sCallback = nullptr; + return Void(); +} + +// Methods from V1_1::IGnssMeasurement follow. +Return GnssMeasurement::setCallback_1_1( + const sp&, bool) { + // TODO implement + return V1_0::IGnssMeasurement::GnssMeasurementStatus{}; +} + +// Methods from V2_0::IGnssMeasurement follow. +Return GnssMeasurement::setCallback_2_0( + const sp& callback, bool) { + ALOGD("setCallback_2_0"); + std::unique_lock 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() { + ALOGD("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() { + ALOGD("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 = V1_0::GnssConstellationType::UNKNOWN, + .timeOffsetNs = 0.0, + .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 = "C", + .constellation = GnssConstellationType::GLONASS, + .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}; + + hidl_vec 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}; + + ElapsedRealtime timestamp = { + .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, + .timestampNs = static_cast(::android::elapsedRealtimeNano()), + // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. + // In an actual implementation provide an estimate of the synchronization uncertainty + // or don't set the field. + .timeUncertaintyNs = 1000000}; + + GnssData gnssData = { + .measurements = measurements, .clock = clock, .elapsedRealtime = timestamp}; + return gnssData; +} + +void GnssMeasurement::reportMeasurement(const GnssData& data) { + ALOGD("reportMeasurement()"); + std::unique_lock 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 +#include +#include +#include +#include +#include + +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 setCallback( + const sp& callback) override; + Return close() override; + + // Methods from V1_1::IGnssMeasurement follow. + Return setCallback_1_1( + const sp& callback, bool enableFullTracking) override; + + // Methods from V2_0::IGnssMeasurement follow. + Return setCallback_2_0( + const sp& callback, bool enableFullTracking) override; + + private: + void start(); + void stop(); + GnssData getMockMeasurement(); + void reportMeasurement(const GnssData&); + + static sp sCallback; + std::atomic mMinIntervalMillis; + std::atomic 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/GnssMeasurementCorrections.cpp b/gnss/2.0/default/GnssMeasurementCorrections.cpp new file mode 100644 index 0000000000..2bf5601820 --- /dev/null +++ b/gnss/2.0/default/GnssMeasurementCorrections.cpp @@ -0,0 +1,75 @@ +/* + * 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 "GnssMeasurementCorrections" + +#include "GnssMeasurementCorrections.h" +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace measurement_corrections { +namespace V1_0 { +namespace implementation { + +// Methods from V1_0::IMeasurementCorrections follow. +Return GnssMeasurementCorrections::setCorrections(const MeasurementCorrections& corrections) { + ALOGD("setCorrections"); + ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, " + "satCorrections.size: %d", + corrections.latitudeDegrees, corrections.longitudeDegrees, corrections.altitudeMeters, + corrections.horizontalPositionUncertaintyMeters, + corrections.verticalPositionUncertaintyMeters, + static_cast(corrections.toaGpsNanosecondsOfWeek), + static_cast(corrections.satCorrections.size())); + for (auto singleSatCorrection : corrections.satCorrections) { + ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f," + " epl: %f, eplUnc: %f", + static_cast(singleSatCorrection.singleSatCorrectionFlags), + static_cast(singleSatCorrection.constellation), + static_cast(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz, + singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters, + singleSatCorrection.excessPathLengthUncertaintyMeters); + ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f", + singleSatCorrection.reflectingPlane.latitudeDegrees, + singleSatCorrection.reflectingPlane.longitudeDegrees, + singleSatCorrection.reflectingPlane.altitudeMeters, + singleSatCorrection.reflectingPlane.azimuthDegrees); + } + + return true; +} + +Return GnssMeasurementCorrections::setCallback( + const sp& callback) { + using Capabilities = V1_0::IMeasurementCorrectionsCallback::Capabilities; + auto ret = + callback->setCapabilitiesCb(Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH | + Capabilities::REFLECTING_PLANE); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + return false; + } + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace measurement_corrections +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/2.0/default/GnssMeasurementCorrections.h b/gnss/2.0/default/GnssMeasurementCorrections.h new file mode 100644 index 0000000000..4339bed55d --- /dev/null +++ b/gnss/2.0/default/GnssMeasurementCorrections.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. + */ + +#pragma once + +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace measurement_corrections { +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 GnssMeasurementCorrections : public IMeasurementCorrections { + // Methods from V1_0::IMeasurementCorrections follow. + Return setCorrections(const MeasurementCorrections& corrections) override; + Return setCallback(const sp& callback) override; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace measurement_corrections +} // namespace gnss +} // namespace hardware +} // namespace android 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 + +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 GnssVisibilityControl::enableNfwLocationAccess( + const hidl_vec& 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 GnssVisibilityControl::setCallback(const sp&) { + 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 +#include +#include + +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 enableNfwLocationAccess(const hidl_vec& proxyApps) override; + Return setCallback(const sp& 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 @@ + + + android.hardware.gnss + hwbinder + 2.0 + 1.1 + + IGnss + default + + + 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 +#include +#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 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/gnss/2.0/types.hal b/gnss/2.0/types.hal new file mode 100644 index 0000000000..3865727e41 --- /dev/null +++ b/gnss/2.0/types.hal @@ -0,0 +1,99 @@ +/* + * 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::GnssLocation; + +/** Network handle type. */ +typedef uint64_t net_handle_t; + +/** + * Flags indicating the validity of the fields in ElapsedRealtime. + */ +@export(name="", value_prefix="ELAPSED_REALTIME_") +enum ElapsedRealtimeFlags : uint16_t { + /** A valid timestampNs is stored in the data structure. */ + HAS_TIMESTAMP_NS = 1 << 0, + /** A valid timeUncertaintyNs is stored in the data structure. */ + HAS_TIME_UNCERTAINTY_NS = 1 << 1, +}; + +/** + * Represents an estimate of elapsed time since boot of Android for a given event. + * + * This timestamp MUST represent the time the event happened and MUST be synchronized + * with the SystemClock.elapsedRealtimeNanos() clock. + */ +struct ElapsedRealtime { + /** + * A set of flags indicating the validity of each field in this data structure. + * + * Fields may have invalid information in them, if not marked as valid by the + * corresponding bit in flags. + */ + bitfield flags; + + /** + * Estimate of the elapsed time since boot value for the corresponding event in nanoseconds. + */ + uint64_t timestampNs; + + /** + * Estimate of the relative precision of the alignment of this SystemClock + * timestamp, with the reported measurements in nanoseconds (68% confidence). + */ + uint64_t timeUncertaintyNs; +}; + +/** Represents a location. */ +struct GnssLocation { + @1.0::GnssLocation v1_0; + + /** + * Timing information of the GNSS location synchronized with SystemClock.elapsedRealtimeNanos() + * clock. + * + * This clock information can be obtained from SystemClock.elapsedRealtimeNanos(), when the GNSS + * is attached straight to the AP/SOC. When it is attached to a separate module the timestamp + * needs to be estimated by syncing the notion of time via PTP or some other mechanism. + */ + ElapsedRealtime elapsedRealtime; +}; + +/** + * GNSS constellation type + * + * This is to specify the navigation satellite system, for example, as listed in Section 3.5 in + * RINEX Version 3.04. + */ +enum GnssConstellationType : uint8_t { + UNKNOWN = 0, + /** Global Positioning System. */ + GPS = 1, + /** Satellite-Based Augmentation System. */ + SBAS = 2, + /** Global Navigation Satellite System. */ + GLONASS = 3, + /** Quasi-Zenith Satellite System. */ + QZSS = 4, + /** BeiDou Navigation Satellite System. */ + BEIDOU = 5, + /** Galileo Navigation Satellite System. */ + GALILEO = 6, + /** Indian Regional Navigation Satellite System. */ + IRNSS = 7, +}; 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..278d87b117 --- /dev/null +++ b/gnss/2.0/vts/functional/Android.bp @@ -0,0 +1,33 @@ +// +// 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", + "android.hardware.gnss@common-vts-lib", + ], +} diff --git a/audio/common/4.0/default/HidlUtils.h b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp similarity index 56% rename from audio/common/4.0/default/HidlUtils.h rename to 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 -#include +#include "gnss_hal_test.h" -#define AUDIO_HAL_VERSION V4_0 -#include -#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..a9f858cc9d --- /dev/null +++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp @@ -0,0 +1,223 @@ +/* + * 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 +#include +#include "Utils.h" + +using ::android::hardware::gnss::common::Utils; + +// Implementations for the main test class for GNSS HAL +void GnssHalTest::SetUp() { + gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService( + GnssHidlEnvironment::Instance()->getServiceName()); + ASSERT_NE(gnss_hal_, nullptr); + + SetUpGnssCallback(); +} + +void GnssHalTest::TearDown() { + if (gnss_hal_ != nullptr) { + gnss_hal_->cleanup(); + gnss_hal_ = nullptr; + } + + // Set to nullptr to destruct the callback event queues and warn of any unprocessed events. + gnss_cb_ = nullptr; +} + +void GnssHalTest::SetUpGnssCallback() { + gnss_cb_ = new GnssCallback(); + ASSERT_NE(gnss_cb_, nullptr); + + auto result = gnss_hal_->setCallback_2_0(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_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC)); + EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC)); + EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC)); + + EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1); + EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1); + EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1); +} + +void GnssHalTest::StopAndClearLocations() { + const auto result = gnss_hal_->stop(); + + EXPECT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + /* + * Clear notify/waiting counter, allowing up till the timeout after + * the last reply for final startup messages to arrive (esp. system + * info.) + */ + while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) { + } + gnss_cb_->location_cbq_.reset(); +} + +void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) { + const int kPreferredAccuracy = 0; // Ideally perfect (matches GnssLocationProvider) + const int kPreferredTimeMsec = 0; // Ideally immediate + + const auto result = gnss_hal_->setPositionMode_1_1( + IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC, + min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode); + + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +bool GnssHalTest::StartAndCheckFirstLocation() { + const auto result = gnss_hal_->start(); + + EXPECT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + /* + * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS, + * so allow time to demodulate ephemeris over the air. + */ + const int kFirstGnssLocationTimeoutSeconds = 75; + + EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, + kFirstGnssLocationTimeoutSeconds)); + int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + EXPECT_EQ(locationCalledCount, 1); + + if (locationCalledCount > 0) { + // don't require speed on first fix + CheckLocation(gnss_cb_->last_location_, false); + return true; + } + return false; +} + +void GnssHalTest::CheckLocation(const GnssLocation_2_0& location, bool check_speed) { + const bool check_more_accuracies = + (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017); + + Utils::checkLocation(location.v1_0, check_speed, check_more_accuracies); +} + +void GnssHalTest::StartAndCheckLocations(int count) { + const int kMinIntervalMsec = 500; + const int kLocationTimeoutSubsequentSec = 2; + const bool kLowPowerMode = false; + + SetPositionMode(kMinIntervalMsec, kLowPowerMode); + + EXPECT_TRUE(StartAndCheckFirstLocation()); + + for (int i = 1; i < count; i++) { + EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, + kLocationTimeoutSubsequentSec)); + int locationCalledCount = gnss_cb_->location_cbq_.calledCount(); + EXPECT_EQ(locationCalledCount, i + 1); + // Don't cause confusion by checking details if no location yet + if (locationCalledCount > 0) { + // Should be more than 1 location by now, but if not, still don't check first fix speed + CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1); + } + } +} + +GnssHalTest::GnssCallback::GnssCallback() + : info_cbq_("system_info"), + name_cbq_("name"), + capabilities_cbq_("capabilities"), + location_cbq_("location"), + sv_info_cbq_("sv_info") {} + +Return GnssHalTest::GnssCallback::gnssSetSystemInfoCb( + const IGnssCallback_1_0::GnssSystemInfo& info) { + ALOGI("Info received, year %d", info.yearOfHw); + info_cbq_.store(info); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) { + ALOGI("Capabilities received %d", capabilities); + capabilities_cbq_.store(capabilities); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) { + ALOGI("Capabilities (v2.0) received %d", capabilities); + capabilities_cbq_.store(capabilities); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) { + ALOGI("Name received: %s", name.c_str()); + name_cbq_.store(name); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation_1_0& location) { + ALOGI("Location received"); + GnssLocation_2_0 location_v2_0; + location_v2_0.v1_0 = location; + return gnssLocationCbImpl(location_v2_0); +} + +Return GnssHalTest::GnssCallback::gnssLocationCb_2_0(const GnssLocation_2_0& location) { + ALOGI("Location (v2.0) received"); + return gnssLocationCbImpl(location); +} + +Return GnssHalTest::GnssCallback::gnssLocationCbImpl(const GnssLocation_2_0& location) { + location_cbq_.store(location); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus&) { + ALOGI("gnssSvStatusCb"); + return Void(); +} + +Return GnssHalTest::GnssCallback::gnssSvStatusCb_2_0( + const hidl_vec& svInfoList) { + ALOGI("gnssSvStatusCb_2_0. Size = %d", (int)svInfoList.size()); + sv_info_cbq_.store(svInfoList); + return Void(); +} + +Return GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_0( + const IGnssMeasurementCallback_2_0::GnssData& data) { + ALOGD("GnssMeasurement received. Size = %d", (int)data.measurements.size()); + measurement_cbq_.store(data); + return Void(); +} + +Return GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb( + uint32_t capabilities) { + ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities); + capabilities_cbq_.store(capabilities); + 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..05e37d33f7 --- /dev/null +++ b/gnss/2.0/vts/functional/gnss_hal_test.h @@ -0,0 +1,290 @@ +/* + * 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 +#include +#include + +#include +#include +#include + +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; + +using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback; +using android::hardware::gnss::V1_0::GnssLocationFlags; +using android::hardware::gnss::V2_0::IGnss; + +using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation; +using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation; + +using IGnssCallback_1_0 = android::hardware::gnss::V1_0::IGnssCallback; +using IGnssCallback_2_0 = android::hardware::gnss::V2_0::IGnssCallback; + +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(); } + + private: + GnssHidlEnvironment() {} +}; + +// The main test class for GNSS HAL. +class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override; + + virtual void TearDown() override; + + /* Producer/consumer queue for storing/retrieving callback events from GNSS HAL */ + template + class CallbackQueue { + public: + CallbackQueue(const std::string& name) : name_(name), called_count_(0){}; + ~CallbackQueue() { reset(); } + + /* Adds callback event to the end of the queue. */ + void store(const T& event); + + /* + * Removes the callack event at the front of the queue, stores it in event parameter + * and returns true. Returns false on timeout and event is not populated. + */ + bool retrieve(T& event, int timeout_seconds); + + /* Returns the number of events pending to be retrieved from the callback event queue. */ + int size() const; + + /* Returns the number of callback events received since last reset(). */ + int calledCount() const; + + /* Clears the callback event queue and resets the calledCount() to 0. */ + void reset(); + + private: + CallbackQueue(const CallbackQueue&) = delete; + CallbackQueue& operator=(const CallbackQueue&) = delete; + + std::string name_; + int called_count_; + mutable std::recursive_mutex mtx_; + std::condition_variable_any cv_; + std::deque events_; + }; + + /* Callback class for data & Event. */ + class GnssCallback : public IGnssCallback_2_0 { + public: + IGnssCallback_1_0::GnssSystemInfo last_info_; + android::hardware::hidl_string last_name_; + uint32_t last_capabilities_; + GnssLocation_2_0 last_location_; + + CallbackQueue info_cbq_; + CallbackQueue name_cbq_; + CallbackQueue capabilities_cbq_; + CallbackQueue location_cbq_; + CallbackQueue> sv_info_cbq_; + + GnssCallback(); + virtual ~GnssCallback() = default; + + // Dummy callback handlers + Return gnssStatusCb(const IGnssCallback_1_0::GnssStatusValue /* status */) override { + return Void(); + } + Return gnssNmeaCb(int64_t /* timestamp */, + const android::hardware::hidl_string& /* nmea */) override { + return Void(); + } + Return gnssAcquireWakelockCb() override { return Void(); } + Return gnssReleaseWakelockCb() override { return Void(); } + Return gnssRequestLocationCb(bool /* independentFromGnss */) override { + return Void(); + } + Return gnssRequestTimeCb() override { return Void(); } + // Actual (test) callback handlers + Return gnssNameCb(const android::hardware::hidl_string& name) override; + Return gnssLocationCb(const GnssLocation_1_0& location) override; + Return gnssSetCapabilitesCb(uint32_t capabilities) override; + Return gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) override; + Return gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus& svStatus) override; + + // New in v2.0 + Return gnssLocationCb_2_0(const GnssLocation_2_0& location) override; + Return gnssRequestLocationCb_2_0(bool /* independentFromGnss */, + bool /* isUserEmergency */) override { + return Void(); + } + Return gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override; + Return gnssSvStatusCb_2_0( + const hidl_vec& svInfoList) override; + + private: + Return gnssLocationCbImpl(const GnssLocation_2_0& location); + }; + + /* Callback class for GnssMeasurement. */ + class GnssMeasurementCallback : public IGnssMeasurementCallback_2_0 { + public: + CallbackQueue measurement_cbq_; + + GnssMeasurementCallback() : measurement_cbq_("measurement"){}; + virtual ~GnssMeasurementCallback() = default; + + // Methods from V1_0::IGnssMeasurementCallback follow. + Return GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override { + return Void(); + } + + // Methods from V1_1::IGnssMeasurementCallback follow. + Return gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override { + return Void(); + } + + // Methods from V2_0::IGnssMeasurementCallback follow. + Return gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override; + }; + + /* Callback class for GnssMeasurementCorrections. */ + class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback { + public: + uint32_t last_capabilities_; + CallbackQueue capabilities_cbq_; + + GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){}; + virtual ~GnssMeasurementCorrectionsCallback() = default; + + // Methods from V1_0::IMeasurementCorrectionsCallback follow. + Return setCapabilitiesCb(uint32_t capabilities) override; + }; + + /* + * SetUpGnssCallback: + * Set GnssCallback and verify the result. + */ + void SetUpGnssCallback(); + + /* + * StartAndCheckFirstLocation: + * Helper function to start location, and check the first one. + * + *

Note this leaves the Location request active, to enable Stop call vs. other call + * reordering tests. + * + * returns true if a location was successfully generated + */ + bool StartAndCheckFirstLocation(); + + /* + * CheckLocation: + * Helper function to vet Location fields + * + * check_speed: true if speed related fields are also verified. + */ + void CheckLocation(const GnssLocation_2_0& location, const bool check_speed); + + /* + * StartAndCheckLocations: + * Helper function to collect, and check a number of + * normal ~1Hz locations. + * + * Note this leaves the Location request active, to enable Stop call vs. other call + * reordering tests. + */ + void StartAndCheckLocations(int count); + + /* + * StopAndClearLocations: + * Helper function to stop locations, and clear any remaining notifications + */ + void StopAndClearLocations(); + + /* + * SetPositionMode: + * Helper function to set positioning mode and verify output + */ + void SetPositionMode(const int min_interval_msec, const bool low_power_mode); + + sp gnss_hal_; // GNSS HAL to call into + sp gnss_cb_; // Primary callback interface +}; + +template +void GnssHalTest::CallbackQueue::store(const T& event) { + std::unique_lock lock(mtx_); + events_.push_back(event); + ++called_count_; + lock.unlock(); + cv_.notify_all(); +} + +template +bool GnssHalTest::CallbackQueue::retrieve(T& event, int timeout_seconds) { + std::unique_lock lock(mtx_); + cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); }); + if (events_.empty()) { + return false; + } + event = events_.front(); + events_.pop_front(); + return true; +} + +template +int GnssHalTest::CallbackQueue::size() const { + std::unique_lock lock(mtx_); + return events_.size(); +} + +template +int GnssHalTest::CallbackQueue::calledCount() const { + std::unique_lock lock(mtx_); + return called_count_; +} + +template +void GnssHalTest::CallbackQueue::reset() { + std::unique_lock lock(mtx_); + if (!events_.empty()) { + ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(), + name_.c_str()); + } + events_.clear(); + called_count_ = 0; +} + +#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..155afd614b --- /dev/null +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -0,0 +1,416 @@ +/* + * 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 +#include +#include "Utils.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 IAGnssRil_1_0 = android::hardware::gnss::V1_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 IGnssBatching_V1_0 = android::hardware::gnss::V1_0::IGnssBatching; +using IGnssBatching_V2_0 = android::hardware::gnss::V2_0::IGnssBatching; + +using android::hardware::gnss::common::Utils; +using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections; +using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections; +using android::hardware::gnss::V1_0::IGnssNi; +using android::hardware::gnss::V2_0::ElapsedRealtimeFlags; +using android::hardware::gnss::V2_0::GnssConstellationType; +using android::hardware::gnss::V2_0::IGnssCallback; +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) {} + +/* + * TestGnssMeasurementExtension: + * Gets the GnssMeasurementExtension and verifies that it returns an actual extension. + */ +TEST_F(GnssHalTest, TestGnssMeasurementExtension) { + 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()); + sp iGnssMeas_2_0 = gnssMeasurement_2_0; + sp iGnssMeas_1_1 = gnssMeasurement_1_1; + sp 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 = 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 = 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 = 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. + * + * If IAGnssRil interface is supported, then 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. + */ +TEST_F(GnssHalTest, TestAGnssRilExtension) { + auto agnssRil_2_0 = gnss_hal_->getExtensionAGnssRil_2_0(); + ASSERT_TRUE(agnssRil_2_0.isOk()); + sp iAGnssRil_2_0 = agnssRil_2_0; + if (iAGnssRil_2_0 == nullptr) { + // Verify IAGnssRil 1.0 is not supported. + auto agnssRil_1_0 = gnss_hal_->getExtensionAGnssRil(); + ASSERT_TRUE(agnssRil_1_0.isOk()); + sp iAGnssRil_1_0 = agnssRil_1_0; + ASSERT_EQ(iAGnssRil_1_0, 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 = agnssRil; + if (iAGnssRil == nullptr) { + return; + } + + // Update GNSS HAL that a network has connected. + IAGnssRil_2_0::NetworkAttributes networkAttributes = { + .networkHandle = static_cast(7700664333), + .isConnected = true, + .capabilities = static_cast(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); +} + +/* + * TestGnssMeasurementFields: + * Sets a GnssMeasurementCallback, waits for a measurement, and verifies + * 1. codeType is valid, + * 2. constellation is valid. + * 3. state is valid. + */ +TEST_F(GnssHalTest, TestGnssMeasurementFields) { + const int kFirstGnssMeasurementTimeoutSeconds = 10; + + auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0(); + if (!gnssMeasurement.isOk()) { + return; + } + + sp iGnssMeasurement = gnssMeasurement; + if (iGnssMeasurement == nullptr) { + return; + } + + sp callback = new GnssMeasurementCallback(); + auto result = iGnssMeasurement->setCallback_2_0(callback, /* enableFullTracking= */ true); + ASSERT_TRUE(result.isOk()); + EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS); + + IGnssMeasurementCallback_2_0::GnssData lastMeasurement; + ASSERT_TRUE(callback->measurement_cbq_.retrieve(lastMeasurement, + kFirstGnssMeasurementTimeoutSeconds)); + EXPECT_EQ(callback->measurement_cbq_.calledCount(), 1); + ASSERT_TRUE(lastMeasurement.measurements.size() > 0); + for (auto measurement : lastMeasurement.measurements) { + // Verify CodeType is valid. + ASSERT_NE(measurement.codeType, ""); + + // Verify ConstellationType is valid. + ASSERT_TRUE(static_cast(measurement.constellation) >= + static_cast(GnssConstellationType::UNKNOWN) && + static_cast(measurement.constellation) <= + static_cast(GnssConstellationType::IRNSS)); + + // Verify State is valid. + ASSERT_TRUE( + static_cast(measurement.state) >= + static_cast(IGnssMeasurementCallback_2_0::GnssMeasurementState:: + STATE_UNKNOWN) && + static_cast(measurement.state) <= + static_cast(IGnssMeasurementCallback_2_0::GnssMeasurementState:: + STATE_2ND_CODE_LOCK)); + } + + iGnssMeasurement->close(); +} + +/* + * TestAGnssExtension: + * Gets the AGnssExtension and verifies that it returns an actual extension. + * + * If IAGnss interface is supported, then 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. + */ +TEST_F(GnssHalTest, TestAGnssExtension) { + auto agnss_2_0 = gnss_hal_->getExtensionAGnss_2_0(); + ASSERT_TRUE(agnss_2_0.isOk()); + sp iAGnss_2_0 = agnss_2_0; + if (iAGnss_2_0 == nullptr) { + // 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; + ASSERT_EQ(iAGnss_1_0, nullptr); + return; + } + + // Set SUPL server host/port + auto result = + iAGnss_2_0->setServer(IAGnssCallback_2_0::AGnssType::SUPL, "supl.google.com", 7275); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +/* + * TestGnssNiExtension_Deprecation: + * Gets the @1.0::IGnssNi extension and verifies that it is a nullptr. + */ +TEST_F(GnssHalTest, TestGnssNiExtension_Deprecation) { + // Verify IGnssNi 1.0 is not supported. + auto gnssNi = gnss_hal_->getExtensionGnssNi(); + ASSERT_TRUE(!gnssNi.isOk() || ((sp)gnssNi) == nullptr); +} + +/* + * TestGnssVisibilityControlExtension: + * Gets the GnssVisibilityControlExtension and if it is not null, verifies that it supports + * the gnss.visibility_control@1.0::IGnssVisibilityControl interface by invoking a method. + */ +TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) { + auto gnssVisibilityControl = gnss_hal_->getExtensionVisibilityControl(); + ASSERT_TRUE(gnssVisibilityControl.isOk()); + sp iGnssVisibilityControl = gnssVisibilityControl; + if (iGnssVisibilityControl == nullptr) { + return; + } + + // Set non-framework proxy apps. + hidl_vec proxyApps{"com.example.ims", "com.example.mdt"}; + auto result = iGnssVisibilityControl->enableNfwLocationAccess(proxyApps); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +/* + * TestGnssMeasurementCorrectionsCapabilities: + * If measurement corrections capability is supported, verifies that the measurement corrections + * capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH + * capability flag is set. + */ +TEST_F(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) { + if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) { + return; + } + + auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections(); + ASSERT_TRUE(measurementCorrections.isOk()); + sp iMeasurementCorrections = measurementCorrections; + ASSERT_NE(iMeasurementCorrections, nullptr); + + // Setup measurement corrections callback. + sp callback = new GnssMeasurementCorrectionsCallback(); + iMeasurementCorrections->setCallback(callback); + + const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5; + callback->capabilities_cbq_.retrieve(callback->last_capabilities_, + kMeasurementCorrectionsCapabilitiesTimeoutSeconds); + ASSERT_TRUE(callback->capabilities_cbq_.calledCount() > 0); + using Capabilities = IMeasurementCorrectionsCallback::Capabilities; + ASSERT_TRUE((callback->last_capabilities_ & + (Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH)) != 0); +} + +/* + * TestGnssMeasurementCorrections: + * If measurement corrections capability is supported, verifies that it supports the + * gnss.measurement_corrections@1.0::IMeasurementCorrections interface by invoking a method. + */ +TEST_F(GnssHalTest, TestGnssMeasurementCorrections) { + if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) { + return; + } + + // Verify IMeasurementCorrections is supported. + auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections(); + ASSERT_TRUE(measurementCorrections.isOk()); + sp iMeasurementCorrections = measurementCorrections; + ASSERT_NE(iMeasurementCorrections, nullptr); + + sp callback = new GnssMeasurementCorrectionsCallback(); + iMeasurementCorrections->setCallback(callback); + + const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5; + callback->capabilities_cbq_.retrieve(callback->last_capabilities_, + kMeasurementCorrectionsCapabilitiesTimeoutSeconds); + ASSERT_TRUE(callback->capabilities_cbq_.calledCount() > 0); + + // Set a mock MeasurementCorrections. + auto result = iMeasurementCorrections->setCorrections(Utils::getMockMeasurementCorrections()); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +/* + * TestGnssDataElapsedRealtimeFlags: + * Sets a GnssMeasurementCallback, waits for a GnssData object, and verifies the flags in member + * elapsedRealitme are valid. + */ +TEST_F(GnssHalTest, TestGnssDataElapsedRealtimeFlags) { + const int kFirstGnssMeasurementTimeoutSeconds = 10; + + auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0(); + if (!gnssMeasurement.isOk()) { + return; + } + + sp iGnssMeasurement = gnssMeasurement; + if (iGnssMeasurement == nullptr) { + return; + } + + sp callback = new GnssMeasurementCallback(); + auto result = iGnssMeasurement->setCallback_2_0(callback, /* enableFullTracking= */ true); + ASSERT_TRUE(result.isOk()); + EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS); + + IGnssMeasurementCallback_2_0::GnssData lastMeasurement; + ASSERT_TRUE(callback->measurement_cbq_.retrieve(lastMeasurement, + kFirstGnssMeasurementTimeoutSeconds)); + EXPECT_EQ(callback->measurement_cbq_.calledCount(), 1); + + ASSERT_TRUE((int)lastMeasurement.elapsedRealtime.flags <= + (int)(ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS)); + + // We expect a non-zero timestamp when set. + if (lastMeasurement.elapsedRealtime.flags & ElapsedRealtimeFlags::HAS_TIMESTAMP_NS) { + ASSERT_TRUE(lastMeasurement.elapsedRealtime.timestampNs != 0); + } + + iGnssMeasurement->close(); +} + +TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) { + StartAndCheckFirstLocation(); + + ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <= + (int)(ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS)); + + // We expect a non-zero timestamp when set. + if (gnss_cb_->last_location_.elapsedRealtime.flags & ElapsedRealtimeFlags::HAS_TIMESTAMP_NS) { + ASSERT_TRUE(gnss_cb_->last_location_.elapsedRealtime.timestampNs != 0); + } + + StopAndClearLocations(); +} + +// This test only verify that injectBestLocation_2_0 does not crash. +TEST_F(GnssHalTest, TestInjectBestLocation_2_0) { + StartAndCheckFirstLocation(); + gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_); + StopAndClearLocations(); +} + +/* + * TestGnssBatchingExtension: + * Gets the @2.0::IGnssBatching extension and verifies that it doesn't return an error. Support + * for this interface is optional. + */ +TEST_F(GnssHalTest, TestGnssBatchingExtension) { + auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0(); + ASSERT_TRUE(gnssBatching_2_0.isOk()); +} diff --git a/gnss/common/OWNERS b/gnss/common/OWNERS new file mode 100644 index 0000000000..3ed36dae8a --- /dev/null +++ b/gnss/common/OWNERS @@ -0,0 +1,7 @@ +wyattriley@google.com +gomo@google.com +smalkos@google.com +yuhany@google.com + +# VTS team +yim@google.com diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp new file mode 100644 index 0000000000..4ea97fac67 --- /dev/null +++ b/gnss/common/utils/default/Android.bp @@ -0,0 +1,33 @@ +// +// 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.gnss@common-default-lib", + vendor_available: true, + relative_install_path: "hw", + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + srcs: [ + "Utils.cpp", + ], + export_include_dirs: ["include"], + shared_libs: [ + "android.hardware.gnss@1.0", + ], +} diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp new file mode 100644 index 0000000000..b9a06e8d6d --- /dev/null +++ b/gnss/common/utils/default/Utils.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. + */ + +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags; + +GnssLocation Utils::getMockLocation() { + GnssLocation location = {.gnssLocationFlags = 0xFF, + .latitudeDegrees = kMockLatitudeDegrees, + .longitudeDegrees = kMockLongitudeDegrees, + .altitudeMeters = kMockAltitudeMeters, + .speedMetersPerSec = kMockSpeedMetersPerSec, + .bearingDegrees = kMockBearingDegrees, + .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters, + .verticalAccuracyMeters = kMockVerticalAccuracyMeters, + .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond, + .bearingAccuracyDegrees = kMockBearingAccuracyDegrees, + .timestamp = kMockTimestamp}; + return location; +} + +GnssSvInfo Utils::getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz, + float elevationDegrees, float azimuthDegrees) { + GnssSvInfo svInfo = {.svid = svid, + .constellation = type, + .cN0Dbhz = cN0DbHz, + .elevationDegrees = elevationDegrees, + .azimuthDegrees = azimuthDegrees, + .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA | + GnssSvFlags::HAS_ALMANAC_DATA}; + return svInfo; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/1.1/default/GnssConstants.h b/gnss/common/utils/default/include/Constants.h similarity index 78% rename from gnss/1.1/default/GnssConstants.h rename to gnss/common/utils/default/include/Constants.h index 9ce1a12633..000a9ec7d2 100644 --- a/gnss/1.1/default/GnssConstants.h +++ b/gnss/common/utils/default/include/Constants.h @@ -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,14 +14,15 @@ * limitations under the License. */ -#ifndef android_hardware_gnss_V1_1_GnssConstants_H_ -#define android_hardware_gnss_V1_1_GnssConstants_H_ +#ifndef android_hardware_gnss_common_Constants_H_ +#define android_hardware_gnss_common_Constants_H_ + +#include namespace android { namespace hardware { namespace gnss { -namespace V1_1 { -namespace implementation { +namespace common { const float kMockLatitudeDegrees = 37.4219999; const float kMockLongitudeDegrees = -122.0840575; @@ -34,10 +35,9 @@ const float kMockSpeedAccuracyMetersPerSecond = 1; const float kMockBearingAccuracyDegrees = 90; const int64_t kMockTimestamp = 1519930775453L; -} // namespace implementation -} // namespace V1_1 +} // namespace common } // namespace gnss } // namespace hardware } // namespace android -#endif // android_hardware_gnss_V1_1_GnssConstants_H_ +#endif // android_hardware_gnss_common_Constants_H_ diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h new file mode 100644 index 0000000000..47c88129f3 --- /dev/null +++ b/gnss/common/utils/default/include/Utils.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef android_hardware_gnss_common_default_Utils_H_ +#define android_hardware_gnss_common_default_Utils_H_ + +#include + +using GnssConstellationType = ::android::hardware::gnss::V1_0::GnssConstellationType; +using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation; +using GnssSvInfo = ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvInfo; + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct Utils { + static GnssLocation getMockLocation(); + static GnssSvInfo getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz, + float elevationDegrees, float azimuthDegrees); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_Utils_H_ diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp new file mode 100644 index 0000000000..1988171979 --- /dev/null +++ b/gnss/common/utils/vts/Android.bp @@ -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. +// + +cc_library_static { + name: "android.hardware.gnss@common-vts-lib", + vendor_available: true, + relative_install_path: "hw", + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + srcs: [ + "Utils.cpp", + ], + export_include_dirs: ["include"], + shared_libs: [ + "android.hardware.gnss@1.0", + "android.hardware.gnss.measurement_corrections@1.0", + ], + static_libs: [ + "libgtest", + ], +} diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp new file mode 100644 index 0000000000..51d3ea18d5 --- /dev/null +++ b/gnss/common/utils/vts/Utils.cpp @@ -0,0 +1,145 @@ +/* + * 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 +#include "gtest/gtest.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +using V1_0::GnssConstellationType; +using V1_0::GnssLocationFlags; + +void Utils::checkLocation(const GnssLocation& location, bool check_speed, + bool check_more_accuracies) { + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG); + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE); + if (check_speed) { + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED); + } + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY); + // New uncertainties available in O must be provided, + // at least when paired with modern hardware (2017+) + if (check_more_accuracies) { + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY); + if (check_speed) { + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY); + if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) { + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY); + } + } + } + EXPECT_GE(location.latitudeDegrees, -90.0); + EXPECT_LE(location.latitudeDegrees, 90.0); + EXPECT_GE(location.longitudeDegrees, -180.0); + EXPECT_LE(location.longitudeDegrees, 180.0); + EXPECT_GE(location.altitudeMeters, -1000.0); + EXPECT_LE(location.altitudeMeters, 30000.0); + if (check_speed) { + EXPECT_GE(location.speedMetersPerSec, 0.0); + EXPECT_LE(location.speedMetersPerSec, 5.0); // VTS tests are stationary. + + // Non-zero speeds must be reported with an associated bearing + if (location.speedMetersPerSec > 0.0) { + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING); + } + } + + /* + * Tolerating some especially high values for accuracy estimate, in case of + * first fix with especially poor geometry (happens occasionally) + */ + EXPECT_GT(location.horizontalAccuracyMeters, 0.0); + EXPECT_LE(location.horizontalAccuracyMeters, 250.0); + + /* + * Some devices may define bearing as -180 to +180, others as 0 to 360. + * Both are okay & understandable. + */ + if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) { + EXPECT_GE(location.bearingDegrees, -180.0); + EXPECT_LE(location.bearingDegrees, 360.0); + } + if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) { + EXPECT_GT(location.verticalAccuracyMeters, 0.0); + EXPECT_LE(location.verticalAccuracyMeters, 500.0); + } + if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) { + EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0); + EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0); + } + if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) { + EXPECT_GT(location.bearingAccuracyDegrees, 0.0); + EXPECT_LE(location.bearingAccuracyDegrees, 360.0); + } + + // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+) + EXPECT_GT(location.timestamp, 1.48e12); +} + +const MeasurementCorrections Utils::getMockMeasurementCorrections() { + ReflectingPlane reflectingPlane = { + .latitudeDegrees = 37.4220039, + .longitudeDegrees = -122.0840991, + .altitudeMeters = 250.35, + .azimuthDegrees = 203.0, + }; + + SingleSatCorrection singleSatCorrection1 = { + .singleSatCorrectionFlags = GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY | + GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH | + GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC | + GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE, + .constellation = GnssConstellationType::GPS, + .svid = 12, + .carrierFrequencyHz = 1.59975e+09, + .probSatIsLos = 0.50001, + .excessPathLengthMeters = 137.4802, + .excessPathLengthUncertaintyMeters = 25.5, + .reflectingPlane = reflectingPlane, + }; + SingleSatCorrection singleSatCorrection2 = { + .singleSatCorrectionFlags = GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY | + GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH | + GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC, + .constellation = GnssConstellationType::GPS, + .svid = 9, + .carrierFrequencyHz = 1.59975e+09, + .probSatIsLos = 0.873, + .excessPathLengthMeters = 26.294, + .excessPathLengthUncertaintyMeters = 10.0, + }; + + hidl_vec singleSatCorrections = {singleSatCorrection1, + singleSatCorrection2}; + MeasurementCorrections mockCorrections = { + .latitudeDegrees = 37.4219999, + .longitudeDegrees = -122.0840575, + .altitudeMeters = 30.60062531, + .horizontalPositionUncertaintyMeters = 9.23542, + .verticalPositionUncertaintyMeters = 15.02341, + .toaGpsNanosecondsOfWeek = 2935633453L, + .satCorrections = singleSatCorrections, + }; + return mockCorrections; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h new file mode 100644 index 0000000000..dce4c7b323 --- /dev/null +++ b/gnss/common/utils/vts/include/Utils.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef android_hardware_gnss_common_vts_Utils_H_ +#define android_hardware_gnss_common_vts_Utils_H_ + +#include +#include + +using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation; +using namespace android::hardware::gnss::measurement_corrections::V1_0; + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct Utils { + static void checkLocation(const GnssLocation& location, bool check_speed, + bool check_more_accuracies); + static const MeasurementCorrections getMockMeasurementCorrections(); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_vts_Utils_H_ diff --git a/gnss/measurement_corrections/1.0/Android.bp b/gnss/measurement_corrections/1.0/Android.bp new file mode 100644 index 0000000000..837cc7abca --- /dev/null +++ b/gnss/measurement_corrections/1.0/Android.bp @@ -0,0 +1,19 @@ +// 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", + "IMeasurementCorrectionsCallback.hal", + ], + interfaces: [ + "android.hardware.gnss@1.0", + "android.hidl.base@1.0", + ], + 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..1fa32f4317 --- /dev/null +++ b/gnss/measurement_corrections/1.0/IMeasurementCorrections.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.gnss.measurement_corrections@1.0; + +import IMeasurementCorrectionsCallback; + +/** + * 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); + + /** + * Opens the interface and provides the callback routines to the implementation of this + * interface. + * + * @param callback Callback interface for IMeasurementCorrections. + * + * @return success Returns true on success. + */ + setCallback(IMeasurementCorrectionsCallback callback) generates (bool success); +}; \ No newline at end of file diff --git a/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.hal b/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.hal new file mode 100644 index 0000000000..91d131192b --- /dev/null +++ b/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.hal @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.gnss.measurement_corrections@1.0; + +/** + * GNSS measurement corrections callback interface. + */ +interface IMeasurementCorrectionsCallback { + + /** + * Flags to indicate supported measurement corrections capabilities + * + * Either the LOS_SATS or the EXCESS_PATH_LENGTH capability must be supported. + */ + enum Capabilities : uint32_t { + /** GNSS supports line-of-sight satellite identification measurement corrections */ + LOS_SATS = 1 << 0, + /** GNSS supports per satellite excess-path-length measurement corrections */ + EXCESS_PATH_LENGTH = 1 << 1, + /** GNSS supports reflecting planes measurement corrections */ + REFLECTING_PLANE = 1 << 2 + }; + + /** + * Callback to inform framework the measurement correction specific capabilities of the GNSS + * HAL implementation. + * + * The GNSS HAL must call this method immediately after the framework opens the measurement + * corrections interface. + * + * @param capabilities Supported measurement corrections capabilities. It is mandatory to + * support either LOS_STATS or EXCESS_PATH_LENGTH capability. + * + */ + setCapabilitiesCb(bitfield capabilities); +}; \ No newline at end of file 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 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 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..e58e9327cb --- /dev/null +++ b/gnss/visibility_control/1.0/Android.bp @@ -0,0 +1,17 @@ +// 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 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..2cfa1d0ab7 --- /dev/null +++ b/graphics/allocator/3.0/Android.bp @@ -0,0 +1,20 @@ +// 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 buffers); +}; + diff --git a/graphics/bufferqueue/2.0/Android.bp b/graphics/bufferqueue/2.0/Android.bp new file mode 100644 index 0000000000..fd080794b8 --- /dev/null +++ b/graphics/bufferqueue/2.0/Android.bp @@ -0,0 +1,21 @@ +// 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", + ], + 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..23b360a535 --- /dev/null +++ b/graphics/bufferqueue/2.0/IGraphicBufferProducer.hal @@ -0,0 +1,659 @@ +/* + * 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. + * @return generationNumber Generation number of the buffer. If + * requestBuffer() is called immediately after dequeueBuffer() returns + * with `bufferNeedsReallocation` set to `true`, @p generationNumber must + * match the current generation number of the buffer queue previously + * set by setGenerationNumber(). Otherwise, @p generationNumber may not + * match the current generation number of the buffer queue. + */ + requestBuffer( + int32_t slot + ) generates ( + Status status, + HardwareBuffer buffer, + uint32_t generationNumber + ); + + /** + * 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. + * @return status Status of the call. + * @return slot Slot index. + * @return 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. + * @param generationNumber Generation number of the buffer. If this does not + * match the current generation number of the buffer queue, the call + * must fail with @p status set to `BAD_VALUE`. + * @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, + uint32_t generationNumber + ) 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 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 similarity index 60% rename from audio/effect/4.0/default/AcousticEchoCancelerEffect.cpp rename to 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 -#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..2c4d93b734 --- /dev/null +++ b/graphics/common/1.2/Android.bp @@ -0,0 +1,19 @@ +// 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", + ], + 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..ebea1dcc7b --- /dev/null +++ b/graphics/common/1.2/types.hal @@ -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. + */ + +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, + + /** + * JPEG APP segments format as specified by JEIDA spec + * + * The buffer must only contain APP1 (Application Marker) segment followed + * by zero or more APPn segments, as is specified by JEITA CP-3451C section 4.5.4. + * The APP1 segment optionally contains a thumbnail. The buffer will not + * contain main compressed image. + * + * This value is valid with formats: + * HAL_PIXEL_FORMAT_BLOB: JPEG APP segments optionally containing thumbnail image + * in APP1. BLOB buffer with this dataspace is output by HAL, and used by + * camera framework to encode into a HEIC image. + */ + JPEG_APP_SEGMENTS = 0x1003, + + /** + * ISO/IEC 23008-12 + * + * High Efficiency Image File Format (HEIF) + * + * This value is valid with formats: + * HAL_PIXEL_FORMAT_BLOB: A HEIC image encoded by HEIC or HEVC encoder + * according to ISO/IEC 23008-12. + */ + HEIF = 0x1004, +}; + +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, +}; + +/** + * Buffer usage definitions. + */ +enum BufferUsage : @1.1::BufferUsage { + /** + * Buffer is used as input for HEIC encoder. + */ + HW_IMAGE_ENCODER = 1ULL << 27, + + /* bits 28 and 32-47 must be zero and are reserved for future versions */ +}; + +/** + * 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::max(); + std::unique_ptr 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 mData; - - uint32_t mDataWritten; // end offset of the current command uint32_t mCommandEnd; @@ -746,13 +746,14 @@ class CommandReaderBase { return fd; } + std::unique_ptr mData; + uint32_t mDataRead; + private: std::unique_ptr mQueue; uint32_t mDataMaxSize; - std::unique_ptr 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/Composer.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h index 581dc96288..90d9b982a7 100644 --- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h +++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h @@ -80,7 +80,8 @@ class ComposerImpl : public Interface { Return createClient(IComposer::createClient_cb hidl_cb) override { std::unique_lock lock(mClientMutex); - if (!waitForClientDestroyedLocked(lock)) { + bool destroyed = waitForClientDestroyedLocked(lock); + if (!destroyed) { hidl_cb(Error::NO_RESOURCES, nullptr); return Void(); } @@ -108,12 +109,10 @@ class ComposerImpl : public Interface { // inverted (create and then destroy). Wait for a brief period to // see if the existing client is destroyed. ALOGD("waiting for previous client to be destroyed"); - mClientDestroyedCondition.wait_for( - lock, 1s, [this]() -> bool { return mClient.promote() == nullptr; }); - if (mClient.promote() != nullptr) { + mClientDestroyedCondition.wait_for(lock, 1s, + [this]() -> bool { return mClient == nullptr; }); + if (mClient != nullptr) { ALOGD("previous client was not destroyed"); - } else { - mClient.clear(); } } 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..18d184ecb4 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 #include +#include #include 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; + } + ALOGD_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0"); + + 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(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(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(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(const_cast(bufferHandle))); + if (mMapper2) { + mMapper2->freeBuffer( + static_cast(const_cast(bufferHandle))); + } else if (mMapper3) { + mMapper3->freeBuffer( + static_cast(const_cast(bufferHandle))); + } } } @@ -91,7 +119,8 @@ class ComposerHandleImporter { } private: - sp mMapper; + sp mMapper2; + sp mMapper3; }; class ComposerHandleCache { @@ -141,7 +170,7 @@ class ComposerHandleCache { } Error lookupCache(uint32_t slot, const native_handle_t** outHandle) { - if (slot < mHandles.size()) { + if (slot >= 0 && slot < mHandles.size()) { *outHandle = mHandles[slot]; return Error::NONE; } else { @@ -151,7 +180,7 @@ class ComposerHandleCache { Error updateCache(uint32_t slot, const native_handle_t* handle, const native_handle** outReplacedHandle) { - if (slot < mHandles.size()) { + if (slot >= 0 && slot < mHandles.size()) { auto& cachedHandle = mHandles[slot]; *outReplacedHandle = cachedHandle; cachedHandle = handle; @@ -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/passthrough/include/composer-passthrough/2.1/HwcHal.h b/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h index 436e4612bb..5826b126bb 100644 --- a/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h +++ b/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h @@ -162,6 +162,7 @@ class HwcHalImpl : public Hal { Error destroyLayer(Display display, Layer layer) override { int32_t err = mDispatch.destroyLayer(mDevice, display, layer); + onLayerDestroyed(display, layer); return static_cast(err); } @@ -327,6 +328,7 @@ class HwcHalImpl : public Hal { std::vector* outCompositionTypes, uint32_t* outDisplayRequestMask, std::vector* outRequestedLayers, std::vector* outRequestMasks) override { + onBeforeValidateDisplay(display); uint32_t typesCount = 0; uint32_t reqsCount = 0; int32_t err = mDispatch.validateDisplay(mDevice, display, &typesCount, &reqsCount); @@ -335,17 +337,15 @@ class HwcHalImpl : public Hal { return static_cast(err); } - err = mDispatch.getChangedCompositionTypes(mDevice, display, &typesCount, nullptr, nullptr); + err = getChangedCompositionTypes(display, &typesCount, nullptr, nullptr); if (err != HWC2_ERROR_NONE) { return static_cast(err); } std::vector changedLayers(typesCount); std::vector compositionTypes(typesCount); - err = mDispatch.getChangedCompositionTypes( - mDevice, display, &typesCount, changedLayers.data(), - reinterpret_cast::type*>( - compositionTypes.data())); + err = getChangedCompositionTypes(display, &typesCount, changedLayers.data(), + compositionTypes.data()); if (err != HWC2_ERROR_NONE) { return static_cast(err); } @@ -578,6 +578,15 @@ class HwcHalImpl : public Hal { return true; } + virtual int32_t getChangedCompositionTypes(Display display, uint32_t* outTypesCount, + Layer* outChangedLayers, + IComposerClient::Composition* outCompositionTypes) { + return getChangedCompositionTypesInternal(display, outTypesCount, outChangedLayers, + outCompositionTypes); + } + virtual void onLayerDestroyed(Display /* display */, Layer /* layer */) {} + virtual void onBeforeValidateDisplay(Display /* display */) {} + static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display, int32_t connected) { auto hal = static_cast(callbackData); @@ -596,6 +605,15 @@ class HwcHalImpl : public Hal { hal->mEventCallback->onVsync(display, timestamp); } + int32_t getChangedCompositionTypesInternal(Display display, uint32_t* outTypesCount, + Layer* outChangedLayers, + IComposerClient::Composition* outCompositionTypes) { + return mDispatch.getChangedCompositionTypes( + mDevice, display, outTypesCount, outChangedLayers, + reinterpret_cast::type*>( + outCompositionTypes)); + } + hwc2_device_t* mDevice = nullptr; std::unordered_set mCapabilities; diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp index 846cfdf355..fcb327f365 100644 --- a/graphics/composer/2.1/utils/vts/Android.bp +++ b/graphics/composer/2.1/utils/vts/Android.bp @@ -25,6 +25,8 @@ cc_library_static { static_libs: [ "VtsHalHidlTargetTestBase", "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0-vts", + "android.hardware.graphics.mapper@3.0-vts", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp index 6e668afdca..c5d5823398 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(); - init(); -} +Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService()) {} -Composer::Composer(const std::string& name) { - mComposer = ::testing::VtsHalHidlTargetTestBase::getService(name); - init(); -} +Composer::Composer(const std::string& name) + : Composer(::testing::VtsHalHidlTargetTestBase::getService(name)) {} -void Composer::init() { - ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service"; +Composer::Composer(const sp& 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 capabilities = getCapabilities(); - mCapabilities.insert(capabilities.begin(), capabilities.end()); + std::vector capabilities = getCapabilities(); + mCapabilities.insert(capabilities.begin(), capabilities.end()); + }(); } sp 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(ret)); - return; } mClient->executeCommands(commandLength, commandHandles, @@ -314,6 +311,79 @@ void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* write ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles)); reader->parse(); }); + reader->reset(); + writer->reset(); +} + +Gralloc::Gralloc() { + [this] { + ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared("default", "default", + /*errOnFailure=*/false)); + if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) { + mGralloc3 = nullptr; + ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared()); + } + }(); +} + +const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, bool import, + uint32_t* outStride) { + if (mGralloc3) { + IMapper3::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast(format); + info.usage = usage; + return mGralloc3->allocate(info, import, outStride); + } else { + IMapper2::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = format; + info.usage = usage; + return mGralloc2->allocate(info, import, outStride); + } +} + +void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const AccessRegion& accessRegionRect, int acquireFence) { + if (mGralloc3) { + IMapper3::Rect accessRegion; + accessRegion.left = accessRegionRect.left; + accessRegion.top = accessRegionRect.top; + accessRegion.width = accessRegionRect.width; + accessRegion.height = accessRegionRect.height; + int32_t bytesPerPixel; + int32_t bytesPerStride; + return mGralloc3->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel, + &bytesPerStride); + } else { + IMapper2::Rect accessRegion; + accessRegion.left = accessRegionRect.left; + accessRegion.top = accessRegionRect.top; + accessRegion.width = accessRegionRect.width; + accessRegion.height = accessRegionRect.height; + return mGralloc2->lock(bufferHandle, cpuUsage, accessRegion, acquireFence); + } +} + +int Gralloc::unlock(const native_handle_t* bufferHandle) { + if (mGralloc3) { + return mGralloc3->unlock(bufferHandle); + } else { + return mGralloc2->unlock(bufferHandle); + } +} + +void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { + if (mGralloc3) { + mGralloc3->freeBuffer(bufferHandle); + } else { + mGralloc2->freeBuffer(bufferHandle); + } } } // 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 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 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..7811048270 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 @@ -25,8 +25,12 @@ #include #include #include +#include +#include #include +#include "gtest/gtest.h" + namespace android { namespace hardware { namespace graphics { @@ -38,6 +42,10 @@ using android::hardware::graphics::common::V1_0::ColorMode; using android::hardware::graphics::common::V1_0::Dataspace; using android::hardware::graphics::common::V1_0::Hdr; using android::hardware::graphics::common::V1_0::PixelFormat; +using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper; +using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper; +using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc; +using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc; class ComposerClient; @@ -57,10 +65,10 @@ class Composer { std::unique_ptr createClient(); protected: - sp mComposer; + explicit Composer(const sp& composer); private: - void init(); + const sp mComposer; std::unordered_set mCapabilities; }; @@ -68,7 +76,7 @@ class Composer { // A wrapper to IComposerClient. class ComposerClient { public: - ComposerClient(const sp& client); + explicit ComposerClient(const sp& client); ~ComposerClient(); sp getRaw() const; @@ -116,7 +124,35 @@ class ComposerClient { std::unordered_map mDisplayResources; private: - sp mClient; + const sp mClient; +}; + +class AccessRegion { + public: + int32_t left; + int32_t top; + int32_t width; + int32_t height; +}; + +class Gralloc { + public: + explicit Gralloc(); + + const native_handle_t* allocate(uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, bool import = true, + uint32_t* outStride = nullptr); + + void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage, + const AccessRegion& accessRegionRect, int acquireFence); + + int unlock(const native_handle_t* bufferHandle); + + void freeBuffer(const native_handle_t* bufferHandle); + + protected: + std::shared_ptr mGralloc2 = nullptr; + std::shared_ptr mGralloc3 = nullptr; }; } // 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> mErrors; + std::vector> mCompositionChanges; }; } // namespace vts diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp index c98cc0deb8..d54da60f6d 100644 --- a/graphics/composer/2.1/vts/functional/Android.bp +++ b/graphics/composer/2.1/vts/functional/Android.bp @@ -26,10 +26,13 @@ cc_test { ], static_libs: [ "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.0-vts", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@3.0-vts", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index 72f3f1b4bf..30b96949dc 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,6 @@ using android::hardware::graphics::common::V1_0::ColorTransform; using android::hardware::graphics::common::V1_0::Dataspace; using android::hardware::graphics::common::V1_0::PixelFormat; using android::hardware::graphics::common::V1_0::Transform; -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; // Test environment for graphics.composer @@ -71,6 +70,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( GraphicsComposerHidlEnvironment::Instance()->getServiceName())); @@ -85,6 +85,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 +100,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::max() displays registered while running tests + Display GetInvalidDisplayId() { + std::vector validDisplays = mComposerCallback->getDisplays(); + + uint64_t id = std::numeric_limits::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 +128,7 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp mComposerCallback; // the first display and is assumed never to be removed Display mPrimaryDisplay; + Display mInvalidDisplayId; private: Display waitForFirstDisplay() { @@ -171,6 +197,22 @@ TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) { mComposerClient->destroyVirtualDisplay(display); } +/** + * 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. * @@ -184,6 +226,89 @@ TEST_F(GraphicsComposerHidlTest, CreateLayer) { mComposerClient->destroyLayer(mPrimaryDisplay, layer); } +/** + * 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 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. */ @@ -225,6 +350,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 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. * @@ -286,6 +435,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 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 modes = mComposerClient->getColorModes(mPrimaryDisplay); + auto nativeModeLocation = std::find(modes.begin(), modes.end(), ColorMode::NATIVE); + + ASSERT_NE(modes.end(), nativeModeLocation); +} + /** * Test IComposerClient::setColorMode. * @@ -305,6 +491,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 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(-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. * @@ -327,6 +552,99 @@ TEST_F(GraphicsComposerHidlTest, SetPowerMode) { } } +/** + * Test IComposerClient::setPowerMode + * + * Test IComposerClient::setPowerMode succeeds with different + * orderings of power modes + */ +TEST_F(GraphicsComposerHidlTest, SetPowerModeVariations) { + std::vector 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(-1)); + ASSERT_EQ(Error::BAD_PARAMETER, error); +} + /** * Test IComposerClient::setVsyncEnabled. * @@ -350,32 +668,36 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp()); ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique()); - + 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(1024); mReader = std::make_unique(); } - 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.layerCount = 1; - info.format = PixelFormat::RGBA_8888; - info.usage = - static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); - - return mGralloc->allocate(info); + uint64_t usage = + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN | + BufferUsage::COMPOSER_OVERLAY); + return mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage); } void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } std::unique_ptr mWriter; std::unique_ptr mReader; + int32_t mDisplayWidth; + int32_t mDisplayHeight; private: - std::unique_ptr mGralloc; + std::unique_ptr mGralloc; }; /** @@ -458,6 +780,60 @@ TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) { execute(); } +/** + * 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(0)); + mWriter->setLayerVisibleRegion(std::vector(1, displayFrame)); + mWriter->setLayerZOrder(10); + mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE); + mWriter->setLayerSurfaceDamage(std::vector(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(1, {0, 0, 10, 10})); + mWriter->presentDisplay(); + execute(); +} + /** * Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION. */ @@ -466,10 +842,37 @@ TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) { ASSERT_NO_FATAL_FAILURE(layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + auto handle = allocate(); + ASSERT_NE(nullptr, handle); + IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight}; + mWriter->selectDisplay(mPrimaryDisplay); mWriter->selectLayer(layer); + mWriter->setLayerBuffer(0, handle, -1); + mWriter->setLayerCompositionType(IComposerClient::Composition::CURSOR); + mWriter->setLayerDisplayFrame(displayFrame); + mWriter->setLayerPlaneAlpha(1); + mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight}); + mWriter->setLayerTransform(static_cast(0)); + mWriter->setLayerVisibleRegion(std::vector(1, displayFrame)); + mWriter->setLayerZOrder(10); + mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE); + mWriter->setLayerSurfaceDamage(std::vector(1, displayFrame)); + mWriter->setLayerDataspace(Dataspace::UNKNOWN); + mWriter->validateDisplay(); + + execute(); + if (mReader->mCompositionChanges.size() != 0) { + GTEST_SUCCEED() << "Composition change requested, skipping test"; + return; + } + mWriter->presentDisplay(); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->setLayerCursorPosition(1, 1); mWriter->setLayerCursorPosition(0, 0); + mWriter->validateDisplay(); + mWriter->presentDisplay(); execute(); } 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 getRenderIntents(Display display, ColorMode mode, IComposerClient::getRenderIntents_cb hidl_cb) override { -#ifdef USES_DISPLAY_RENDER_INTENTS std::vector intents; Error err = mHal->getRenderIntents(display, mode, &intents); hidl_cb(err, intents); -#else - (void)display; - (void)mode; - hidl_cb(Error::NONE, hidl_vec({RenderIntent::COLORIMETRIC})); -#endif return Void(); } Return 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/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp index c6b524d234..dd979cb08c 100644 --- a/graphics/composer/2.2/utils/vts/Android.bp +++ b/graphics/composer/2.2/utils/vts/Android.bp @@ -25,6 +25,10 @@ cc_library_static { "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@2.1-vts", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@3.0-vts", ], export_static_lib_headers: [ "android.hardware.graphics.composer@2.1-vts", diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp index 6a32071279..cd6772a485 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 Composer_v2_2::createClient_v2_2() { - std::unique_ptr client; - mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) { +std::unique_ptr Composer::createClient() { + std::unique_ptr 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(IComposerClient::castFrom(tmpClient, true)); + client = std::make_unique(IComposerClient::castFrom(tmpClient, true)); }); return client; } -sp ComposerClient_v2_2::getRaw() const { - return mClient_v2_2; +sp ComposerClient::getRaw() const { + return mClient; } -std::vector ComposerClient_v2_2::getPerFrameMetadataKeys( +std::vector ComposerClient::getPerFrameMetadataKeys( Display display) { std::vector 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 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 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(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); + mClient->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); - }); - } + 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(); - }); + 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 ComposerClient_v2_2::getColorModes(Display display) { +std::vector ComposerClient::getColorModes(Display display) { std::vector 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 ComposerClient_v2_2::getRenderIntents(Display display, ColorMode mode) { +std::vector ComposerClient::getRenderIntents(Display display, ColorMode mode) { std::vector 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 ComposerClient_v2_2::getDataspaceSaturationMatrix(Dataspace dataspace) { +std::array ComposerClient::getDataspaceSaturationMatrix(Dataspace dataspace) { std::array 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()); @@ -185,6 +180,48 @@ std::array ComposerClient_v2_2::getDataspaceSaturationMatrix(Dataspac return matrix; } +Gralloc::Gralloc() { + [this] { + ALOGD("Attempting to initialize gralloc3"); + ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared("default", "default", + /*errOnFailure=*/false)); + if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) { + mGralloc3 = nullptr; + ALOGD("Failed to create gralloc3, initializing gralloc2_1"); + mGralloc2_1 = std::make_shared(/*errOnFailure*/ false); + if (!mGralloc2_1->getMapper()) { + mGralloc2_1 = nullptr; + ALOGD("Failed to create gralloc2_1, initializing gralloc2"); + ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared()); + } + } + }(); +} + +bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width, + uint32_t height, uint32_t layerCount, PixelFormat format, + uint64_t usage, uint32_t stride) { + if (mGralloc3) { + IMapper3::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast(format); + info.usage = usage; + return mGralloc3->validateBufferSize(bufferHandle, info, stride); + } else if (mGralloc2_1) { + IMapper2_1::BufferDescriptorInfo info{}; + info.width = width; + info.height = height; + info.layerCount = layerCount; + info.format = static_cast(format); + info.usage = usage; + return mGralloc2_1->validateBufferSize(bufferHandle, info, stride); + } else { + return true; + } +} + } // namespace vts } // namespace V2_2 } // namespace composer 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..8fa9b7b3fe 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 @@ -27,6 +27,7 @@ #include #include #include +#include #include namespace android { @@ -36,36 +37,36 @@ 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; +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; +using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper; +using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper; +using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc; +using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc; +using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc; -class ComposerClient_v2_2; +class ComposerClient; -// 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 { +// 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 createClient_v2_2(); + std::unique_ptr 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& client) - : V2_1::vts::ComposerClient(client), mClient_v2_2(client){}; + explicit ComposerClient(const sp& client) + : V2_1::vts::ComposerClient(client), mClient(client) {} - sp getRaw() const; + sp 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 getPerFrameMetadataKeys(Display display); @@ -73,7 +74,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 +87,27 @@ class ComposerClient_v2_2 std::array getDataspaceSaturationMatrix(Dataspace dataspace); private: - sp mClient_v2_2; + const sp mClient; +}; + +class Gralloc : public V2_1::vts::Gralloc { + public: + Gralloc(); + const native_handle_t* allocate(uint32_t width, uint32_t height, uint32_t layerCount, + PixelFormat format, uint64_t usage, bool import = true, + uint32_t* outStride = nullptr) { + return V2_1::vts::Gralloc::allocate( + width, height, layerCount, + static_cast(format), usage, + import, outStride); + } + + bool validateBufferSize(const native_handle_t* bufferHandle, uint32_t width, uint32_t height, + uint32_t layerCount, PixelFormat format, uint64_t usage, + uint32_t stride); + + protected: + std::shared_ptr mGralloc2_1 = nullptr; }; } // namespace vts diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index a3da8294cb..9f7e1cd22e 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -17,16 +17,21 @@ 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", + "libhidlbase", + "libhidltransport", "libsync", ], static_libs: [ "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.common@1.1", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", @@ -36,6 +41,8 @@ cc_test { "android.hardware.graphics.mapper@2.0-vts", "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@2.1-vts", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@3.0-vts", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", 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..0648b3456a --- /dev/null +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp @@ -0,0 +1,1334 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 V2_1::Display; +using V2_1::Layer; +using V2_1::vts::AccessRegion; +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(); } + + private: + GraphicsComposerHidlEnvironment() {} + GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); +}; + +class TestLayer { + public: + TestLayer(const std::shared_ptr& 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& 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 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 mSurfaceDamage; + Transform mTransform = static_cast(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 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 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( + GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + 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(1024); + mReader = std::make_unique(); + mGralloc = std::make_shared(); + + 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>& layers) { + for (auto layer : layers) { + layer->write(mWriter); + } + execute(); + } + + void clearColors(std::vector& 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& 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 mComposer; + std::shared_ptr mComposerClient; + + sp mComposerCallback; + // the first display and is assumed never to be removed + Display mPrimaryDisplay; + int32_t mDisplayWidth; + int32_t mDisplayHeight; + std::shared_ptr mWriter; + std::unique_ptr mReader; + std::shared_ptr mGralloc; + + bool mHasReadbackBuffer; + PixelFormat mPixelFormat; + Dataspace mDataspace; + + static constexpr uint32_t kClientTargetSlotCount = 64; + + private: + Display waitForFirstDisplay() { + while (true) { + std::vector displays = mComposerCallback->getDisplays(); + if (displays.empty()) { + usleep(5 * 1000); + continue; + } + return displays[0]; + } + } +}; +class ReadbackBuffer { + public: + ReadbackBuffer(Display display, const std::shared_ptr& client, + const std::shared_ptr& gralloc, uint32_t width, uint32_t height, + PixelFormat pixelFormat, Dataspace dataspace) { + mDisplay = display; + + mComposerClient = client; + mGralloc = gralloc; + + mFormat = pixelFormat; + mDataspace = dataspace; + + mWidth = width; + mHeight = height; + mLayerCount = 1; + mUsage = static_cast(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(mWidth, mHeight, mLayerCount, mFormat, mUsage, + /*import*/ true, &mStride); + ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount, + mFormat, mUsage, mStride)); + ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1)); + } + + void checkReadbackBuffer(std::vector expectedColors) { + // lock buffer for reading + int32_t fenceHandle; + ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle)); + + void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle); + ASSERT_TRUE(mFormat == PixelFormat::RGB_888 || mFormat == PixelFormat::RGBA_8888); + int32_t bytesPerPixel = GraphicsComposerReadbackTest::GetBytesPerPixel(mFormat); + ASSERT_NE(-1, bytesPerPixel); + for (int row = 0; row < mHeight; row++) { + for (int col = 0; col < mWidth; col++) { + int pixel = row * mWidth + 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); + } + } + + uint32_t mWidth; + uint32_t mHeight; + uint32_t mLayerCount; + PixelFormat mFormat; + uint64_t mUsage; + AccessRegion mAccessRegion; + + protected: + uint32_t mStride; + const native_handle_t* mBufferHandle = nullptr; + Dataspace mDataspace; + Display mDisplay; + std::shared_ptr mGralloc; + std::shared_ptr mComposerClient; +}; + +class TestColorLayer : public TestLayer { + public: + TestColorLayer(const std::shared_ptr& client, Display display) + : TestLayer{client, display} {} + + void write(const std::shared_ptr& 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& client, + const std::shared_ptr& gralloc, Display display, int32_t width, + int32_t height, PixelFormat format, + IComposerClient::Composition composition = IComposerClient::Composition::DEVICE) + : TestLayer{client, display} { + mGralloc = gralloc; + mComposition = composition; + mWidth = width; + mHeight = height; + mLayerCount = 1; + mFormat = format; + mUsage = static_cast(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& writer) override { + TestLayer::write(writer); + writer->setLayerCompositionType(mComposition); + writer->setLayerDataspace(Dataspace::UNKNOWN); + writer->setLayerVisibleRegion(std::vector(1, mDisplayFrame)); + if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence); + } + + void fillBuffer(std::vector expectedColors) { + void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1); + ASSERT_NO_FATAL_FAILURE(GraphicsComposerReadbackTest::fillBuffer( + mWidth, mHeight, mStride, bufData, mFormat, expectedColors)); + mFillFence = mGralloc->unlock(mBufferHandle); + if (mFillFence != -1) { + sync_wait(mFillFence, -1); + close(mFillFence); + } + } + void setBuffer(std::vector colors) { + if (mBufferHandle != nullptr) { + mGralloc->freeBuffer(mBufferHandle); + mBufferHandle = nullptr; + } + mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage, + /*import*/ true, &mStride); + ASSERT_NE(nullptr, mBufferHandle); + ASSERT_NO_FATAL_FAILURE(fillBuffer(colors)); + ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount, + mFormat, mUsage, mStride)); + } + + void setToClientComposition(const std::shared_ptr& writer) { + writer->selectLayer(mLayer); + writer->setLayerCompositionType(IComposerClient::Composition::CLIENT); + } + + AccessRegion mAccessRegion; + uint32_t mStride; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mLayerCount; + PixelFormat mFormat; + + protected: + uint64_t mUsage; + IComposerClient::Composition mComposition; + std::shared_ptr 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(mComposerClient, mPrimaryDisplay); + IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + + std::vector> layers = {layer}; + + // expected color for each pixel + std::vector 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 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(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> 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(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 + PixelFormat format = PixelFormat::RGBA_8888; + uint64_t usage = + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN); + const native_handle_t* bufferHandle = + mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, format, usage); + mWriter->setLayerBuffer(0, bufferHandle, -1); + + // expected color for each pixel + std::vector 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 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(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_FP16); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + + std::vector> 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; + PixelFormat clientFormat = PixelFormat::RGBA_8888; + uint64_t clientUsage = + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_CLIENT_TARGET); + const native_handle_t* clientBufferHandle = + mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, clientFormat, + clientUsage, /*import*/ true, &clientStride); + ASSERT_NE(nullptr, clientBufferHandle); + + void* clientBufData = + mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1); + + ASSERT_NO_FATAL_FAILURE(fillBuffer(layer->mWidth, layer->mHeight, clientStride, + clientBufData, clientFormat, 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(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 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(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight / 2, PixelFormat::RGBA_8888); + std::vector deviceColors(deviceLayer->mWidth * deviceLayer->mHeight); + fillColorsArea(deviceColors, deviceLayer->mWidth, + {0, 0, static_cast(deviceLayer->mWidth), + static_cast(deviceLayer->mHeight)}, + GREEN); + deviceLayer->setDisplayFrame({0, 0, static_cast(deviceLayer->mWidth), + static_cast(deviceLayer->mHeight)}); + deviceLayer->setZOrder(10); + ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors)); + deviceLayer->write(mWriter); + + auto clientLayer = std::make_shared( + 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()); + + uint64_t clientUsage = + static_cast(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_CLIENT_TARGET); + uint32_t clientStride; + const native_handle_t* clientBufferHandle = + mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, + clientUsage, /*import*/ true, &clientStride); + ASSERT_NE(nullptr, clientBufferHandle); + + AccessRegion clientAccessRegion; + clientAccessRegion.left = 0; + clientAccessRegion.top = 0; + clientAccessRegion.width = mDisplayWidth; + clientAccessRegion.height = mDisplayHeight; + void* clientData = mGralloc->lock(clientBufferHandle, clientUsage, clientAccessRegion, -1); + std::vector clientColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED); + ASSERT_NO_FATAL_FAILURE(fillBuffer(mDisplayWidth, mDisplayHeight, clientStride, clientData, + PixelFormat::RGBA_8888, clientColors)); + int clientFence = mGralloc->unlock(clientBufferHandle); + if (clientFence != -1) { + sync_wait(clientFence, -1); + close(clientFence); + } + + mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN, + std::vector(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 expectedColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + auto layer = + std::make_shared(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> 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(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(mComposerClient, mPrimaryDisplay); + layer->setColor(RED); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setAlpha(0); + layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED); + + std::vector> 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 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 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(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setSourceCrop({0, static_cast(mDisplayHeight / 2), + static_cast(mDisplayWidth), static_cast(mDisplayHeight)}); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector> 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(mComposerClient, mPrimaryDisplay); + redLayer->setColor(RED); + redLayer->setDisplayFrame(redRect); + + auto blueLayer = std::make_shared(mComposerClient, mPrimaryDisplay); + blueLayer->setColor(BLUE); + blueLayer->setDisplayFrame(blueRect); + blueLayer->setZOrder(5); + + std::vector> layers = {redLayer, blueLayer}; + std::vector 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 { + 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 topLayerPixelColors(mDisplayWidth * mDisplayHeight); + fillColorsArea(topLayerPixelColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, + mTopLayerColor); + + auto backgroundLayer = std::make_shared(mComposerClient, mPrimaryDisplay); + backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + backgroundLayer->setZOrder(0); + backgroundLayer->setColor(mBackgroundColor); + + auto layer = std::make_shared(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& 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> 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 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 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 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(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(mComposerClient, mGralloc, mPrimaryDisplay, + mSideLength, mSideLength, PixelFormat::RGBA_8888); + mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength}); + mLayer->setZOrder(10); + + std::vector 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 mLayer; + std::vector baseColors; + std::vector> 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 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 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 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..51832f9f4c 100644 --- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp +++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp @@ -32,17 +32,14 @@ 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; // Test environment for graphics.composer class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { @@ -65,9 +62,9 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { protected: void SetUp() override { ASSERT_NO_FATAL_FAILURE( - mComposer = std::make_unique( + mComposer = std::make_unique( GraphicsComposerHidlEnvironment::Instance()->getServiceName())); - 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 +72,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(0), mReadbackPixelFormat); + ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace); + } }); + + mInvalidDisplayId = GetInvalidDisplayId(); } void TearDown() override { @@ -93,16 +105,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::max() displays registered while running tests + Display GetInvalidDisplayId() { + std::vector validDisplays = mComposerCallback->getDisplays(); + uint64_t id = std::numeric_limits::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 mComposer; - std::unique_ptr mComposerClient; + std::unique_ptr mComposer; + std::unique_ptr mComposerClient; sp 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,27 +160,25 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique()); - mWriter = std::make_unique(1024); + mWriter = std::make_unique(1024); mReader = std::make_unique(); } - void TearDown() override { 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(PixelFormat::RGBA_8888); - info.usage = - static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); - - return mGralloc->allocate(info); + void TearDown() override { + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); } - void execute() { mComposerClient->execute_v2_2(mReader.get(), mWriter.get()); } + const native_handle_t* allocate() { + uint64_t usage = + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + return mGralloc->allocate(/*width*/ 64, /*height*/ 64, /*layerCount*/ 1, + PixelFormat::RGBA_8888, usage); + } - std::unique_ptr mWriter; + void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + + std::unique_ptr mWriter; std::unique_ptr mReader; private: @@ -191,13 +224,35 @@ 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(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::getPerFrameMetadataKeys. */ TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) { - mComposerClient->getPerFrameMetadataKeys(mPrimaryDisplay); + std::vector keys; + Error error = Error::NONE; + mComposerClient->getRaw()->getPerFrameMetadataKeys( + mPrimaryDisplay, [&](const auto& tmpError, const auto& tmpKeys) { + error = tmpError; + keys = tmpKeys; + }); + if (error == Error::UNSUPPORTED) { + GTEST_SUCCEED() << "getPerFrameMetadataKeys is not supported"; + return; + } + ASSERT_EQ(Error::NONE, error); + ASSERT_TRUE(keys.size() >= 0); } /** @@ -248,10 +303,36 @@ 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 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 modes; modes.push_back(IComposerClient::PowerMode::OFF); modes.push_back(IComposerClient::PowerMode::ON_SUSPEND); @@ -262,37 +343,166 @@ 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 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(-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(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.layerCount = 1; - info.format = static_cast(pixelFormat); // BufferUsage::COMPOSER_OUTPUT is missing - info.usage = static_cast(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); + uint64_t usage = + static_cast(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); std::unique_ptr gralloc; const native_handle_t* buffer; ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique()); - ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(info)); + ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(mDisplayWidth, mDisplayHeight, 1, + mReadbackPixelFormat, usage)); 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; + } + + uint64_t usage = + static_cast(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN); + + std::unique_ptr gralloc; + const native_handle_t* buffer; + ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique()); + ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(mDisplayWidth, mDisplayHeight, 1, + mReadbackPixelFormat, usage)); + + 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(mReader->mErrors[0].second) == Error::UNSUPPORTED && + static_cast(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::getRenderIntent. +/* + * Test IComposerClient::getColorMode_2_2 + * + * Test that IComposerClient::getColorMode returns Error::BAD_DISPLAY when + * passed an invalid display handle */ -TEST_F(GraphicsComposerHidlTest, GetRenderIntent) { +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::getRenderIntents. + */ +TEST_F(GraphicsComposerHidlTest, GetRenderIntents) { std::vector modes = mComposerClient->getColorModes(mPrimaryDisplay); for (auto mode : modes) { std::vector 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 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(-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(-1), RenderIntent::COLORIMETRIC); + EXPECT_EQ(Error::BAD_PARAMETER, colorModeError); + + Error renderIntentError = mComposerClient->getRaw()->setColorMode_2_2( + mPrimaryDisplay, ColorMode::NATIVE, static_cast(-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..a777556aee --- /dev/null +++ b/graphics/composer/2.3/Android.bp @@ -0,0 +1,22 @@ +// 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 similarity index 53% rename from audio/effect/4.0/default/EnvironmentalReverbEffect.h rename to 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 +import IComposerClient; -#include +import @2.1::Error; +import @2.2::IComposer; -#include "Effect.h" +interface IComposer extends @2.2::IComposer { -#define AUDIO_HAL_VERSION V4_0 -#include -#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..4d6f78f0be --- /dev/null +++ b/graphics/composer/2.3/IComposerClient.hal @@ -0,0 +1,541 @@ +/* + * 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 { + + /** + * 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, + + /** + * Indicates that the display supports brightness operations. + */ + BRIGHTNESS = 3, + }; + + /** + * 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 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 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 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 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 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 sampleComponent0, + vec sampleComponent1, + vec sampleComponent2, + vec 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 inHandles) + generates (Error error, + bool outQueueChanged, + uint32_t outLength, + vec 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 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 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 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 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 types, + float maxLuminance, + float maxAverageLuminance, + float minLuminance); + + /** + * Use getDisplayCapabilities instead. If brightness is supported, must return + * DisplayCapability::BRIGHTNESS as one of the display capabilities via getDisplayCapabilities. + * Only use getDisplayCapabilities as the source of truth to query brightness support. + * + * Gets whether brightness operations are supported on a display. + * + * @param display + * The display. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when the display is invalid, or + * BAD_PARAMETER when the output parameter is invalid. + * @return support + * Whether brightness operations are supported on the display. + */ + getDisplayBrightnessSupport(Display display) generates (Error error, bool support); + + /** + * Sets the brightness of a display. + * + * Ideally, the brightness change should take effect in the next frame post (so that it can be + * aligned with color transforms). + * + * @param display + * The display whose brightness is set. + * @param brightness + * A number between 0.0f (minimum brightness) and 1.0f (maximum brightness), or -1.0 to + * turn the backlight off. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when the display is invalid, or + * UNSUPPORTED when brightness operations are not supported, or + * BAD_PARAMETER when the brightness is invalid, or + * NO_RESOURCES when the brightness cannot be applied. + */ + setDisplayBrightness(Display display, float brightness) generates (Error error); +}; 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..81ce89059c --- /dev/null +++ b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc @@ -0,0 +1,7 @@ +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 + writepid /dev/cpuset/system-background/tasks 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 + +#include +#include +#include +#include + +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 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 +#include +#include +#include + +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& metadataVec) { + beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA, + metadataVec.size() * 2); + for (const auto& metadata : metadataVec) { + writeSigned(static_cast(metadata.key)); + writeFloat(metadata.value); + } + endCommand(); + } + + void setLayerDataspace(Dataspace dataspace) { + setLayerDataspaceInternal(static_cast(dataspace)); + } + + void setClientTarget(uint32_t slot, const native_handle_t* target, int acquireFence, + Dataspace dataspace, const std::vector& damage) { + setClientTargetInternal(slot, target, acquireFence, static_cast(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& metadata) { + size_t commandLength = 0; + + if (metadata.size() > std::numeric_limits::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::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(commandLength); + beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length); + write(static_cast(metadata.size())); + for (auto metadataBlob : metadata) { + writeSigned(static_cast(metadataBlob.key)); + write(static_cast(metadataBlob.blob.size())); + writeBlob(static_cast(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(static_cast(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 similarity index 61% rename from audio/common/4.0/default/Android.bp rename to 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 +#include +#include + +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 +class ComposerImpl : public V2_2::hal::detail::ComposerImpl { + public: + static std::unique_ptr create(std::unique_ptr hal) { + return std::make_unique(std::move(hal)); + } + + explicit ComposerImpl(std::unique_ptr hal) : BaseType2_2(std::move(hal)) {} + + // IComposer 2.3 interface + + Return createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) override { + std::unique_lock lock(mClientMutex); + if (!waitForClientDestroyedLocked(lock)) { + hidl_cb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + sp 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; + using BaseType2_1 = V2_1::hal::detail::ComposerImpl; + + 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; + +} // 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..b289b6a0f9 --- /dev/null +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h @@ -0,0 +1,210 @@ +/* + * 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 +#include +#include +#include + +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 +class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl { + public: + Return getPerFrameMetadataKeys_2_3( + Display display, IComposerClient::getPerFrameMetadataKeys_2_3_cb hidl_cb) override { + std::vector keys; + Error error = mHal->getPerFrameMetadataKeys_2_3(display, &keys); + hidl_cb(error, keys); + return Void(); + } + + Return setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) override { + return mHal->setColorMode_2_3(display, mode, intent); + } + + Return getRenderIntents_2_3(Display display, ColorMode mode, + IComposerClient::getRenderIntents_2_3_cb hidl_cb) override { + std::vector intents; + Error err = mHal->getRenderIntents_2_3(display, mode, &intents); + hidl_cb(err, intents); + return Void(); + } + + Return getColorModes_2_3(Display display, + IComposerClient::getColorModes_2_3_cb hidl_cb) override { + hidl_vec modes; + Error err = mHal->getColorModes_2_3(display, &modes); + hidl_cb(err, modes); + return Void(); + } + + Return 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 getHdrCapabilities_2_3( + Display display, IComposerClient::getHdrCapabilities_2_3_cb hidl_cb) override { + hidl_vec 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 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 getDisplayCapabilities( + Display display, IComposerClient::getDisplayCapabilities_cb hidl_cb) override { + std::vector capabilities; + Error error = mHal->getDisplayCapabilities(display, &capabilities); + hidl_cb(error, capabilities); + return Void(); + } + + static std::unique_ptr create(Hal* hal) { + auto client = std::make_unique(hal); + return client->init() ? std::move(client) : nullptr; + } + + ComposerClientImpl(Hal* hal) : BaseType2_2(hal) {} + + // IComposerClient 2.3 interface + + Return getDisplayIdentificationData( + Display display, IComposerClient::getDisplayIdentificationData_cb hidl_cb) override { + uint8_t port = 0; + std::vector data; + Error error = mHal->getDisplayIdentificationData(display, &port, &data); + hidl_cb(error, port, data); + return Void(); + } + + Return getDisplayedContentSamplingAttributes( + uint64_t display, + IComposerClient::getDisplayedContentSamplingAttributes_cb hidl_cb) override { + PixelFormat format; + common::V1_2::Dataspace dataspace; + hidl_bitfield componentMask; + Error error = + mHal->getDisplayedContentSamplingAttributes(display, format, dataspace, componentMask); + hidl_cb(error, format, dataspace, componentMask); + return Void(); + } + + Return setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield componentMask, + uint64_t maxFrames) override { + return mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames); + } + + Return getDisplayedContentSample( + uint64_t display, uint64_t maxFrames, uint64_t timestamp, + IComposerClient::getDisplayedContentSample_cb hidl_cb) override { + uint64_t frameCount; + hidl_vec sampleComponent0; + hidl_vec sampleComponent1; + hidl_vec sampleComponent2; + hidl_vec sampleComponent3; + + Error error = mHal->getDisplayedContentSample(display, maxFrames, timestamp, frameCount, + sampleComponent0, sampleComponent1, + sampleComponent2, sampleComponent3); + hidl_cb(error, frameCount, sampleComponent0, sampleComponent1, sampleComponent2, + sampleComponent3); + return Void(); + } + + Return executeCommands_2_3(uint32_t inLength, const hidl_vec& inHandles, + IComposerClient::executeCommands_2_2_cb hidl_cb) override { + std::lock_guard lock(mCommandEngineMutex); + bool outChanged = false; + uint32_t outLength = 0; + hidl_vec outHandles; + Error error = + mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles); + + hidl_cb(error, outChanged, outLength, outHandles); + + mCommandEngine->reset(); + + return Void(); + } + + Return getDisplayBrightnessSupport( + Display display, IComposerClient::getDisplayBrightnessSupport_cb hidl_cb) override { + bool support = false; + Error error = mHal->getDisplayBrightnessSupport(display, &support); + hidl_cb(error, support); + return Void(); + } + + Return setDisplayBrightness(Display display, float brightness) override { + return mHal->setDisplayBrightness(display, brightness); + } + + protected: + std::unique_ptr createCommandEngine() override { + return std::make_unique( + mHal, static_cast(mResources.get())); + } + + private: + using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl; + using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl; + using BaseType2_1::mCommandEngine; + using BaseType2_1::mCommandEngineMutex; + using BaseType2_1::mHal; + using BaseType2_1::mResources; +}; + +} // namespace detail + +using ComposerClient = detail::ComposerClientImpl; + +} // 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 +#include +#include +#include +#include + +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(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 metadata; + + for (size_t i = 0; i < numBlobs; i++) { + IComposerClient::PerFrameMetadataKey key = + static_cast(readSigned()); + uint32_t blobSize = read(); + + length -= 2; + + if (length * sizeof(uint32_t) < blobSize) { + return false; + } + + metadata.push_back({key, std::vector()}); + 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..c3c488746d --- /dev/null +++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h @@ -0,0 +1,131 @@ +/* + * 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 + +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* outKeys) { + return getPerFrameMetadataKeys_2_3( + display, reinterpret_cast*>(outKeys)); + } + + Error setColorMode_2_2(Display display, common::V1_1::ColorMode mode, + RenderIntent intent) override { + return setColorMode_2_3(display, static_cast(mode), intent); + } + + Error getColorModes_2_2(Display display, hidl_vec* outModes) override { + return getColorModes_2_3(display, reinterpret_cast*>(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(format), + static_cast(dataspace)); + } + + Error getReadbackBufferAttributes(Display display, common::V1_1::PixelFormat* outFormat, + common::V1_1::Dataspace* outDataspace) override { + return getReadbackBufferAttributes_2_3(display, reinterpret_cast(outFormat), + reinterpret_cast(outDataspace)); + } + + Error getHdrCapabilities(Display display, hidl_vec* outTypes, + float* outMaxLuminance, float* outMaxAverageLuminance, + float* outMinLuminance) override { + return getHdrCapabilities_2_3(display, reinterpret_cast*>(outTypes), + outMaxLuminance, outMaxAverageLuminance, outMinLuminance); + } + + Error setLayerPerFrameMetadata( + Display display, Layer layer, + const std::vector& metadata) override { + return setLayerPerFrameMetadata_2_3( + display, layer, + reinterpret_cast&>(metadata)); + } + + virtual Error getPerFrameMetadataKeys_2_3( + Display display, std::vector* 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* outIntents) = 0; + + virtual Error getColorModes_2_3(Display display, hidl_vec* 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* outTypes, + float* outMaxLuminance, float* outMaxAverageLuminance, + float* outMinLuminance) = 0; + virtual Error setLayerPerFrameMetadata_2_3( + Display display, Layer layer, + const std::vector& metadata) = 0; + virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector* 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& componentMask) = 0; + virtual Error setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield componentMask, uint64_t maxFrames) = 0; + virtual Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, + uint64_t timestamp, uint64_t& frameCount, + hidl_vec& sampleComponent0, + hidl_vec& sampleComponent1, + hidl_vec& sampleComponent2, + hidl_vec& sampleComponent3) = 0; + virtual Error getDisplayCapabilities( + Display display, std::vector* outCapabilities) = 0; + virtual Error setLayerPerFrameMetadataBlobs( + Display display, Layer layer, + std::vector& blobs) = 0; + virtual Error getDisplayBrightnessSupport(Display display, bool* outSupport) = 0; + virtual Error setDisplayBrightness(Display display, float brightness) = 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..d3b29bb803 --- /dev/null +++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h @@ -0,0 +1,441 @@ +/* + * 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 + +#include +#include + +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; + +namespace { + +bool isIdentityMatrix(const float* matrix) { + if (matrix[0] == 1.0 && matrix[1] == 0.0 && matrix[2] == 0.0 && matrix[3] == 0.0 && + matrix[4] == 0.0 && matrix[5] == 1.0 && matrix[6] == 0.0 && matrix[7] == 0.0 && + matrix[8] == 0.0 && matrix[9] == 0.0 && matrix[10] == 1.0 && matrix[11] == 0.0 && + matrix[12] == 0.0 && matrix[13] == 0.0 && matrix[14] == 0.0 && matrix[15] == 1.0) { + return true; + } + return false; +} + +} // namespace + +// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2 +template +class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl { + public: + Error getPerFrameMetadataKeys_2_3( + Display display, std::vector* outKeys) override { + std::vector castKeys; + Error error = getPerFrameMetadataKeys(display, &castKeys); + if (error != Error::NONE) { + return error; + } + outKeys->clear(); + for (auto key : castKeys) { + outKeys->push_back(static_cast(key)); + } + return Error::NONE; + } + + Error setLayerPerFrameMetadata_2_3( + Display display, Layer layer, + const std::vector& metadata) override { + return setLayerPerFrameMetadata( + display, layer, + reinterpret_cast&>( + metadata)); + } + + Error setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) override { + return setColorMode_2_2(display, static_cast(mode), intent); + } + + Error getRenderIntents_2_3(Display display, ColorMode mode, + std::vector* outIntents) override { + return getRenderIntents(display, static_cast(mode), outIntents); + } + + Error getColorModes_2_3(Display display, hidl_vec* outModes) override { + return getColorModes_2_2(display, + reinterpret_cast*>(outModes)); + } + + Error getHdrCapabilities_2_3(Display display, hidl_vec* outTypes, float* outMaxLuminance, + float* outMaxAverageLuminance, float* outMinLuminance) override { + return getHdrCapabilities(display, reinterpret_cast*>(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(format), + static_cast(dataspace)); + } + + Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat, + Dataspace* outDataspace) override { + return getReadbackBufferAttributes( + display, reinterpret_cast(outFormat), + reinterpret_cast(outDataspace)); + } + + Error getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector* 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); + } + + std::vector data(size); + error = + mDispatch.getDisplayIdentificationData(mDevice, display, outPort, &size, data.data()); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + + data.resize(size); + *outData = std::move(data); + return Error::NONE; + } + + Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override { + if (!mDispatch.setLayerColorTransform) { + if (isIdentityMatrix(matrix)) { + // If an identity matrix is set, then we can remove the layer from client + // composition list. + mClientCompositionLayers[display].erase(layer); + return Error::UNSUPPORTED; + } + // if setLayerColorTransform is not implemented, per spec we want to make sure the + // layer marked as client composition, and thus we maintain a list, and mark all these + // layers as client composition later before validate the display. + mClientCompositionLayers[display].insert(layer); + return Error::UNSUPPORTED; + } + int32_t err = mDispatch.setLayerColorTransform(mDevice, display, layer, matrix); + return static_cast(err); + } + + Error getDisplayedContentSamplingAttributes( + uint64_t display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield& 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(errorRaw); + if (error == Error::NONE) { + format = static_cast(formatRaw); + dataspace = static_cast(dataspaceRaw); + componentMask = + static_cast>(componentMaskRaw); + } + return error; + }; + + Error setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield componentMask, + uint64_t maxFrames) override { + if (!mDispatch.setDisplayedContentSamplingEnabled) { + return Error::UNSUPPORTED; + } + return static_cast(mDispatch.setDisplayedContentSamplingEnabled( + mDevice, display, static_cast(enable), componentMask, maxFrames)); + } + + Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp, + uint64_t& frameCount, hidl_vec& sampleComponent0, + hidl_vec& sampleComponent1, + hidl_vec& sampleComponent2, + hidl_vec& 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(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(errorRaw); + } + + Error getDisplayCapabilities( + Display display, + std::vector* outCapabilities) override { + uint32_t count = 0; + int32_t error = mDispatch.getDisplayCapabilities(mDevice, display, &count, nullptr); + if (error != HWC2_ERROR_NONE) { + return static_cast(error); + } + outCapabilities->resize(count); + error = mDispatch.getDisplayCapabilities( + mDevice, display, &count, + reinterpret_cast::type*>( + outCapabilities->data())); + if (error != HWC2_ERROR_NONE) { + *outCapabilities = std::vector(); + return static_cast(error); + } + return Error::NONE; + } + + Error setLayerPerFrameMetadataBlobs( + Display display, Layer layer, + std::vector& metadata) override { + if (!mDispatch.setLayerPerFrameMetadataBlobs) { + return Error::UNSUPPORTED; + } + + std::vector keys; + std::vector sizes; + std::vector 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(metadata.size()), + reinterpret_cast(keys.data()), reinterpret_cast(sizes.data()), + blobs.data()); + return static_cast(err); + } + + Error getDisplayBrightnessSupport(Display display, bool* outSupport) { + if (!mDispatch.getDisplayBrightnessSupport) { + // Preemptively set to false. + *outSupport = false; + // Try to query from getDisplayCapabilities. + std::vector capabilities; + Error error = getDisplayCapabilities(display, &capabilities); + if (error != Error::NONE) { + // This function is not registered, always return UNSUPPORTED. + return Error::UNSUPPORTED; + } + *outSupport = + std::find(capabilities.begin(), capabilities.end(), + IComposerClient::DisplayCapability::BRIGHTNESS) != capabilities.end(); + // This function is not registered, always return UNSUPPORTED. + return Error::UNSUPPORTED; + } + bool support = false; + int32_t error = mDispatch.getDisplayBrightnessSupport(mDevice, display, &support); + *outSupport = support; + return static_cast(error); + } + + Error setDisplayBrightness(Display display, float brightness) { + if (std::isnan(brightness) || brightness > 1.0f || + (brightness < 0.0f && brightness != -1.0f)) { + return Error::BAD_PARAMETER; + } + if (!mDispatch.setDisplayBrightness) { + return Error::UNSUPPORTED; + } + int32_t error = mDispatch.setDisplayBrightness(mDevice, display, brightness); + return static_cast(error); + } + + 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); + this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_BRIGHTNESS_SUPPORT, + &mDispatch.getDisplayBrightnessSupport); + this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS, + &mDispatch.setDisplayBrightness); + return true; + } + + int32_t getChangedCompositionTypes(Display display, uint32_t* outTypesCount, + Layer* outChangedLayers, + IComposerClient::Composition* outCompositionTypes) override { + if (outChangedLayers == nullptr && outCompositionTypes == nullptr) { + uint32_t typesCount = 0; + int32_t error = BaseType2_1::getChangedCompositionTypesInternal(display, &typesCount, + nullptr, nullptr); + if (error != HWC2_ERROR_NONE) { + return error; + } + mChangedLayersCache[display].resize(typesCount); + mCompositionTypesCache[display].resize(typesCount); + error = BaseType2_1::getChangedCompositionTypesInternal( + display, &typesCount, mChangedLayersCache[display].data(), + mCompositionTypesCache[display].data()); + if (error != HWC2_ERROR_NONE) { + return error; + } + for (Layer layer : mClientCompositionLayers[display]) { + bool exist = false; + for (uint32_t i = 0; i < typesCount; ++i) { + if (mChangedLayersCache[display][i] == layer) { + exist = true; + break; + } + } + if (!exist) { + mChangedLayersCache[display].push_back(layer); + mCompositionTypesCache[display].push_back(IComposerClient::Composition::CLIENT); + } + } + *outTypesCount = mChangedLayersCache[display].size(); + return error; + } + for (uint32_t i = 0; i < *outTypesCount; ++i) { + if (outChangedLayers != nullptr) { + outChangedLayers[i] = mChangedLayersCache[display][i]; + } + if (outCompositionTypes != nullptr) { + outCompositionTypes[i] = mCompositionTypesCache[display][i]; + } + } + return HWC2_ERROR_NONE; + } + + void onLayerDestroyed(Display display, Layer layer) override { + if (mClientCompositionLayers.find(display) == mClientCompositionLayers.end()) { + return; + } + mClientCompositionLayers[display].erase(layer); + } + + void onBeforeValidateDisplay(Display display) override { + if (mClientCompositionLayers.find(display) == mClientCompositionLayers.end()) { + return; + } + + // clear the cache proactively so that we don't hold too much memory over time. + mChangedLayersCache[display].clear(); + mCompositionTypesCache[display].clear(); + + // SET_LAYER_COLOR_TRANSFORM is optional, and thus if it's not implemented, we need to + // follow the spec to make sure those layers marked as client composition before validate + // the display. + if (!mDispatch.setLayerColorTransform) { + for (Layer layer : mClientCompositionLayers[display]) { + BaseType2_1::setLayerCompositionType( + display, layer, static_cast(IComposerClient::Composition::CLIENT)); + } + } + } + + 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; + HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT getDisplayBrightnessSupport; + HWC2_PFN_SET_DISPLAY_BRIGHTNESS setDisplayBrightness; + } mDispatch = {}; + + using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl; + using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl; + 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; + std::map> mClientCompositionLayers; + std::map> mChangedLayersCache; + std::map> mCompositionTypesCache; +}; + +} // namespace detail + +using HwcHal = detail::HwcHalImpl; + +} // 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 +#include +#include +#include + +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 createHal(const hw_module_t* module) { + auto hal = std::make_unique(); + return hal->initWithModule(module) ? std::move(hal) : nullptr; + } + + // create a ComposerHal instance, insert an adapter if necessary + static std::unique_ptr createHalWithAdapter(const hw_module_t* module) { + bool adapted; + hwc2_device_t* device = openDeviceWithAdapter(module, &adapted); + if (!device) { + return nullptr; + } + auto hal = std::make_unique(); + return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr; + } + + // create an IComposer instance + static std::unique_ptr createComposer(std::unique_ptr 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..2fe6cd6a40 --- /dev/null +++ b/graphics/composer/2.3/utils/vts/Android.bp @@ -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. +// + +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", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.0-vts", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@2.1-vts", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@3.0-vts", + ], + 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..d4f5b3a4de --- /dev/null +++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp @@ -0,0 +1,209 @@ +/* + * 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 + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_3 { +namespace vts { + +using V2_1::Error; + +Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService()) {} + +Composer::Composer(const std::string& name) + : Composer(::testing::VtsHalHidlTargetTestBase::getService(name)) {} + +Composer::Composer(const sp& composer) + : V2_2::vts::Composer(composer), mComposer(composer) {} + +std::unique_ptr Composer::createClient() { + std::unique_ptr 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(tmpClient); + }); + + return client; +} + +sp ComposerClient::getRaw() const { + return mClient; +} + +bool ComposerClient::getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector* 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 ComposerClient::getColorModes_2_3(Display display) { + std::vector 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 ComposerClient::getRenderIntents_2_3(Display display, ColorMode mode) { + std::vector 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 ComposerClient::getPerFrameMetadataKeys_2_3( + Display display) { + std::vector 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 ComposerClient::getHdrCapabilities_2_3(Display display, float* outMaxLuminance, + float* outMaxAverageLuminance, + float* outMinLuminance) { + std::vector 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& 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 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& sampleComponent0, + hidl_vec& sampleComponent1, + hidl_vec& sampleComponent2, + hidl_vec& 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; +} + +Error ComposerClient::getDisplayCapabilities( + Display display, std::vector* outCapabilities) { + std::vector capabilities; + Error error = Error::NONE; + mClient->getDisplayCapabilities(display, + [&](const auto& tmpError, const auto& tmpCapabilities) { + error = tmpError; + *outCapabilities = tmpCapabilities; + }); + + return error; +} + +bool ComposerClient::getDisplayBrightnessSupport(Display display) { + bool support = false; + mClient->getDisplayBrightnessSupport( + display, [&](const auto& /*error*/, const auto& tmpSupport) { support = tmpSupport; }); + return support; +} + +Error ComposerClient::setDisplayBrightness(Display display, float brightness) { + return mClient->setDisplayBrightness(display, brightness); +} + +} // 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..0d4e5b8d5b --- /dev/null +++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h @@ -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. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +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 createClient(); + + protected: + explicit Composer(const sp& composer); + + private: + const sp mComposer; +}; + +// A wrapper to IComposerClient. +class ComposerClient : public V2_2::vts::ComposerClient { + public: + explicit ComposerClient(const sp& client) + : V2_2::vts::ComposerClient(client), mClient(client) {} + + sp getRaw() const; + + bool getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector* outData); + Error getDisplayedContentSamplingAttributes( + uint64_t display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield& componentMask); + Error setDisplayedContentSamplingEnabled( + uint64_t display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield componentMask, uint64_t maxFrames); + Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp, + uint64_t& frameCount, hidl_vec& sampleComponent0, + hidl_vec& sampleComponent1, + hidl_vec& sampleComponent2, + hidl_vec& sampleComponent3); + + std::vector getColorModes_2_3(Display display); + + void setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent); + + std::vector getRenderIntents_2_3(Display display, ColorMode mode); + + void getReadbackBufferAttributes_2_3(Display display, PixelFormat* outPixelFormat, + Dataspace* outDataspace); + + std::vector 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); + Error getDisplayCapabilities( + Display display, + std::vector* outDisplayCapabilities); + + std::vector getPerFrameMetadataKeys_2_3(Display display); + + bool getDisplayBrightnessSupport(Display display); + + Error setDisplayBrightness(Display display, float brightness); + + private: + const sp 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..2766638754 --- /dev/null +++ b/graphics/composer/2.3/vts/functional/Android.bp @@ -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. +// + +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", + "libhidlbase", + "libhidltransport", + "libsync", + ], + static_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.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", + "android.hardware.graphics.mapper@2.1-vts", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@3.0-vts", + ], + 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..dafe58786b --- /dev/null +++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp @@ -0,0 +1,645 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +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 V2_2::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(); } + + 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( + GraphicsComposerHidlEnvironment::Instance()->getServiceName())); + 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(1024); + mReader = std::make_unique(); + } + + 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::max() displays registered while running tests + Display GetInvalidDisplayId() { + std::vector validDisplays = mComposerCallback->getDisplays(); + uint64_t id = std::numeric_limits::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 mComposer; + std::unique_ptr mComposerClient; + sp mComposerCallback; + // the first display and is assumed never to be removed + Display mPrimaryDisplay; + Display mInvalidDisplayId; + std::unique_ptr mWriter; + std::unique_ptr mReader; + + private: + Display waitForFirstDisplay() { + while (true) { + std::vector 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()); + + mWriter = std::make_unique(1024); + mReader = std::make_unique(); + } + + void TearDown() override { + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); + } + + const native_handle_t* allocate() { + return mGralloc->allocate( + 64, 64, 1, static_cast(PixelFormat::RGBA_8888), + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN)); + } + + void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + + std::unique_ptr mWriter; + std::unique_ptr mReader; + + private: + std::unique_ptr mGralloc; +}; + +/** + * Test IComposerClient::getDisplayIdentificationData. + * + * TODO: Check that ports are unique for multiple displays. + */ +TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) { + uint8_t port0; + std::vector data0; + if (mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) { + uint8_t port1; + std::vector 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 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(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 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 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 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 modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); + for (auto mode : modes) { + std::vector 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 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(-1), + [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); }); +} + +/** + * IComposerClient::getColorModes_2_3 + */ +TEST_F(GraphicsComposerHidlTest, GetColorModes_2_3) { + std::vector 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 colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay); + for (auto mode : colorModes) { + std::vector 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(-1), RenderIntent::COLORIMETRIC); + EXPECT_EQ(Error::BAD_PARAMETER, colorModeError); + + Error renderIntentError = mComposerClient->getRaw()->setColorMode_2_3( + mPrimaryDisplay, ColorMode::NATIVE, static_cast(-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 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(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(invalid); + auto dataspace = static_cast(invalid); + auto componentMask = static_cast>(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(invalid)); + EXPECT_NE(dataspace, static_cast(invalid)); + EXPECT_NE(componentMask, + static_cast>(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(invalid); + auto dataspace = static_cast(invalid); + auto componentMask = static_cast>(invalid); + auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format, + dataspace, componentMask); + + uint64_t maxFrames = 10; + uint64_t timestamp = 0; + uint64_t frameCount = 0; + hidl_array, 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) { + std::vector capabilities; + const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities); + ASSERT_EQ(Error::NONE, error); + const bool hasDozeSupport = + std::find(capabilities.begin(), capabilities.end(), + IComposerClient::DisplayCapability::DOZE) != capabilities.end(); + EXPECT_EQ(mComposerClient->getDozeSupport(mPrimaryDisplay), hasDozeSupport); + bool hasBrightnessSupport = + std::find(capabilities.begin(), capabilities.end(), + IComposerClient::DisplayCapability::BRIGHTNESS) != capabilities.end(); + EXPECT_EQ(mComposerClient->getDisplayBrightnessSupport(mPrimaryDisplay), hasBrightnessSupport); +} + +TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) { + std::vector capabilities; + const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities); + EXPECT_EQ(Error::BAD_DISPLAY, error); +} + +TEST_F(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) { + Layer layer; + ASSERT_NO_FATAL_FAILURE(layer = + mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + + std::vector metadata; + metadata.push_back( + {IComposerClient::PerFrameMetadataKey::HDR10_PLUS_SEI, std::vector(1, 0xff)}); + + mWriter->setLayerPerFrameMetadataBlobs(metadata); + execute(); + + if (mReader->mErrors.size() == 1 && + static_cast(mReader->mErrors[0].second) == Error::UNSUPPORTED) { + mReader->mErrors.clear(); + GTEST_SUCCEED() << "setLayerDynamicPerFrameMetadata is not supported"; + return; + } +} + +/* + * Test that if brightness operations are supported, setDisplayBrightness works as expected. + */ +TEST_F(GraphicsComposerHidlTest, setDisplayBrightness) { + std::vector capabilities; + const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities); + ASSERT_EQ(Error::NONE, error); + bool brightnessSupport = + std::find(capabilities.begin(), capabilities.end(), + IComposerClient::DisplayCapability::BRIGHTNESS) != capabilities.end(); + if (!brightnessSupport) { + EXPECT_EQ(mComposerClient->getRaw()->setDisplayBrightness(mPrimaryDisplay, 0.5f), + Error::UNSUPPORTED); + GTEST_SUCCEED() << "Brightness operations are not supported"; + return; + } + + EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.0f), Error::NONE); + EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.5f), Error::NONE); + EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 1.0f), Error::NONE); + EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -1.0f), Error::NONE); + + EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, +2.0f), Error::BAD_PARAMETER); + EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f), Error::BAD_PARAMETER); +} + +} // 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/IMapper.hal b/graphics/mapper/2.0/IMapper.hal index 45661357af..0e18f42674 100644 --- a/graphics/mapper/2.0/IMapper.hal +++ b/graphics/mapper/2.0/IMapper.hal @@ -147,6 +147,9 @@ interface IMapper { * outside of accessRegion is undefined, except that it must not cause * process termination. * + * An accessRegion of all-zeros means the entire buffer. That is, it is + * equivalent to '(0,0)-(buffer width, buffer height)'. + * * data will be filled with a pointer to the locked buffer memory. This * address will represent the top-left corner of the entire buffer, even * if accessRegion does not begin at the top-left corner. 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 +#include +#include + #include #include #include @@ -124,6 +128,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 timeUp(false); + std::atomic allocationCount(0); + auto threadLoop = [&]() { + while (!timeUp) { + mGralloc->getAllocator()->allocate( + descriptor, 1, [&](const auto&, const auto&, const auto&) { allocationCount++; }); + } + }; + + std::vector 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. */ diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h index b704fdba4c..18fbb6d035 100644 --- a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h +++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h @@ -34,34 +34,48 @@ using V2_0::Error; template class Gralloc0HalImpl : public V2_0::passthrough::detail::Gralloc0HalImpl { public: - Error validateBufferSize(const native_handle_t* /*bufferHandle*/, - const IMapper::BufferDescriptorInfo& /*descriptorInfo*/, - uint32_t /*stride*/) override { - // need a gralloc0 extension to really validate - return Error::NONE; - } + Error validateBufferSize(const native_handle_t* bufferHandle, + const IMapper::BufferDescriptorInfo& descriptorInfo, + uint32_t stride) override { + if (!mModule->validateBufferSize) { + return Error::NONE; + } - Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, - uint32_t* outNumInts) override { - // need a gralloc0 extension to get the transport size - *outNumFds = bufferHandle->numFds; - *outNumInts = bufferHandle->numInts; - return Error::NONE; + int32_t ret = mModule->validateBufferSize( + mModule, bufferHandle, descriptorInfo.width, descriptorInfo.height, + static_cast(descriptorInfo.format), + static_cast(descriptorInfo.usage), stride); + return static_cast(ret); + } + Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts) override { + if (!mModule->getTransportSize) { + *outNumFds = bufferHandle->numFds; + *outNumInts = bufferHandle->numInts; + return Error::NONE; + } + + int32_t ret = mModule->getTransportSize(mModule, bufferHandle, outNumFds, outNumInts); + return static_cast(ret); } Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo, BufferDescriptor* outDescriptor) override { return createDescriptor( - V2_0::IMapper::BufferDescriptorInfo{ - descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount, - static_cast(descriptorInfo.format), descriptorInfo.usage, - }, - outDescriptor); + V2_0::IMapper::BufferDescriptorInfo{ + descriptorInfo.width, + descriptorInfo.height, + descriptorInfo.layerCount, + static_cast(descriptorInfo.format), + descriptorInfo.usage, + }, + outDescriptor); } private: using BaseType2_0 = V2_0::passthrough::detail::Gralloc0HalImpl; using BaseType2_0::createDescriptor; + using BaseType2_0::mModule; }; } // namespace detail 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 { 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 { 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; using BaseType2_0::createDescriptor; diff --git a/graphics/mapper/2.1/utils/vts/MapperVts.cpp b/graphics/mapper/2.1/utils/vts/MapperVts.cpp index 078068e306..36f9cbbeb2 100644 --- a/graphics/mapper/2.1/utils/vts/MapperVts.cpp +++ b/graphics/mapper/2.1/utils/vts/MapperVts.cpp @@ -43,24 +43,25 @@ static_assert(sizeof(OldBufferDescriptorInfo) == sizeof(IMapper::BufferDescripto offsetof(IMapper::BufferDescriptorInfo, usage), ""); -Gralloc::Gralloc() : V2_0::vts::Gralloc() { +Gralloc::Gralloc(bool errOnFailure) : V2_0::vts::Gralloc() { if (::testing::Test::HasFatalFailure()) { return; } - init(); + init(errOnFailure); } -Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName) +Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName, + bool errOnFailure) : V2_0::vts::Gralloc(allocatorServiceName, mapperServiceName) { if (::testing::Test::HasFatalFailure()) { return; } - init(); + init(errOnFailure); } -void Gralloc::init() { +void Gralloc::init(bool errOnFailure) { mMapperV2_1 = IMapper::castFrom(V2_0::vts::Gralloc::getMapper()); - ASSERT_NE(nullptr, mMapperV2_1.get()) << "failed to get mapper 2.1 service"; + if (errOnFailure) ASSERT_NE(nullptr, mMapperV2_1.get()) << "failed to get mapper 2.1 service"; } sp Gralloc::getMapper() const { diff --git a/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h index 423d4b3c0d..bc683bb355 100644 --- a/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h +++ b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h @@ -32,25 +32,26 @@ using V2_0::BufferDescriptor; // A wrapper to IAllocator and IMapper. class Gralloc : public V2_0::vts::Gralloc { public: - Gralloc(); - Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName); + Gralloc(bool errOnFailure = true); + Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName, + bool errOnFailure = true); - sp getMapper() const; + sp getMapper() const; - 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 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); - BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo); + BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo); - const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, - bool import = true, uint32_t* outStride = nullptr); + const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, + bool import = true, uint32_t* outStride = nullptr); protected: - void init(); + void init(bool errOnFailure = true); - sp mMapperV2_1; + sp mMapperV2_1; }; } // namespace vts diff --git a/graphics/mapper/3.0/Android.bp b/graphics/mapper/3.0/Android.bp new file mode 100644 index 0000000000..a14324310c --- /dev/null +++ b/graphics/mapper/3.0/Android.bp @@ -0,0 +1,21 @@ +// 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", + ], + 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..71b56d98c0 --- /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.2::BufferUsage; +import android.hardware.graphics.common@1.2::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 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 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..c94e8db065 --- /dev/null +++ b/graphics/mapper/3.0/utils/vts/MapperVts.cpp @@ -0,0 +1,303 @@ +/* + * 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 + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V3_0 { +namespace vts { + +Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName, + bool errOnFailure) { + if (errOnFailure) { + init(allocatorServiceName, mapperServiceName); + } else { + initNoErr(allocatorServiceName, mapperServiceName); + } +} + +void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) { + mAllocator = ::testing::VtsHalHidlTargetTestBase::getService(allocatorServiceName); + ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service"; + + mMapper = ::testing::VtsHalHidlTargetTestBase::getService(mapperServiceName); + ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service"; + ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; +} + +void Gralloc::initNoErr(const std::string& allocatorServiceName, + const std::string& mapperServiceName) { + mAllocator = ::testing::VtsHalHidlTargetTestBase::getService(allocatorServiceName); + + mMapper = ::testing::VtsHalHidlTargetTestBase::getService(mapperServiceName); + if (mMapper.get()) { + ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; + } +} + +Gralloc::~Gralloc() { + for (auto bufferHandle : mClonedBuffers) { + auto buffer = const_cast(bufferHandle); + native_handle_close(buffer); + native_handle_delete(buffer); + } + mClonedBuffers.clear(); + + for (auto bufferHandle : mImportedBuffers) { + auto buffer = const_cast(bufferHandle); + EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer; + } + mImportedBuffers.clear(); +} + +sp 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 Gralloc::allocate(const BufferDescriptor& descriptor, + uint32_t count, bool import, + uint32_t* outStride) { + std::vector 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 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(tmpBuffer); + }); + + if (bufferHandle) { + mImportedBuffers.insert(bufferHandle); + } + + return bufferHandle; +} + +void Gralloc::freeBuffer(const native_handle_t* bufferHandle) { + auto buffer = const_cast(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(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(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(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(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(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..1141a881e0 --- /dev/null +++ b/graphics/mapper/3.0/utils/vts/include/mapper-vts/3.0/MapperVts.h @@ -0,0 +1,106 @@ +/* + * 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 +#include +#include + +#include +#include +#include + +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", bool errOnFailure = true); + ~Gralloc(); + + // IAllocator methods + + sp 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 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 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); + + // initialize without checking for failure to get service + void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName); + const native_handle_t* cloneBuffer(const hidl_handle& rawHandle); + + sp mAllocator; + sp 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 mClonedBuffers; + std::unordered_set 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/graphics/mapper/3.0/vts/functional/Android.bp b/graphics/mapper/3.0/vts/functional/Android.bp new file mode 100644 index 0000000000..77075a5a88 --- /dev/null +++ b/graphics/mapper/3.0/vts/functional/Android.bp @@ -0,0 +1,30 @@ +// +// 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. +// + +cc_test { + name: "VtsHalGraphicsMapperV3_0TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalGraphicsMapperV3_0TargetTest.cpp"], + static_libs: [ + "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..ff73ecf769 --- /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 +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V3_0 { +namespace vts { +namespace { + +using android::hardware::graphics::common::V1_2::BufferUsage; +using android::hardware::graphics::common::V1_2::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(); + registerTestService(); + } +}; + +class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE( + mGralloc = std::make_unique( + GraphicsMapperHidlEnvironment::Instance()->getServiceName(), + GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + + mDummyDescriptorInfo.width = 64; + mDummyDescriptorInfo.height = 64; + mDummyDescriptorInfo.layerCount = 1; + mDummyDescriptorInfo.format = PixelFormat::RGBA_8888; + mDummyDescriptorInfo.usage = + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); + } + + void TearDown() override {} + + std::unique_ptr 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 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 timeUp(false); + std::atomic allocationCount(0); + auto threadLoop = [&]() { + while (!timeUp) { + mGralloc->getAllocator()->allocate( + descriptor, 1, [&](const auto&, const auto&, const auto&) { allocationCount++; }); + } + }; + + std::vector 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(buffer); + }); + + // free the imported handle with another mapper + std::unique_ptr anotherGralloc; + ASSERT_NO_FATAL_FAILURE( + anotherGralloc = std::make_unique( + GraphicsMapperHidlEnvironment::Instance()->getServiceName(), + GraphicsMapperHidlEnvironment::Instance()->getServiceName())); + 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(info.width), + static_cast(info.height)}; + int fence = -1; + uint8_t* data; + int32_t bytesPerPixel = -1; + int32_t bytesPerStride = -1; + ASSERT_NO_FATAL_FAILURE( + data = static_cast(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(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(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(info.width), + static_cast(info.height)}; + int fence = -1; + YCbCrLayout layout; + ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence)); + + auto yData = static_cast(layout.y); + auto cbData = static_cast(layout.cb); + auto crData = static_cast(layout.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast(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(layout.y); + cbData = static_cast(layout.cb); + crData = static_cast(layout.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast(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( + 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( + 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/health/storage/1.0/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp index 250a7dcb84..b18e36f83e 100644 --- a/health/storage/1.0/vts/functional/Android.bp +++ b/health/storage/1.0/vts/functional/Android.bp @@ -20,7 +20,8 @@ cc_test { srcs: ["VtsHalHealthStorageV1_0TargetTest.cpp"], static_libs: ["android.hardware.health.storage@1.0"], shared_libs: [ - "libhidltransport" + "libhidlbase", + "libhidltransport", ], test_suites: ["general-tests"], } diff --git a/input/classifier/1.0/Android.bp b/input/classifier/1.0/Android.bp new file mode 100644 index 0000000000..11e0f52dd0 --- /dev/null +++ b/input/classifier/1.0/Android.bp @@ -0,0 +1,17 @@ +// 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..ceb2aca9f8 --- /dev/null +++ b/input/classifier/1.0/default/Android.bp @@ -0,0 +1,23 @@ +cc_binary { + name: "android.hardware.input.classifier@1.0-service.default", + init_rc: ["android.hardware.input.classifier@1.0-service.default.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..cce9190cc8 --- /dev/null +++ b/input/classifier/1.0/default/InputClassifier.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. + */ + +#define LOG_TAG "InputClassifierHAL" + +#include "InputClassifier.h" +#include +#include +#include + +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 InputClassifier::classify(const MotionEvent& /*event*/) { + /** + * The touchscreen data is highly device-dependent. + * As a result, the implementation of this method will likely be hardware-specific. + * Here we just report gesture as not having any classification, which means that the + * default action will be taken in the framework. + * This is equivalent to not having the InputClassifier HAL at all. + */ + return Classification::NONE; +} + +Return InputClassifier::reset() { + // We don't have any internal state, so no work needed here. + return Void(); +} + +Return InputClassifier::resetDevice(int32_t /*deviceId*/) { + // We don't have any internal per-device state, 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 +#include + +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 classify( + const android::hardware::input::common::V1_0::MotionEvent& event) override; + + Return reset() override; + Return 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.default.rc b/input/classifier/1.0/default/android.hardware.input.classifier@1.0-service.default.rc new file mode 100644 index 0000000000..e7d16ae05e --- /dev/null +++ b/input/classifier/1.0/default/android.hardware.input.classifier@1.0-service.default.rc @@ -0,0 +1,9 @@ +service vendor.input.classifier-1-0 /vendor/bin/hw/android.hardware.input.classifier@1.0-service.default + # 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 @@ + + + android.hardware.input.classifier + hwbinder + 1.0 + + IInputClassifier + default + + + 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 + +#include +#include + +#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 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/classifier/1.0/vts/OWNERS b/input/classifier/1.0/vts/OWNERS new file mode 100644 index 0000000000..447f3d9b67 --- /dev/null +++ b/input/classifier/1.0/vts/OWNERS @@ -0,0 +1,3 @@ +michaelwr@google.com +pquinn@google.com +svv@google.com \ No newline at end of file diff --git a/audio/core/2.0/vts/functional/Android.bp b/input/classifier/1.0/vts/functional/Android.bp similarity index 66% rename from audio/core/2.0/vts/functional/Android.bp rename to input/classifier/1.0/vts/functional/Android.bp index 2cfba21fb9..ef49d70dfb 100644 --- a/audio/core/2.0/vts/functional/Android.bp +++ b/input/classifier/1.0/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,17 +15,13 @@ // cc_test { - name: "VtsHalAudioV2_0TargetTest", + name: "VtsHalInputClassifierV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], - srcs: [ - "AudioPrimaryHidlHalTest.cpp", - "ValidateAudioConfiguration.cpp" - ], + srcs: ["VtsHalInputClassifierV1_0TargetTest.cpp"], static_libs: [ - "android.hardware.audio.common.test.utility", - "android.hardware.audio@2.0", - "android.hardware.audio.common@2.0", - "libxml2", + "android.hardware.input.classifier@1.0", + "android.hardware.input.common@1.0", ], test_suites: ["general-tests"], } + diff --git a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp new file mode 100644 index 0000000000..f033c2a102 --- /dev/null +++ b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp @@ -0,0 +1,193 @@ +/* + * 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 "input_classifier_hal_test" + +#include +#include +#include +#include +#include +#include +#include + +using ::android::ReservedInputDeviceId; +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::input::classifier::V1_0::IInputClassifier; +using ::android::hardware::input::common::V1_0::Action; +using ::android::hardware::input::common::V1_0::Axis; +using ::android::hardware::input::common::V1_0::Button; +using ::android::hardware::input::common::V1_0::EdgeFlag; +using ::android::hardware::input::common::V1_0::MotionEvent; +using ::android::hardware::input::common::V1_0::PointerCoords; +using ::android::hardware::input::common::V1_0::PointerProperties; +using ::android::hardware::input::common::V1_0::Source; +using ::android::hardware::input::common::V1_0::ToolType; +using ::android::hardware::input::common::V1_0::VideoFrame; + +static MotionEvent getSimpleMotionEvent() { + MotionEvent event; + event.action = Action::DOWN; + event.actionButton = Button::NONE; + event.actionIndex = 0; + event.buttonState = 0; + event.deviceId = 0; + event.deviceTimestamp = 0; + event.displayId = 1; + event.downTime = 2; + event.edgeFlags = 0; + event.eventTime = 3; + event.flags = 0; + event.frames = {}; + event.metaState = 0; + event.policyFlags = 0; + event.source = Source::TOUCHSCREEN; + event.xPrecision = 0; + event.yPrecision = 0; + + PointerCoords coords; + coords.bits = Axis::X | Axis::Y; + coords.values = {1 /*X*/, 2 /*Y*/}; + event.pointerCoords = {coords}; + + PointerProperties properties; + properties.id = 0; + properties.toolType = ToolType::FINGER; + event.pointerProperties = {properties}; + + return event; +} + +// Test environment for Input Classifier HIDL HAL. +class InputClassifierHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static InputClassifierHidlEnvironment* Instance() { + static InputClassifierHidlEnvironment* instance = new InputClassifierHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService(); } + + private: + InputClassifierHidlEnvironment() {} +}; + +// The main test class for INPUT CLASSIFIER HIDL HAL 1.0. +class InputClassifierHidlTest_1_0 : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + classifier = ::testing::VtsHalHidlTargetTestBase::getService( + InputClassifierHidlEnvironment::Instance()->getServiceName()); + ASSERT_NE(classifier, nullptr); + } + + virtual void TearDown() override {} + + sp classifier; +}; + +/** + * Call resetDevice(..) for a few common device id values, and make sure that the HAL + * can handle the resets gracefully. + */ +TEST_F(InputClassifierHidlTest_1_0, ResetDevice) { + EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID).isOk()); + EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID).isOk()); + EXPECT_TRUE(classifier->resetDevice(1).isOk()); + EXPECT_TRUE(classifier->resetDevice(2).isOk()); +} + +/** + * Call reset() on the HAL to ensure no fatal failure there. + */ +TEST_F(InputClassifierHidlTest_1_0, ResetHal) { + EXPECT_TRUE(classifier->reset().isOk()); +} + +/** + * Classify an event without any video frames. + */ +TEST_F(InputClassifierHidlTest_1_0, Classify_NoVideoFrame) { + // Create a MotionEvent that does not have any video data + MotionEvent event = getSimpleMotionEvent(); + + EXPECT_TRUE(classifier->classify(event).isOk()); + // We are not checking the actual classification here, + // because the HAL operation is highly device-specific. + + // Return HAL to a consistent state by doing a reset + classifier->reset(); +} + +/** + * Classify an event with one video frame. Should be the most common scenario. + */ +TEST_F(InputClassifierHidlTest_1_0, Classify_OneVideoFrame) { + MotionEvent event = getSimpleMotionEvent(); + VideoFrame frame; + frame.data = {1, 2, 3, 4}; + frame.height = 2; + frame.width = 2; + frame.timestamp = event.eventTime; + event.frames = {frame}; + + EXPECT_TRUE(classifier->classify(event).isOk()); + // We are not checking the actual classification here, + // because the HAL operation is highly device-specific. + + // Return HAL to a consistent state by doing a reset + classifier->reset(); +} + +/** + * Classify an event with 2 video frames. This could happen if there's slowness in the system, + * or if simply the video rate is somehow higher that the input event rate. + * The HAL should be able to handle events with more than 1 video frame. + * + * The frames should be in chronological order, but it is not guaranteed that they will have + * monotonically increasing timestamps. Still, we provide consistent timestamps here since that + * is the most realistic mode of operation. + */ +TEST_F(InputClassifierHidlTest_1_0, Classify_TwoVideoFrames) { + MotionEvent event = getSimpleMotionEvent(); + VideoFrame frame1; + frame1.data = {1, 2, 3, 4}; + frame1.height = 2; + frame1.width = 2; + frame1.timestamp = event.eventTime; + VideoFrame frame2 = frame1; + frame2.data = {5, 5, 5, -1}; + frame2.timestamp += 1; + event.frames = {frame1, frame2}; + + EXPECT_TRUE(classifier->classify(event).isOk()); + // We are not checking the actual classification here, + // because the HAL operation is highly device-specific. + + // Return HAL to a consistent state by doing a reset + classifier->reset(); +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(InputClassifierHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + InputClassifierHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +} diff --git a/input/common/1.0/Android.bp b/input/common/1.0/Android.bp new file mode 100644 index 0000000000..2c7c517cce --- /dev/null +++ b/input/common/1.0/Android.bp @@ -0,0 +1,13 @@ +// 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", + ], + 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..9ad368b3b6 --- /dev/null +++ b/input/common/1.0/types.hal @@ -0,0 +1,846 @@ +/* + * 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). + * On game pads with two analog joysticks, this axis is often reinterpreted + * to report the absolute X position of the second joystick instead. + */ + 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 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 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 is rotated 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 a 10 x 6 matrix: + * + * <-- width --> + * 0 1 2 3 4 5 ^ + * 6 7 8 9 10 11 | + * 12 13 14 15 16 17 | + * 18 ... 23 | + * 24 ... 29 | height + * 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 height=10 and width=6. + * + * If the screen orientation changes to landscape (a 90 degree orientation + * change), the frame's dimensions will become 6 x 10 + * and the data will look as follows: + * 54 48 42 36 30 24 18 12 6 0 ^ + * ... 13 7 1 | + * ... 14 8 2 | height + * ... 15 9 3 | + * ... 16 10 4 | + * 59 53 47 41 35 29 23 17 11 5 v + * <-- width --> + * + * Here the element "0" is at the physical top left of the unrotated screen. + * + * Since the coordinates of a MotionEvent are also adjusted based on the + * orientation, the rotation of the video frame data ensures that + * the axes for MotionEvent and VideoFrame data are consistent. + */ +struct VideoFrame { + /** + * Video frame data. + * Size of the data is height * width. + */ + vec data; + uint32_t height; + uint32_t width; + /** + * 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 flags; + /** + * The motion event policy flags. + */ + bitfield policyFlags; + /** + * The edges, if any, that were touched by this motion event. + */ + bitfield edgeFlags; + /** + * The state of any meta / modifier keys that were in effect when the event was generated. + */ + bitfield metaState; + /** + * The state of buttons that are pressed. + */ + bitfield