From 01d65e01d0772af82f79e25fca6be92e0540f3b8 Mon Sep 17 00:00:00 2001 From: William Escande Date: Tue, 9 May 2023 16:37:45 -0700 Subject: [PATCH 001/152] Fix deathRecipient of BluetoothAudioProvider The "provider" is managed with a shared_ptr but we do not hold it and instead are giving the raw inner pointer as binderDiedCallbackAidl. This can randomly generate crash as the provider may be freed outside of this code. Replacing the provider with a context that we can manually allocate and deallocate. Setup AIBinder_DeathRecipient_setOnUnlinked to clean the data allocated Bug: 245009140 Test: m android.hardware.bluetooth.audio-impl and start / stop session + manually kill bluetooth process during audio play (cherry picked from https://android-review.googlesource.com/q/commit:f3faab081a543ad43e86eec6d03cd7835ef5c712) Merged-In: I0c14c062a8bde7e532ff02f01991d66da33ec569 Change-Id: I0c14c062a8bde7e532ff02f01991d66da33ec569 --- .../aidl/default/BluetoothAudioProvider.cpp | 44 ++++++++++++------- .../aidl/default/BluetoothAudioProvider.h | 3 -- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp index 2a88959af5..727453beca 100644 --- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp +++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp @@ -27,9 +27,31 @@ namespace hardware { namespace bluetooth { namespace audio { +struct BluetoothAudioProviderContext { + SessionType session_type; +}; + +static void binderUnlinkedCallbackAidl(void* cookie) { + LOG(INFO) << __func__; + BluetoothAudioProviderContext* ctx = + static_cast(cookie); + delete ctx; +} + +static void binderDiedCallbackAidl(void* cookie) { + LOG(INFO) << __func__; + BluetoothAudioProviderContext* ctx = + static_cast(cookie); + CHECK_NE(ctx, nullptr); + + BluetoothAudioSessionReport::OnSessionEnded(ctx->session_type); +} + BluetoothAudioProvider::BluetoothAudioProvider() { death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient( AIBinder_DeathRecipient_new(binderDiedCallbackAidl)); + AIBinder_DeathRecipient_setOnUnlinked(death_recipient_.get(), + binderUnlinkedCallbackAidl); } ndk::ScopedAStatus BluetoothAudioProvider::startSession( @@ -45,10 +67,11 @@ ndk::ScopedAStatus BluetoothAudioProvider::startSession( latency_modes_ = latencyModes; audio_config_ = std::make_unique(audio_config); stack_iface_ = host_if; - is_binder_died = false; + BluetoothAudioProviderContext* cookie = + new BluetoothAudioProviderContext{session_type_}; AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(), - this); + cookie); onSessionReady(_aidl_return); return ndk::ScopedAStatus::ok(); @@ -60,10 +83,8 @@ ndk::ScopedAStatus BluetoothAudioProvider::endSession() { if (stack_iface_ != nullptr) { BluetoothAudioSessionReport::OnSessionEnded(session_type_); - if (!is_binder_died) { - AIBinder_unlinkToDeath(stack_iface_->asBinder().get(), - death_recipient_.get(), this); - } + AIBinder_unlinkToDeath(stack_iface_->asBinder().get(), + death_recipient_.get(), this); } else { LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << " has NO session"; @@ -143,17 +164,6 @@ ndk::ScopedAStatus BluetoothAudioProvider::setLowLatencyModeAllowed( return ndk::ScopedAStatus::ok(); } -void BluetoothAudioProvider::binderDiedCallbackAidl(void* ptr) { - LOG(ERROR) << __func__ << " - BluetoothAudio Service died"; - auto provider = static_cast(ptr); - if (provider == nullptr) { - LOG(ERROR) << __func__ << ": Null AudioProvider HAL died"; - return; - } - provider->is_binder_died = true; - provider->endSession(); -} - } // namespace audio } // namespace bluetooth } // namespace hardware diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h index dbfff7d26c..b6e07a1783 100644 --- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h +++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h @@ -54,7 +54,6 @@ class BluetoothAudioProvider : public BnBluetoothAudioProvider { protected: virtual ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) = 0; - static void binderDiedCallbackAidl(void* cookie_ptr); ::ndk::ScopedAIBinder_DeathRecipient death_recipient_; @@ -62,9 +61,7 @@ class BluetoothAudioProvider : public BnBluetoothAudioProvider { std::unique_ptr audio_config_ = nullptr; SessionType session_type_; std::vector latency_modes_; - bool is_binder_died = false; }; - } // namespace audio } // namespace bluetooth } // namespace hardware From d1de935e1dfc8821002f64167cc8d71bd519f527 Mon Sep 17 00:00:00 2001 From: William Escande Date: Tue, 9 May 2023 16:38:23 -0700 Subject: [PATCH 002/152] Improve AudioProvider logging Bug: 245009140 Test: looked at some beautiful log when bluetooth is killed (RIP) (cherry picked from https://android-review.googlesource.com/q/commit:fb6dd74b2c84bf6ab0238760e06bcd3d078011c4) Merged-In: If33bee4e875812ce3710d41014cae8bd54d840f2 Change-Id: If33bee4e875812ce3710d41014cae8bd54d840f2 --- .../audio/aidl/default/BluetoothAudioProvider.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp index 727453beca..9c72e195e3 100644 --- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp +++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp @@ -61,6 +61,8 @@ ndk::ScopedAStatus BluetoothAudioProvider::startSession( DataMQDesc* _aidl_return) { if (host_if == nullptr) { *_aidl_return = DataMQDesc(); + LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_) + << " Illegal argument"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } @@ -73,6 +75,7 @@ ndk::ScopedAStatus BluetoothAudioProvider::startSession( AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(), cookie); + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_); onSessionReady(_aidl_return); return ndk::ScopedAStatus::ok(); } @@ -98,10 +101,9 @@ ndk::ScopedAStatus BluetoothAudioProvider::endSession() { ndk::ScopedAStatus BluetoothAudioProvider::streamStarted( BluetoothAudioStatus status) { - LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) - << ", status=" << toString(status); - if (stack_iface_ != nullptr) { + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << ", status=" << toString(status); BluetoothAudioSessionReport::ReportControlStatus(session_type_, true, status); } else { @@ -129,8 +131,6 @@ ndk::ScopedAStatus BluetoothAudioProvider::streamSuspended( ndk::ScopedAStatus BluetoothAudioProvider::updateAudioConfiguration( const AudioConfiguration& audio_config) { - LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_); - if (stack_iface_ == nullptr || audio_config_ == nullptr) { LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << " has NO session"; @@ -146,13 +146,13 @@ ndk::ScopedAStatus BluetoothAudioProvider::updateAudioConfiguration( audio_config_ = std::make_unique(audio_config); BluetoothAudioSessionReport::ReportAudioConfigChanged(session_type_, *audio_config_); + LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) + << " | audio_config=" << audio_config.toString(); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus BluetoothAudioProvider::setLowLatencyModeAllowed( bool allowed) { - LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_); - if (stack_iface_ == nullptr) { LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << " has NO session"; From 1266c86ea656071d940f597e33c44378f1b8deac Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 12 May 2023 13:51:06 -0700 Subject: [PATCH 003/152] audio: Update hardwired configuration Fill in address for remote submix devices. Specify correct connection type for the remote submix output. Avoid logging entire HAL Engine Config. Bug: 205884982 Test: atest VtsHalAudioCoreTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:26526f15e3996fb8acd132e2a402e6e4afd5158c) Merged-In: I246435e4d3b848b5d0ad9810d13f650603eac76d Change-Id: I246435e4d3b848b5d0ad9810d13f650603eac76d --- audio/aidl/default/Config.cpp | 6 +++++- audio/aidl/default/Configuration.cpp | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp index 87c0ace6d2..e87af071a2 100644 --- a/audio/aidl/default/Config.cpp +++ b/audio/aidl/default/Config.cpp @@ -47,10 +47,14 @@ ndk::ScopedAStatus Config::getEngineConfig(AudioHalEngineConfig* _aidl_return) { LOG(WARNING) << __func__ << mAudioPolicyConverter.getError(); } } + // Logging full contents of the config is an overkill, just provide statistics. + LOG(DEBUG) << "getEngineConfig: number of strategies parsed: " + << engConfig.productStrategies.size() + << ", default strategy: " << engConfig.defaultProductStrategyId + << ", number of volume groups parsed: " << engConfig.volumeGroups.size(); return engConfig; }(); *_aidl_return = returnEngCfg; - LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString(); return ndk::ScopedAStatus::ok(); } } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index e1e1f79376..d41ea67329 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -81,6 +81,8 @@ static AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags, deviceExt.device.address = "bottom"; } else if (devType == AudioDeviceType::IN_MICROPHONE_BACK && connection.empty()) { deviceExt.device.address = "back"; + } else if (devType == AudioDeviceType::IN_SUBMIX || devType == AudioDeviceType::OUT_SUBMIX) { + deviceExt.device.address = "0"; } deviceExt.device.type.connection = std::move(connection); deviceExt.flags = flags; @@ -365,8 +367,10 @@ std::unique_ptr getRSubmixConfiguration() { // Device ports - AudioPort rsubmixOutDevice = createPort(c.nextPortId++, "Remote Submix Out", 0, false, - createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0)); + AudioPort rsubmixOutDevice = + createPort(c.nextPortId++, "Remote Submix Out", 0, false, + createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0, + AudioDeviceDescription::CONNECTION_VIRTUAL)); rsubmixOutDevice.profiles.push_back( createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixOutDevice); From eed3211f33ee2d3be04d7555ad380325d9fa4437 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 15 May 2023 14:35:24 -0700 Subject: [PATCH 004/152] audio: Enable more compile time checks in the default impl Enable "-Wall, Wextra, Werror, Wthread-safety", fix discovered issues. Bug: 205884982 Test: m (cherry picked from https://android-review.googlesource.com/q/commit:b511b8aa2179f0c5dd4e5cc180258995e6b41714) Merged-In: I0a8d3095dd24dbb3bc7cf6569c1f71945cd55168 Change-Id: I0a8d3095dd24dbb3bc7cf6569c1f71945cd55168 --- audio/aidl/default/Android.bp | 6 ++++++ audio/aidl/default/Module.cpp | 4 ++-- audio/aidl/default/usb/StreamUsb.cpp | 11 +++++++---- audio/aidl/default/usb/UsbAlsaMixerControl.cpp | 15 ++++----------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index c9edae0aa7..31ed044514 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -92,6 +92,12 @@ cc_library { "audio_policy_configuration_aidl_default", "audio_policy_engine_configuration_aidl_default", ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-Wthread-safety", + ], } cc_binary { diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 6b417a4331..6885a49d6b 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -187,7 +187,7 @@ ndk::ScopedAStatus Module::createStreamContext( return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } LOG(DEBUG) << __func__ << ": frame size " << frameSize << " bytes"; - if (frameSize > kMaximumStreamBufferSizeBytes / in_bufferSizeFrames) { + if (frameSize > static_cast(kMaximumStreamBufferSizeBytes / in_bufferSizeFrames)) { LOG(ERROR) << __func__ << ": buffer size " << in_bufferSizeFrames << " frames is too large, maximum size is " << kMaximumStreamBufferSizeBytes / frameSize; @@ -281,7 +281,7 @@ ndk::ScopedAStatus Module::findPortIdForNewStream(int32_t in_portConfigId, Audio << " does not correspond to a mix port"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } - const int32_t maxOpenStreamCount = portIt->ext.get().maxOpenStreamCount; + const size_t maxOpenStreamCount = portIt->ext.get().maxOpenStreamCount; if (maxOpenStreamCount != 0 && mStreams.count(portId) >= maxOpenStreamCount) { LOG(ERROR) << __func__ << ": port id " << portId << " has already reached maximum allowed opened stream count: " diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index 5d1d7febc8..9ac1cc9b77 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -106,10 +106,13 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput) ::android::status_t DriverUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { - if (!mConfig.has_value() || mConnectedDevices.empty()) { - LOG(ERROR) << __func__ << ": failed, has config: " << mConfig.has_value() - << ", has connected devices: " << mConnectedDevices.empty(); - return ::android::NO_INIT; + { + std::lock_guard guard(mLock); + if (!mConfig.has_value() || mConnectedDevices.empty()) { + LOG(ERROR) << __func__ << ": failed, has config: " << mConfig.has_value() + << ", has connected devices: " << mConnectedDevices.empty(); + return ::android::NO_INIT; + } } if (mIsStandby) { if (::android::status_t status = exitStandby(); status != ::android::OK) { diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp index b5337d1642..6c0c24bc09 100644 --- a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp +++ b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp @@ -99,16 +99,6 @@ int volumeFloatToInteger(float fValue, int maxValue, int minValue) { return minValue + std::ceil((maxValue - minValue) * fValue); } -float volumeIntegerToFloat(int iValue, int maxValue, int minValue) { - if (iValue > maxValue) { - return 1.0f; - } - if (iValue < minValue) { - return 0.0f; - } - return static_cast(iValue - minValue) / (maxValue - minValue); -} - } // namespace ndk::ScopedAStatus AlsaMixer::setMasterMute(bool muted) { @@ -146,11 +136,14 @@ ndk::ScopedAStatus AlsaMixer::setVolumes(std::vector volumes) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } const int numValues = it->second->getNumValues(); + if (numValues < 0) { + LOG(FATAL) << __func__ << ": negative number of values: " << numValues; + } const int maxValue = it->second->getMaxValue(); const int minValue = it->second->getMinValue(); std::vector values; size_t i = 0; - for (; i < numValues && i < values.size(); ++i) { + for (; i < static_cast(numValues) && i < values.size(); ++i) { values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue)); } if (int err = it->second->setArray(values.data(), values.size()); err != 0) { From 2a51f6db2b8ed8ce71bae59c58b5046dc222f5b1 Mon Sep 17 00:00:00 2001 From: Lorena Torres-Huerta Date: Mon, 12 Dec 2022 18:17:10 +0000 Subject: [PATCH 005/152] audio: Provide code for parsing surround sound config from XML The main change is to convert the result of parsing from XSDC types to AIDL, and add a VTS test for IConfig.getSurroundSoundConfig. Extra changes: - add 'Unchecked' suffix to conversion functions that do not wrap the result into ConversionResult; - enable more compile-time checks for the default AIDL service, fix issues found. Bug: 205884982 Test: atest VtsHalAudioCoreTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:aa8f76af92cc0f706e0bd13508c7b6b596e0aac4) Merged-In: Icf578b8d28647e6355ed5328599c77d2ca1234f9 Change-Id: Icf578b8d28647e6355ed5328599c77d2ca1234f9 --- audio/aidl/common/include/Utils.h | 3 +- audio/aidl/default/AidlConversionXsdc.cpp | 56 ++++++++++++++++ audio/aidl/default/Android.bp | 22 ++++++ .../default/AudioPolicyConfigXmlConverter.cpp | 67 ++++++++++++++++++- audio/aidl/default/Config.cpp | 13 +++- .../aidl/default/EngineConfigXmlConverter.cpp | 45 ++++++------- .../include/core-impl/AidlConversionXsdc.h | 32 +++++++++ .../core-impl/AudioPolicyConfigXmlConverter.h | 5 +- .../default/include/core-impl/XmlConverter.h | 12 ++-- audio/aidl/default/main.cpp | 1 + .../vts/VtsHalAudioCoreConfigTargetTest.cpp | 55 ++++++++++++++- 11 files changed, 274 insertions(+), 37 deletions(-) create mode 100644 audio/aidl/default/AidlConversionXsdc.cpp create mode 100644 audio/aidl/default/include/core-impl/AidlConversionXsdc.h diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h index 305c92471e..dd7975d1be 100644 --- a/audio/aidl/common/include/Utils.h +++ b/audio/aidl/common/include/Utils.h @@ -102,7 +102,8 @@ constexpr size_t getFrameSizeInBytes( constexpr bool isDefaultAudioFormat( const ::aidl::android::media::audio::common::AudioFormatDescription& desc) { return desc.type == ::aidl::android::media::audio::common::AudioFormatType::DEFAULT && - desc.pcm == ::aidl::android::media::audio::common::PcmType::DEFAULT; + desc.pcm == ::aidl::android::media::audio::common::PcmType::DEFAULT && + desc.encoding.empty(); } constexpr bool isTelephonyDeviceType( diff --git a/audio/aidl/default/AidlConversionXsdc.cpp b/audio/aidl/default/AidlConversionXsdc.cpp new file mode 100644 index 0000000000..c404d6728b --- /dev/null +++ b/audio/aidl/default/AidlConversionXsdc.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_AidlXsdc" +#include +#include +#include +#include + +#include "core-impl/AidlConversionXsdc.h" + +using aidl::android::media::audio::common::AudioFormatDescription; + +namespace xsd = android::audio::policy::configuration; + +namespace aidl::android::hardware::audio::core::internal { + +ConversionResult xsdc2aidl_AudioFormatDescription(const std::string& xsdc) { + return legacy2aidl_audio_format_t_AudioFormatDescription(::android::formatFromString(xsdc)); +} + +ConversionResult xsdc2aidl_SurroundFormatFamily( + const ::xsd::SurroundFormats::Format& xsdc) { + SurroundSoundConfig::SurroundFormatFamily aidl; + aidl.primaryFormat = VALUE_OR_RETURN(xsdc2aidl_AudioFormatDescription(xsdc.getName())); + if (xsdc.hasSubformats()) { + aidl.subFormats = VALUE_OR_RETURN(convertContainer>( + xsdc.getSubformats(), xsdc2aidl_AudioFormatDescription)); + } + return aidl; +} + +ConversionResult xsdc2aidl_SurroundSoundConfig( + const ::xsd::SurroundSound& xsdc) { + SurroundSoundConfig aidl; + if (!xsdc.hasFormats() || !xsdc.getFirstFormats()->hasFormat()) return aidl; + aidl.formatFamilies = VALUE_OR_RETURN( + convertContainer>( + xsdc.getFirstFormats()->getFormat(), xsdc2aidl_SurroundFormatFamily)); + return aidl; +} + +} // namespace aidl::android::hardware::audio::core::internal diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 31ed044514..bda0de2b6d 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -65,6 +65,7 @@ cc_library { ], export_include_dirs: ["include"], srcs: [ + "AidlConversionXsdc.cpp", "AudioPolicyConfigXmlConverter.cpp", "Bluetooth.cpp", "Config.cpp", @@ -92,11 +93,20 @@ cc_library { "audio_policy_configuration_aidl_default", "audio_policy_engine_configuration_aidl_default", ], + shared_libs: [ + "libaudio_aidl_conversion_common_ndk", + "libmedia_helper", + "libstagefright_foundation", + ], + export_shared_lib_headers: [ + "libaudio_aidl_conversion_common_ndk", + ], cflags: [ "-Wall", "-Wextra", "-Werror", "-Wthread-safety", + "-DBACKEND_NDK", ], } @@ -114,7 +124,19 @@ cc_binary { static_libs: [ "libaudioserviceexampleimpl", ], + shared_libs: [ + "libaudio_aidl_conversion_common_ndk", + "libmedia_helper", + "libstagefright_foundation", + ], srcs: ["main.cpp"], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-Wthread-safety", + "-DBACKEND_NDK", + ], } cc_defaults { diff --git a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp index 6290912774..2848d719c7 100644 --- a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp +++ b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp @@ -21,11 +21,17 @@ #include #include +#define LOG_TAG "AHAL_ApmXmlConverter" +#include + #include +#include #include +#include "core-impl/AidlConversionXsdc.h" #include "core-impl/AudioPolicyConfigXmlConverter.h" +using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioHalEngineConfig; using aidl::android::media::audio::common::AudioHalVolumeCurve; using aidl::android::media::audio::common::AudioHalVolumeGroup; @@ -68,13 +74,13 @@ AudioHalVolumeCurve AudioPolicyConfigXmlConverter::convertVolumeCurveToAidl( getXsdcConfig()->getVolumes()); } aidlVolumeCurve.curvePoints = - convertCollectionToAidl( + convertCollectionToAidlUnchecked( mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(), std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this, std::placeholders::_1)); } else { aidlVolumeCurve.curvePoints = - convertCollectionToAidl( + convertCollectionToAidlUnchecked( xsdcVolumeCurve.getPoint(), std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this, std::placeholders::_1)); @@ -87,6 +93,22 @@ void AudioPolicyConfigXmlConverter::mapStreamToVolumeCurve(const xsd::Volume& xs convertVolumeCurveToAidl(xsdcVolumeCurve)); } +const SurroundSoundConfig& AudioPolicyConfigXmlConverter::getSurroundSoundConfig() { + static const SurroundSoundConfig aidlSurroundSoundConfig = [this]() { + if (auto xsdcConfig = getXsdcConfig(); xsdcConfig && xsdcConfig->hasSurroundSound()) { + auto configConv = xsdc2aidl_SurroundSoundConfig(*xsdcConfig->getFirstSurroundSound()); + if (configConv.ok()) { + return configConv.value(); + } + LOG(ERROR) << "There was an error converting surround formats to AIDL: " + << configConv.error(); + } + LOG(WARNING) << "Audio policy config does not have section, using default"; + return getDefaultSurroundSoundConfig(); + }(); + return aidlSurroundSoundConfig; +} + const AudioHalEngineConfig& AudioPolicyConfigXmlConverter::getAidlEngineConfig() { if (mAidlEngineConfig.volumeGroups.empty() && getXsdcConfig() && getXsdcConfig()->hasVolumes()) { @@ -95,6 +117,47 @@ const AudioHalEngineConfig& AudioPolicyConfigXmlConverter::getAidlEngineConfig() return mAidlEngineConfig; } +// static +const SurroundSoundConfig& AudioPolicyConfigXmlConverter::getDefaultSurroundSoundConfig() { + // Provide a config similar to the one used by the framework by default + // (see AudioPolicyConfig::setDefaultSurroundFormats). +#define ENCODED_FORMAT(format) \ + AudioFormatDescription { \ + .encoding = ::android::format \ + } +#define SIMPLE_FORMAT(format) \ + SurroundSoundConfig::SurroundFormatFamily { \ + .primaryFormat = ENCODED_FORMAT(format) \ + } + + static const SurroundSoundConfig defaultConfig = { + .formatFamilies = { + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_AC3), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_EAC3), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD_MA), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_EAC3_JOC), + SurroundSoundConfig::SurroundFormatFamily{ + .primaryFormat = ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_LC), + .subFormats = + { + ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_HE_V1), + ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_HE_V2), + ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_ELD), + ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_XHE), + }}, + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_AC4), + }}; +#undef SIMPLE_FORMAT +#undef ENCODED_FORMAT + + return defaultConfig; +} + void AudioPolicyConfigXmlConverter::mapStreamsToVolumeCurves() { if (getXsdcConfig()->hasVolumes()) { for (const xsd::Volumes& xsdcWrapperType : getXsdcConfig()->getVolumes()) { diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp index e87af071a2..d1023da6f5 100644 --- a/audio/aidl/default/Config.cpp +++ b/audio/aidl/default/Config.cpp @@ -27,9 +27,16 @@ using aidl::android::media::audio::common::AudioHalEngineConfig; namespace aidl::android::hardware::audio::core { ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) { - SurroundSoundConfig surroundSoundConfig; - // TODO: parse from XML; for now, use empty config as default - *_aidl_return = std::move(surroundSoundConfig); + static const SurroundSoundConfig surroundSoundConfig = [this]() { + SurroundSoundConfig surroundCfg; + if (mAudioPolicyConverter.getStatus() == ::android::OK) { + surroundCfg = mAudioPolicyConverter.getSurroundSoundConfig(); + } else { + LOG(WARNING) << __func__ << mAudioPolicyConverter.getError(); + } + return surroundCfg; + }(); + *_aidl_return = surroundSoundConfig; LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString(); return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/default/EngineConfigXmlConverter.cpp b/audio/aidl/default/EngineConfigXmlConverter.cpp index 5f17d7125d..96b555c640 100644 --- a/audio/aidl/default/EngineConfigXmlConverter.cpp +++ b/audio/aidl/default/EngineConfigXmlConverter.cpp @@ -140,7 +140,7 @@ AudioHalAttributesGroup EngineConfigXmlConverter::convertAttributesGroupToAidl( aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup(); if (xsdcAttributesGroup.hasAttributes_optional()) { aidlAttributesGroup.attributes = - convertCollectionToAidl( + convertCollectionToAidlUnchecked( xsdcAttributesGroup.getAttributes_optional(), std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this, std::placeholders::_1)); @@ -172,7 +172,7 @@ AudioHalProductStrategy EngineConfigXmlConverter::convertProductStrategyToAidl( if (xsdcProductStrategy.hasAttributesGroup()) { aidlProductStrategy.attributesGroups = - convertCollectionToAidl( + convertCollectionToAidlUnchecked( xsdcProductStrategy.getAttributesGroup(), std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this, std::placeholders::_1)); @@ -204,13 +204,13 @@ AudioHalVolumeCurve EngineConfigXmlConverter::convertVolumeCurveToAidl( getXsdcConfig()->getVolumes()); } aidlVolumeCurve.curvePoints = - convertCollectionToAidl( + convertCollectionToAidlUnchecked( mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(), std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this, std::placeholders::_1)); } else { aidlVolumeCurve.curvePoints = - convertCollectionToAidl( + convertCollectionToAidlUnchecked( xsdcVolumeCurve.getPoint(), std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this, std::placeholders::_1)); @@ -224,10 +224,11 @@ AudioHalVolumeGroup EngineConfigXmlConverter::convertVolumeGroupToAidl( aidlVolumeGroup.name = xsdcVolumeGroup.getName(); aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin(); aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax(); - aidlVolumeGroup.volumeCurves = convertCollectionToAidl( - xsdcVolumeGroup.getVolume(), - std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this, - std::placeholders::_1)); + aidlVolumeGroup.volumeCurves = + convertCollectionToAidlUnchecked( + xsdcVolumeGroup.getVolume(), + std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this, + std::placeholders::_1)); return aidlVolumeGroup; } @@ -251,7 +252,7 @@ AudioHalCapCriterionType EngineConfigXmlConverter::convertCapCriterionTypeToAidl aidlCapCriterionType.name = xsdcCriterionType.getName(); aidlCapCriterionType.isInclusive = !(static_cast(xsdcCriterionType.getType())); aidlCapCriterionType.values = - convertWrappedCollectionToAidl( + convertWrappedCollectionToAidlUnchecked( xsdcCriterionType.getValues(), &xsd::ValuesType::getValue, std::bind(&EngineConfigXmlConverter::convertCriterionTypeValueToAidl, this, std::placeholders::_1)); @@ -266,9 +267,9 @@ void EngineConfigXmlConverter::init() { initProductStrategyMap(); if (getXsdcConfig()->hasProductStrategies()) { mAidlEngineConfig.productStrategies = - convertWrappedCollectionToAidl( + convertWrappedCollectionToAidlUnchecked( getXsdcConfig()->getProductStrategies(), &xsd::ProductStrategies::getProductStrategy, std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this, @@ -278,7 +279,7 @@ void EngineConfigXmlConverter::init() { } } if (getXsdcConfig()->hasVolumeGroups()) { - mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidl< + mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidlUnchecked< xsd::VolumeGroupsType, xsd::VolumeGroupsType::VolumeGroup, AudioHalVolumeGroup>( getXsdcConfig()->getVolumeGroups(), &xsd::VolumeGroupsType::getVolumeGroup, std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this, @@ -287,19 +288,17 @@ void EngineConfigXmlConverter::init() { if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) { AudioHalEngineConfig::CapSpecificConfig capSpecificConfig; capSpecificConfig.criteria = - convertWrappedCollectionToAidl( + convertWrappedCollectionToAidlUnchecked( getXsdcConfig()->getCriteria(), &xsd::CriteriaType::getCriterion, std::bind(&EngineConfigXmlConverter::convertCapCriterionToAidl, this, std::placeholders::_1)); - capSpecificConfig.criterionTypes = - convertWrappedCollectionToAidl( - getXsdcConfig()->getCriterion_types(), - &xsd::CriterionTypesType::getCriterion_type, - std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this, - std::placeholders::_1)); + capSpecificConfig.criterionTypes = convertWrappedCollectionToAidlUnchecked< + xsd::CriterionTypesType, xsd::CriterionTypeType, AudioHalCapCriterionType>( + getXsdcConfig()->getCriterion_types(), &xsd::CriterionTypesType::getCriterion_type, + std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this, + std::placeholders::_1)); mAidlEngineConfig.capSpecificConfig = capSpecificConfig; } } -} // namespace aidl::android::hardware::audio::core::internal \ No newline at end of file +} // namespace aidl::android::hardware::audio::core::internal diff --git a/audio/aidl/default/include/core-impl/AidlConversionXsdc.h b/audio/aidl/default/include/core-impl/AidlConversionXsdc.h new file mode 100644 index 0000000000..c9aefc7cd8 --- /dev/null +++ b/audio/aidl/default/include/core-impl/AidlConversionXsdc.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace aidl::android::hardware::audio::core::internal { + +ConversionResult<::aidl::android::media::audio::common::AudioFormatDescription> +xsdc2aidl_AudioFormatDescription(const std::string& xsdc); + +ConversionResult xsdc2aidl_SurroundSoundConfig( + const ::android::audio::policy::configuration::SurroundSound& xsdc); + +} // namespace aidl::android::hardware::audio::core::internal diff --git a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h index 47918f0839..94501a81ba 100644 --- a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h +++ b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -35,8 +36,11 @@ class AudioPolicyConfigXmlConverter { ::android::status_t getStatus() const { return mConverter.getStatus(); } const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig(); + const SurroundSoundConfig& getSurroundSoundConfig(); private: + static const SurroundSoundConfig& getDefaultSurroundSoundConfig(); + const std::optional<::android::audio::policy::configuration::AudioPolicyConfiguration>& getXsdcConfig() const { return mConverter.getXsdcConfig(); @@ -48,7 +52,6 @@ class AudioPolicyConfigXmlConverter { void parseVolumes(); ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl( const std::string& xsdcCurvePoint); - ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl( const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve); diff --git a/audio/aidl/default/include/core-impl/XmlConverter.h b/audio/aidl/default/include/core-impl/XmlConverter.h index ec23edb70a..a68a6fdde9 100644 --- a/audio/aidl/default/include/core-impl/XmlConverter.h +++ b/audio/aidl/default/include/core-impl/XmlConverter.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -78,7 +79,7 @@ class XmlConverter { * */ template -static std::vector convertWrappedCollectionToAidl( +std::vector convertWrappedCollectionToAidlUnchecked( const std::vector& xsdcWrapperTypeVec, std::function&(const W&)> getInnerTypeVec, std::function convertToAidl) { @@ -100,12 +101,12 @@ static std::vector convertWrappedCollectionToAidl( } template -static std::vector convertCollectionToAidl(const std::vector& xsdcTypeVec, - std::function convertToAidl) { +std::vector convertCollectionToAidlUnchecked(const std::vector& xsdcTypeVec, + std::function itemConversion) { std::vector resultAidlTypeVec; resultAidlTypeVec.reserve(xsdcTypeVec.size()); std::transform(xsdcTypeVec.begin(), xsdcTypeVec.end(), std::back_inserter(resultAidlTypeVec), - convertToAidl); + itemConversion); return resultAidlTypeVec; } @@ -121,8 +122,7 @@ static std::vector convertCollectionToAidl(const std::vector& xsdcTypeVec, * */ template -static std::unordered_map generateReferenceMap( - const std::vector& xsdcWrapperTypeVec) { +std::unordered_map generateReferenceMap(const std::vector& xsdcWrapperTypeVec) { std::unordered_map resultMap; if (!xsdcWrapperTypeVec.empty()) { /* diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp index af71aa872e..12c0c4b53e 100644 --- a/audio/aidl/default/main.cpp +++ b/audio/aidl/default/main.cpp @@ -64,6 +64,7 @@ int main() { auto modules = {createModule(Module::Type::DEFAULT, "default"), createModule(Module::Type::R_SUBMIX, "r_submix"), createModule(Module::Type::USB, "usb")}; + (void)modules; ABinderProcess_joinThreadPool(); return EXIT_FAILURE; // should not reach diff --git a/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp index e5e06ebce2..f82e8e57c6 100644 --- a/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp @@ -20,21 +20,27 @@ #include #include +#define LOG_TAG "VtsHalAudioCore.Config" + +#include #include #include #include #include #include -#define LOG_TAG "VtsHalAudioCore.Config" #include #include "AudioHalBinderServiceUtil.h" #include "TestUtils.h" using namespace android; +using aidl::android::hardware::audio::common::isDefaultAudioFormat; using aidl::android::hardware::audio::core::IConfig; +using aidl::android::hardware::audio::core::SurroundSoundConfig; using aidl::android::media::audio::common::AudioAttributes; using aidl::android::media::audio::common::AudioFlag; +using aidl::android::media::audio::common::AudioFormatDescription; +using aidl::android::media::audio::common::AudioFormatType; using aidl::android::media::audio::common::AudioHalAttributesGroup; using aidl::android::media::audio::common::AudioHalCapCriterion; using aidl::android::media::audio::common::AudioHalCapCriterionType; @@ -46,6 +52,7 @@ using aidl::android::media::audio::common::AudioProductStrategyType; using aidl::android::media::audio::common::AudioSource; using aidl::android::media::audio::common::AudioStreamType; using aidl::android::media::audio::common::AudioUsage; +using aidl::android::media::audio::common::PcmType; class AudioCoreConfig : public testing::TestWithParam { public: @@ -58,6 +65,7 @@ class AudioCoreConfig : public testing::TestWithParam { void RestartService() { ASSERT_NE(mConfig, nullptr); mEngineConfig.reset(); + mSurroundSoundConfig.reset(); mConfig = IConfig::fromBinder(mBinderUtil.restartService()); ASSERT_NE(mConfig, nullptr); } @@ -70,6 +78,14 @@ class AudioCoreConfig : public testing::TestWithParam { } } + void SetUpSurroundSoundConfig() { + if (mSurroundSoundConfig == nullptr) { + auto tempConfig = std::make_unique(); + ASSERT_IS_OK(mConfig->getSurroundSoundConfig(tempConfig.get())); + mSurroundSoundConfig = std::move(tempConfig); + } + } + static bool IsProductStrategyTypeReservedForSystemUse(const AudioProductStrategyType& pst) { switch (pst) { case AudioProductStrategyType::SYS_RESERVED_NONE: @@ -325,9 +341,41 @@ class AudioCoreConfig : public testing::TestWithParam { } } + void ValidateAudioFormatDescription(const AudioFormatDescription& format) { + EXPECT_NE(AudioFormatType::SYS_RESERVED_INVALID, format.type); + if (format.type == AudioFormatType::PCM) { + EXPECT_NE(PcmType::DEFAULT, format.pcm); + EXPECT_TRUE(format.encoding.empty()) << format.encoding; + } else { + EXPECT_FALSE(format.encoding.empty()); + } + } + + /** + * Verify that the surround sound configuration is not empty. + * Verify each of the formatFamilies has a non-empty primaryFormat. + * Verify that each format only appears once. + */ + void ValidateSurroundSoundConfig() { + EXPECT_FALSE(mSurroundSoundConfig->formatFamilies.empty()); + std::set formatSet; + for (const SurroundSoundConfig::SurroundFormatFamily& family : + mSurroundSoundConfig->formatFamilies) { + EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(family.primaryFormat)); + EXPECT_FALSE(isDefaultAudioFormat(family.primaryFormat)); + EXPECT_TRUE(formatSet.insert(family.primaryFormat).second); + for (const AudioFormatDescription& subformat : family.subFormats) { + EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(subformat)); + EXPECT_FALSE(isDefaultAudioFormat(subformat)); + EXPECT_TRUE(formatSet.insert(subformat).second); + } + } + } + private: std::shared_ptr mConfig; std::unique_ptr mEngineConfig; + std::unique_ptr mSurroundSoundConfig; AudioHalBinderServiceUtil mBinderUtil; }; @@ -344,6 +392,11 @@ TEST_P(AudioCoreConfig, GetEngineConfigIsValid) { EXPECT_NO_FATAL_FAILURE(ValidateAudioHalEngineConfig()); } +TEST_P(AudioCoreConfig, GetSurroundSoundConfigIsValid) { + ASSERT_NO_FATAL_FAILURE(SetUpSurroundSoundConfig()); + EXPECT_NO_FATAL_FAILURE(ValidateSurroundSoundConfig()); +} + INSTANTIATE_TEST_SUITE_P(AudioCoreConfigTest, AudioCoreConfig, testing::ValuesIn(android::getAidlHalInstanceNames(IConfig::descriptor)), android::PrintInstanceNameToString); From ac3635efbe33d7e93a963c678c0be503d9852422 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 19 May 2023 20:08:53 -0700 Subject: [PATCH 006/152] audio: Fix the comment about threading of DriverInterface::init 'DriverInterface::init' is called on the same thread as other interface methods (the worker thread), except for 'setConnectedDevices'. Update the comment to reflect this, and rearrange the methods order in the interface. Bug: 283463913 Test: m (cherry picked from https://android-review.googlesource.com/q/commit:37551347204c461e709929d798c5a85327f1a7bb) Merged-In: I8937506d20ff8233b4b934c421173ce2bec9d43e Change-Id: I8937506d20ff8233b4b934c421173ce2bec9d43e --- audio/aidl/default/include/core-impl/Stream.h | 15 +++++++-------- audio/aidl/default/include/core-impl/StreamStub.h | 7 ++++--- audio/aidl/default/include/core-impl/StreamUsb.h | 7 ++++--- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 65680df664..476f1ff30d 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -155,20 +155,19 @@ class StreamContext { struct DriverInterface { using CreateInstance = std::function; virtual ~DriverInterface() = default; - // This function is called once, on the main thread, before starting the worker thread. - virtual ::android::status_t init() = 0; - // This function is called from Binder pool thread. It must be done in a thread-safe manner - // if this method and other methods in this interface share data. - virtual ::android::status_t setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& - connectedDevices) = 0; - // All the functions below are called on the worker thread. + // All the methods below are called on the worker thread. + virtual ::android::status_t init() = 0; // This function is only called once. virtual ::android::status_t drain(StreamDescriptor::DrainMode mode) = 0; virtual ::android::status_t flush() = 0; virtual ::android::status_t pause() = 0; virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) = 0; virtual ::android::status_t standby() = 0; + // The method below is called from a thread of the Binder pool. Access to data shared with other + // methods of this interface must be done in a thread-safe manner. + virtual ::android::status_t setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& + connectedDevices) = 0; }; class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic { diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index df0182cf9f..436e610ccf 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -24,15 +24,16 @@ class DriverStub : public DriverInterface { public: DriverStub(const StreamContext& context, bool isInput); ::android::status_t init() override; - ::android::status_t setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices) - override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; ::android::status_t standby() override; + // Note: called on a different thread. + ::android::status_t setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices) + override; private: const size_t mFrameSizeBytes; diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 36e64cbcdb..05d889a713 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -34,15 +34,16 @@ class DriverUsb : public DriverInterface { public: DriverUsb(const StreamContext& context, bool isInput); ::android::status_t init() override; - ::android::status_t setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices) - override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; ::android::status_t standby() override; + // Note: called on a different thread. + ::android::status_t setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices) + override; private: ::android::status_t exitStandby(); From e924b55037e7d3352731224c10017bc484972eec Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 22 May 2023 13:52:50 -0700 Subject: [PATCH 007/152] audio: Add more legacy channel masks for the input direction This is in order to achieve a better parity both with legacy output channel masks and AIDL channel layouts. The change only affects the XSD schema used to generate a parser for legacy configuration files. Bug: 283542128 Test: atest audio_aidl_conversion_tests (cherry picked from https://android-review.googlesource.com/q/commit:310b1c6e7e277577b991414c016dcf645e47ea1d) Merged-In: Ic69b94f6ec650e0814f0200dbef219567eac9fe2 Change-Id: Ic69b94f6ec650e0814f0200dbef219567eac9fe2 --- audio/aidl/default/config/audioPolicy/api/current.txt | 5 +++++ .../config/audioPolicy/audio_policy_configuration.xsd | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt index fabb93b48e..e2bc833d43 100644 --- a/audio/aidl/default/config/audioPolicy/api/current.txt +++ b/audio/aidl/default/config/audioPolicy/api/current.txt @@ -33,14 +33,19 @@ package android.audio.policy.configuration { enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_8; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_9; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT0POINT2; + enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT1; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT1POINT2; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT0POINT2; + enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT1; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT1POINT2; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_5POINT1; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_6; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_FRONT_BACK; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_MONO; + enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_PENTA; + enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_QUAD; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_STEREO; + enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_TRI; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_CALL_MONO; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO; enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO; diff --git a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd index d57790aab4..9a3a447b5f 100644 --- a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd +++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd @@ -535,12 +535,17 @@ + + + + + From 8baa50b00705bd482d5b18639f831c71ca200db4 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Tue, 16 May 2023 11:10:00 +0800 Subject: [PATCH 008/152] Replace the function 'OnRcpReset()' with 'HardwareReset()' The lastest OpenThread source code has removed the function 'OnRcpReset()' and added the function 'HardwareReset()'. This CL replaces the function 'OnRcpReset()' with 'HardwareReset()'. Bug: b/281629567 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fc01bfdd2867bbcf82de8f930004928a01020e1a) Merged-In: I9e77970903656e7c7b66078fb5a380f6630d639b Change-Id: I9e77970903656e7c7b66078fb5a380f6630d639b --- staging/threadnetwork/aidl/default/thread_chip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staging/threadnetwork/aidl/default/thread_chip.cpp b/staging/threadnetwork/aidl/default/thread_chip.cpp index 38abad4ab5..9bd729d57e 100644 --- a/staging/threadnetwork/aidl/default/thread_chip.cpp +++ b/staging/threadnetwork/aidl/default/thread_chip.cpp @@ -170,7 +170,7 @@ ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector& in_fr } ndk::ScopedAStatus ThreadChip::reset() { - mInterface.OnRcpReset(); + mInterface.HardwareReset(); ALOGI("reset()"); return ndk::ScopedAStatus::ok(); } From 71965ef98a2f8403e83fe84f0a5b8d5102aefd3e Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Fri, 9 Jun 2023 16:09:12 +0800 Subject: [PATCH 009/152] remove the Thread Network HAL from the stage folder The Thread Network HAL is going to be added to the AOSP. The implementation of the Thread Network HAL under the staging folder is no longer needed. This commit removes the unstable Thread Network HAL. Bug: 283905423 Test: Build (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b044d98115f19fa6d1e430fd6065a372153f8680) Merged-In: I7e4bf260c03dd0500725fec068747e3b3d05820c Change-Id: I7e4bf260c03dd0500725fec068747e3b3d05820c --- staging/threadnetwork/OWNERS | 5 - staging/threadnetwork/README.md | 12 -- staging/threadnetwork/aidl/Android.bp | 26 --- .../hardware/threadnetwork/IThreadChip.aidl | 88 -------- .../threadnetwork/IThreadChipCallback.aidl | 30 --- staging/threadnetwork/aidl/default/Android.bp | 63 ------ ...roid.hardware.threadnetwork-service.sim.rc | 3 - staging/threadnetwork/aidl/default/main.cpp | 30 --- .../threadnetwork/aidl/default/service.cpp | 90 -------- .../threadnetwork/aidl/default/service.hpp | 42 ---- .../aidl/default/thread_chip.cpp | 197 ------------------ .../aidl/default/thread_chip.hpp | 68 ------ staging/threadnetwork/aidl/default/utils.cpp | 34 --- staging/threadnetwork/aidl/vts/Android.bp | 47 ----- .../vts/VtsHalThreadNetworkTargetTest.cpp | 149 ------------- 15 files changed, 884 deletions(-) delete mode 100644 staging/threadnetwork/OWNERS delete mode 100644 staging/threadnetwork/README.md delete mode 100644 staging/threadnetwork/aidl/Android.bp delete mode 100644 staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl delete mode 100644 staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl delete mode 100644 staging/threadnetwork/aidl/default/Android.bp delete mode 100644 staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc delete mode 100644 staging/threadnetwork/aidl/default/main.cpp delete mode 100644 staging/threadnetwork/aidl/default/service.cpp delete mode 100644 staging/threadnetwork/aidl/default/service.hpp delete mode 100644 staging/threadnetwork/aidl/default/thread_chip.cpp delete mode 100644 staging/threadnetwork/aidl/default/thread_chip.hpp delete mode 100644 staging/threadnetwork/aidl/default/utils.cpp delete mode 100644 staging/threadnetwork/aidl/vts/Android.bp delete mode 100644 staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp diff --git a/staging/threadnetwork/OWNERS b/staging/threadnetwork/OWNERS deleted file mode 100644 index 037215d70f..0000000000 --- a/staging/threadnetwork/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# Bug component: 1203089 - -wgtdkp@google.com -xyk@google.com -zhanglongxia@google.com diff --git a/staging/threadnetwork/README.md b/staging/threadnetwork/README.md deleted file mode 100644 index 12104e5f4d..0000000000 --- a/staging/threadnetwork/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Staging threadnetwork HAL interface - -The directory includes the unstable/unreleased version of `hardware/interfaces/threadnetwork` -code which should **NOT** be used in production. But vendors may start verifying their hardware -with the HAL interface. - -This directory will be cleaned up when the stable Thread HAL interface is added in -`hardware/interfaces/threadnetwork` by version `V` or later. - -More information about _Thread_: -- https://www.threadgroup.org -- https://openthread.io diff --git a/staging/threadnetwork/aidl/Android.bp b/staging/threadnetwork/aidl/Android.bp deleted file mode 100644 index b59d6da3f5..0000000000 --- a/staging/threadnetwork/aidl/Android.bp +++ /dev/null @@ -1,26 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -aidl_interface { - name: "android.hardware.threadnetwork", - host_supported: true, - vendor_available: true, - - srcs: [ - "android/hardware/threadnetwork/*.aidl", - ], - - unstable: true, - - backend: { - ndk: { - enabled: true, - }, - }, -} diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl deleted file mode 100644 index 3c57149324..0000000000 --- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.threadnetwork; - -import android.hardware.threadnetwork.IThreadChipCallback; - -/** - * Controls a Thread radio chip on the device. - */ - -interface IThreadChip { - /** - * The operation failed for the internal error. - */ - const int ERROR_FAILED = 1; - - /** - * Insufficient buffers available to send frames. - */ - const int ERROR_NO_BUFS = 2; - - /** - * Service is busy and could not service the operation. - */ - const int ERROR_BUSY = 3; - - /** - * This method initializes the Thread HAL instance. If open completes - * successfully, then the Thread HAL instance is ready to accept spinel - * messages through sendSpinelFrame() API. - * - * @param callback A IThreadChipCallback callback instance. If multiple - * callbacks are passed in, the open() will return ERROR_BUSY. - * - * @throws EX_ILLEGAL_ARGUMENT if the callback handle is invalid (for example, it is null). - * @throws ServiceSpecificException with one of the following values: - * - ERROR_FAILED The interface cannot be opened due to an internal error. - * - ERROR_BUSY This interface is in use. - */ - void open(in IThreadChipCallback callback); - - /** - * Close the Thread HAL instance. Must free all resources. - * - * @throws EX_ILLEGAL_STATE if the Thread HAL instance is not opened. - * - */ - void close(); - - /** - * This method resets the Thread HAL internal state. The callback registered by - * `open()` won’t be reset and the resource allocated by `open()` won’t be free. - * - */ - void reset(); - - /** - * This method sends a spinel frame to the Thread HAL. - * - * This method should block until the frame is sent out successfully or - * the method throws errors immediately. - * - * Spinel Protocol: - * https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h - * - * @param frame The spinel frame to be sent. - * - * @throws ServiceSpecificException with one of the following values: - * - ERROR_FAILED The Thread HAL failed to send the frame for an internal reason. - * - ERROR_NO_BUFS Insufficient buffer space to send the frame. - * - ERROR_BUSY The Thread HAL is busy. - */ - void sendSpinelFrame(in byte[] frame); -} diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl deleted file mode 100644 index a0fe88cf8d..0000000000 --- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.threadnetwork; - -interface IThreadChipCallback { - /** - * This method is called when a spinel frame is received. Thread network - * will process the received spinel frame. - * - * Spinel Protocol: - * https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h - * - * @param frame The received spinel frame. - */ - oneway void onReceiveSpinelFrame(in byte[] frame); -} diff --git a/staging/threadnetwork/aidl/default/Android.bp b/staging/threadnetwork/aidl/default/Android.bp deleted file mode 100644 index 8fc22ad538..0000000000 --- a/staging/threadnetwork/aidl/default/Android.bp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -cc_defaults { - name: "threadnetwork_service_default", - vendor: true, - relative_install_path: "hw", - - shared_libs: [ - "android.hardware.threadnetwork-ndk", - "libbase", - "libbinder_ndk", - "libcutils", - "liblog", - "libutils", - ], - - static_libs: [ - "openthread-common", - "openthread-hdlc", - "openthread-platform", - "openthread-posix", - "openthread-url", - ], - - srcs: [ - "main.cpp", - "service.cpp", - "thread_chip.cpp", - "utils.cpp", - ], -} - -cc_binary { - name: "android.hardware.threadnetwork-service.sim", - defaults: ["threadnetwork_service_default"], - init_rc: ["android.hardware.threadnetwork-service.sim.rc"], -} - -cc_binary { - name: "android.hardware.threadnetwork-service", - defaults: ["threadnetwork_service_default"], -} diff --git a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc b/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc deleted file mode 100644 index 2fb409cd93..0000000000 --- a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc +++ /dev/null @@ -1,3 +0,0 @@ -service vendor.threadnetwork_hal /vendor/bin/hw/android.hardware.threadnetwork-service.sim spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=1 - class hal - user thread_network diff --git a/staging/threadnetwork/aidl/default/main.cpp b/staging/threadnetwork/aidl/default/main.cpp deleted file mode 100644 index b6c8bbb7ba..0000000000 --- a/staging/threadnetwork/aidl/default/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "service.hpp" - -int main(int argc, char* argv[]) { - CHECK_GT(argc, 1); - aidl::android::hardware::threadnetwork::Service service(&argv[1], argc - 1); - - ALOGI("Thread Network HAL is running"); - - service.startLoop(); - return EXIT_FAILURE; // should not reach -} diff --git a/staging/threadnetwork/aidl/default/service.cpp b/staging/threadnetwork/aidl/default/service.cpp deleted file mode 100644 index 8047214f24..0000000000 --- a/staging/threadnetwork/aidl/default/service.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "service.hpp" - -#include -#include -#include -#include - -#include "thread_chip.hpp" - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -Service::Service(char* urls[], int numUrls) : mBinderFd(-1) { - int fd; - - CHECK_NE(urls, nullptr); - CHECK_GT(numUrls, 0); - - for (int i = 0; i < numUrls; i++) { - auto threadChip = ndk::SharedRefBase::make(i, urls[i]); - CHECK_NE(threadChip, nullptr); - mThreadChips.push_back(std::move(threadChip)); - } - - binder_status_t status = ABinderProcess_setupPolling(&fd); - CHECK_EQ(status, ::STATUS_OK); - CHECK_GE(fd, 0); - mBinderFd.reset(fd); -} - -void Service::Update(otSysMainloopContext& context) { - FD_SET(mBinderFd.get(), &context.mReadFdSet); - context.mMaxFd = std::max(context.mMaxFd, mBinderFd.get()); -} - -void Service::Process(const otSysMainloopContext& context) { - if (FD_ISSET(mBinderFd.get(), &context.mReadFdSet)) { - ABinderProcess_handlePolledCommands(); - } -} - -void Service::startLoop(void) { - const struct timeval kPollTimeout = {1, 0}; - otSysMainloopContext context; - int rval; - - ot::Posix::Mainloop::Manager::Get().Add(*this); - - while (true) { - context.mMaxFd = -1; - context.mTimeout = kPollTimeout; - - FD_ZERO(&context.mReadFdSet); - FD_ZERO(&context.mWriteFdSet); - FD_ZERO(&context.mErrorFdSet); - - ot::Posix::Mainloop::Manager::Get().Update(context); - - rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, - &context.mErrorFdSet, &context.mTimeout); - - if (rval >= 0) { - ot::Posix::Mainloop::Manager::Get().Process(context); - } else if (errno != EINTR) { - ALOGE("select() failed: %s", strerror(errno)); - break; - } - } -} -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/service.hpp b/staging/threadnetwork/aidl/default/service.hpp deleted file mode 100644 index 6e6e86845a..0000000000 --- a/staging/threadnetwork/aidl/default/service.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "mainloop.hpp" -#include "thread_chip.hpp" - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -class Service : public ot::Posix::Mainloop::Source { - public: - Service(char* urls[], int numUrls); - - void Update(otSysMainloopContext& context) override; - void Process(const otSysMainloopContext& context) override; - void startLoop(void); - - private: - ::android::base::unique_fd mBinderFd; - std::vector> mThreadChips; -}; -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/thread_chip.cpp b/staging/threadnetwork/aidl/default/thread_chip.cpp deleted file mode 100644 index 9bd729d57e..0000000000 --- a/staging/threadnetwork/aidl/default/thread_chip.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "thread_chip.hpp" - -#include -#include -#include -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -static ndk::ScopedAStatus errorStatus(int32_t error, const char* message) { - return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message)); -} - -ThreadChip::ThreadChip(uint8_t id, char* url) - : mUrl(), - mInterface(handleReceivedFrame, this, mRxFrameBuffer), - mRxFrameBuffer(), - mCallback(nullptr) { - const std::string name(std::string() + IThreadChip::descriptor + "/chip" + std::to_string(id)); - binder_status_t status; - - ALOGI("ServiceName: %s, Url: %s", name.c_str(), url); - CHECK_EQ(mUrl.Init(url), 0); - status = AServiceManager_addService(asBinder().get(), name.c_str()); - CHECK_EQ(status, STATUS_OK); - - mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient( - AIBinder_DeathRecipient_new(ThreadChip::onBinderDied)); - AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinked); -} - -ThreadChip::~ThreadChip() { - AIBinder_DeathRecipient_delete(mDeathRecipient.get()); -} - -void ThreadChip::onBinderDied(void* context) { - reinterpret_cast(context)->onBinderDied(); -} - -void ThreadChip::onBinderDied(void) { - ALOGW("Thread Network HAL client is dead."); -} - -void ThreadChip::onBinderUnlinked(void* context) { - reinterpret_cast(context)->onBinderUnlinked(); -} - -void ThreadChip::onBinderUnlinked(void) { - ALOGW("ThreadChip binder is unlinked."); - deinitChip(); -} - -void ThreadChip::handleReceivedFrame(void* context) { - reinterpret_cast(context)->handleReceivedFrame(); -} - -void ThreadChip::handleReceivedFrame(void) { - if (mCallback != nullptr) { - mCallback->onReceiveSpinelFrame(std::vector( - mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength())); - } - - mRxFrameBuffer.DiscardFrame(); -} - -ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr& in_callback) { - ndk::ScopedAStatus status = initChip(in_callback); - - if (status.isOk()) { - AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this); - ALOGI("Open IThreadChip successfully."); - } else { - ALOGW("Open IThreadChip failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr& in_callback) { - if (in_callback == nullptr) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } else if (mCallback == nullptr) { - if (mInterface.Init(mUrl) != OT_ERROR_NONE) { - return errorStatus(ERROR_FAILED, "Failed to initialize the interface"); - } - - mCallback = in_callback; - ot::Posix::Mainloop::Manager::Get().Add(*this); - return ndk::ScopedAStatus::ok(); - } else { - return errorStatus(ERROR_BUSY, "Interface is already opened"); - } -} - -ndk::ScopedAStatus ThreadChip::close() { - ndk::ScopedAStatus status; - std::shared_ptr callback = mCallback; - - status = deinitChip(); - if (status.isOk()) { - if (callback != nullptr) { - AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this); - } - - ALOGI("Close IThreadChip successfully"); - } else { - ALOGW("Close IThreadChip failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::deinitChip() { - if (mCallback != nullptr) { - mInterface.Deinit(); - ot::Posix::Mainloop::Manager::Get().Remove(*this); - mCallback = nullptr; - return ndk::ScopedAStatus::ok(); - } - - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); -} - -ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector& in_frame) { - ndk::ScopedAStatus status; - otError error; - - if (mCallback == nullptr) { - status = errorStatus(ERROR_FAILED, "The interface is not open"); - } else { - error = mInterface.SendFrame(reinterpret_cast(in_frame.data()), - in_frame.size()); - if (error == OT_ERROR_NONE) { - status = ndk::ScopedAStatus::ok(); - } else if (error == OT_ERROR_NO_BUFS) { - status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send"); - } else if (error == OT_ERROR_BUSY) { - status = errorStatus(ERROR_BUSY, "The interface is busy"); - } else { - status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame"); - } - } - - if (!status.isOk()) { - ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::reset() { - mInterface.HardwareReset(); - ALOGI("reset()"); - return ndk::ScopedAStatus::ok(); -} - -void ThreadChip::Update(otSysMainloopContext& context) { - if (mCallback != nullptr) { - mInterface.UpdateFdSet(context.mReadFdSet, context.mWriteFdSet, context.mMaxFd, - context.mTimeout); - } -} - -void ThreadChip::Process(const otSysMainloopContext& context) { - struct RadioProcessContext radioContext; - - if (mCallback != nullptr) { - radioContext.mReadFdSet = &context.mReadFdSet; - radioContext.mWriteFdSet = &context.mWriteFdSet; - mInterface.Process(radioContext); - } -} -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/thread_chip.hpp b/staging/threadnetwork/aidl/default/thread_chip.hpp deleted file mode 100644 index da5cba7585..0000000000 --- a/staging/threadnetwork/aidl/default/thread_chip.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "hdlc_interface.hpp" -#include "lib/spinel/spinel_interface.hpp" -#include "mainloop.hpp" - -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source { - public: - ThreadChip(uint8_t id, char* url); - ~ThreadChip(); - - ndk::ScopedAStatus open(const std::shared_ptr& in_callback) override; - ndk::ScopedAStatus close() override; - ndk::ScopedAStatus sendSpinelFrame(const std::vector& in_frame) override; - ndk::ScopedAStatus reset() override; - void Update(otSysMainloopContext& context) override; - void Process(const otSysMainloopContext& context) override; - - private: - static void onBinderDied(void* context); - void onBinderDied(void); - static void onBinderUnlinked(void* context); - void onBinderUnlinked(void); - static void handleReceivedFrame(void* context); - void handleReceivedFrame(void); - - ndk::ScopedAStatus initChip(const std::shared_ptr& in_callback); - ndk::ScopedAStatus deinitChip(); - - ot::Url::Url mUrl; - ot::Posix::HdlcInterface mInterface; - ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer; - std::shared_ptr mCallback; - ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; -}; - -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/utils.cpp b/staging/threadnetwork/aidl/default/utils.cpp deleted file mode 100644 index d3b4062ee3..0000000000 --- a/staging/threadnetwork/aidl/default/utils.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -void otLogCritPlat(const char* format, ...) { - va_list args; - - va_start(args, format); - __android_log_vprint(ANDROID_LOG_FATAL, LOG_TAG, format, args); - va_end(args); -} - -void otLogWarnPlat(const char* format, ...) { - va_list args; - - va_start(args, format); - __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, args); - va_end(args); -} diff --git a/staging/threadnetwork/aidl/vts/Android.bp b/staging/threadnetwork/aidl/vts/Android.bp deleted file mode 100644 index e2609ed1b5..0000000000 --- a/staging/threadnetwork/aidl/vts/Android.bp +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -cc_test { - name: "VtsHalThreadNetworkTargetTest", - defaults: [ - "VtsHalTargetTestDefaults", - "use_libaidlvintf_gtest_helper_static", - ], - srcs: [ - "VtsHalThreadNetworkTargetTest.cpp", - ], - - shared_libs: [ - "libbinder", - "libbinder_ndk", - ], - static_libs: [ - "android.hardware.threadnetwork-ndk", - ], - test_suites: [ - "general-tests", - "vts", - ], -} diff --git a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp deleted file mode 100644 index 3e43f9c8b7..0000000000 --- a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "ThreadNetworkHalTargetTest" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using aidl::android::hardware::threadnetwork::BnThreadChipCallback; -using aidl::android::hardware::threadnetwork::IThreadChip; -using android::ProcessState; -using ndk::ScopedAStatus; -using ndk::SpAIBinder; - -namespace { -constexpr static int kCallbackTimeoutMs = 5000; -} // namespace - -class ThreadChipCallback : public BnThreadChipCallback { - public: - ThreadChipCallback(const std::function&)>& on_spinel_message_cb) - : on_spinel_message_cb_(on_spinel_message_cb) {} - - ScopedAStatus onReceiveSpinelFrame(const std::vector& in_aFrame) { - on_spinel_message_cb_(in_aFrame); - return ScopedAStatus::ok(); - } - - private: - std::function&)> on_spinel_message_cb_; -}; - -class ThreadNetworkAidl : public testing::TestWithParam { - public: - virtual void SetUp() override { - std::string serviceName = GetParam(); - - ALOGI("serviceName: %s", serviceName.c_str()); - - thread_chip = IThreadChip::fromBinder( - SpAIBinder(AServiceManager_waitForService(serviceName.c_str()))); - ASSERT_NE(thread_chip, nullptr); - } - - virtual void TearDown() override { thread_chip->close(); } - - std::shared_ptr thread_chip; -}; - -TEST_P(ThreadNetworkAidl, Open) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_EQ(thread_chip->open(callback).getServiceSpecificError(), IThreadChip::ERROR_BUSY); -} - -TEST_P(ThreadNetworkAidl, Close) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_TRUE(thread_chip->close().isOk()); - EXPECT_EQ(thread_chip->close().getExceptionCode(), EX_ILLEGAL_STATE); -} - -TEST_P(ThreadNetworkAidl, Reset) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_TRUE(thread_chip->reset().isOk()); -} - -TEST_P(ThreadNetworkAidl, SendSpinelFrame) { - const uint8_t kCmdOffset = 2; - const uint8_t kMajorVersionOffset = 3; - const uint8_t kMinorVersionOffset = 4; - const std::vector kGetSpinelProtocolVersion({0x81, 0x02, 0x01}); - const std::vector kGetSpinelProtocolVersionResponse({0x81, 0x06, 0x01, 0x04, 0x03}); - uint8_t min_major_version = kGetSpinelProtocolVersionResponse[kMajorVersionOffset]; - uint8_t min_minor_version = kGetSpinelProtocolVersionResponse[kMinorVersionOffset]; - uint8_t major_version; - uint8_t minor_version; - std::promise open_cb_promise; - std::future open_cb_future{open_cb_promise.get_future()}; - std::shared_ptr callback; - std::vector received_frame; - std::chrono::milliseconds timeout{kCallbackTimeoutMs}; - - callback = ndk::SharedRefBase::make( - [&](const std::vector& in_aFrame) { - if (in_aFrame.size() == kGetSpinelProtocolVersionResponse.size() && - in_aFrame[kCmdOffset] == kGetSpinelProtocolVersionResponse[kCmdOffset]) { - major_version = in_aFrame[kMajorVersionOffset]; - minor_version = in_aFrame[kMinorVersionOffset]; - open_cb_promise.set_value(); - } - }); - - ASSERT_NE(callback, nullptr); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - - EXPECT_TRUE(thread_chip->sendSpinelFrame(kGetSpinelProtocolVersion).isOk()); - EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); - - EXPECT_GE(major_version, min_major_version); - if (major_version == min_major_version) { - EXPECT_GE(minor_version, min_minor_version); - } -} - -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThreadNetworkAidl); -INSTANTIATE_TEST_SUITE_P( - Thread, ThreadNetworkAidl, - testing::ValuesIn(android::getAidlHalInstanceNames(IThreadChip::descriptor)), - android::PrintInstanceNameToString); - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - ProcessState::self()->setThreadPoolMaxThreadCount(1); - ProcessState::self()->startThreadPool(); - return RUN_ALL_TESTS(); -} From 125dffe1367f6b53e7bd5180b6486bc49a2d533c Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Fri, 9 Jun 2023 16:09:12 +0800 Subject: [PATCH 010/152] remove the Thread Network HAL from the stage folder The Thread Network HAL is going to be added to the AOSP. The implementation of the Thread Network HAL under the staging folder is no longer needed. This commit removes the unstable Thread Network HAL. Bug: 283905423 Test: Build (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b044d98115f19fa6d1e430fd6065a372153f8680) Merged-In: I7e4bf260c03dd0500725fec068747e3b3d05820c Change-Id: I7e4bf260c03dd0500725fec068747e3b3d05820c --- staging/threadnetwork/OWNERS | 5 - staging/threadnetwork/README.md | 12 -- staging/threadnetwork/aidl/Android.bp | 26 --- .../hardware/threadnetwork/IThreadChip.aidl | 88 -------- .../threadnetwork/IThreadChipCallback.aidl | 30 --- staging/threadnetwork/aidl/default/Android.bp | 63 ------ ...roid.hardware.threadnetwork-service.sim.rc | 3 - staging/threadnetwork/aidl/default/main.cpp | 30 --- .../threadnetwork/aidl/default/service.cpp | 90 -------- .../threadnetwork/aidl/default/service.hpp | 42 ---- .../aidl/default/thread_chip.cpp | 197 ------------------ .../aidl/default/thread_chip.hpp | 68 ------ staging/threadnetwork/aidl/default/utils.cpp | 34 --- staging/threadnetwork/aidl/vts/Android.bp | 47 ----- .../vts/VtsHalThreadNetworkTargetTest.cpp | 149 ------------- 15 files changed, 884 deletions(-) delete mode 100644 staging/threadnetwork/OWNERS delete mode 100644 staging/threadnetwork/README.md delete mode 100644 staging/threadnetwork/aidl/Android.bp delete mode 100644 staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl delete mode 100644 staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl delete mode 100644 staging/threadnetwork/aidl/default/Android.bp delete mode 100644 staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc delete mode 100644 staging/threadnetwork/aidl/default/main.cpp delete mode 100644 staging/threadnetwork/aidl/default/service.cpp delete mode 100644 staging/threadnetwork/aidl/default/service.hpp delete mode 100644 staging/threadnetwork/aidl/default/thread_chip.cpp delete mode 100644 staging/threadnetwork/aidl/default/thread_chip.hpp delete mode 100644 staging/threadnetwork/aidl/default/utils.cpp delete mode 100644 staging/threadnetwork/aidl/vts/Android.bp delete mode 100644 staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp diff --git a/staging/threadnetwork/OWNERS b/staging/threadnetwork/OWNERS deleted file mode 100644 index 037215d70f..0000000000 --- a/staging/threadnetwork/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# Bug component: 1203089 - -wgtdkp@google.com -xyk@google.com -zhanglongxia@google.com diff --git a/staging/threadnetwork/README.md b/staging/threadnetwork/README.md deleted file mode 100644 index 12104e5f4d..0000000000 --- a/staging/threadnetwork/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Staging threadnetwork HAL interface - -The directory includes the unstable/unreleased version of `hardware/interfaces/threadnetwork` -code which should **NOT** be used in production. But vendors may start verifying their hardware -with the HAL interface. - -This directory will be cleaned up when the stable Thread HAL interface is added in -`hardware/interfaces/threadnetwork` by version `V` or later. - -More information about _Thread_: -- https://www.threadgroup.org -- https://openthread.io diff --git a/staging/threadnetwork/aidl/Android.bp b/staging/threadnetwork/aidl/Android.bp deleted file mode 100644 index b59d6da3f5..0000000000 --- a/staging/threadnetwork/aidl/Android.bp +++ /dev/null @@ -1,26 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -aidl_interface { - name: "android.hardware.threadnetwork", - host_supported: true, - vendor_available: true, - - srcs: [ - "android/hardware/threadnetwork/*.aidl", - ], - - unstable: true, - - backend: { - ndk: { - enabled: true, - }, - }, -} diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl deleted file mode 100644 index 3c57149324..0000000000 --- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.threadnetwork; - -import android.hardware.threadnetwork.IThreadChipCallback; - -/** - * Controls a Thread radio chip on the device. - */ - -interface IThreadChip { - /** - * The operation failed for the internal error. - */ - const int ERROR_FAILED = 1; - - /** - * Insufficient buffers available to send frames. - */ - const int ERROR_NO_BUFS = 2; - - /** - * Service is busy and could not service the operation. - */ - const int ERROR_BUSY = 3; - - /** - * This method initializes the Thread HAL instance. If open completes - * successfully, then the Thread HAL instance is ready to accept spinel - * messages through sendSpinelFrame() API. - * - * @param callback A IThreadChipCallback callback instance. If multiple - * callbacks are passed in, the open() will return ERROR_BUSY. - * - * @throws EX_ILLEGAL_ARGUMENT if the callback handle is invalid (for example, it is null). - * @throws ServiceSpecificException with one of the following values: - * - ERROR_FAILED The interface cannot be opened due to an internal error. - * - ERROR_BUSY This interface is in use. - */ - void open(in IThreadChipCallback callback); - - /** - * Close the Thread HAL instance. Must free all resources. - * - * @throws EX_ILLEGAL_STATE if the Thread HAL instance is not opened. - * - */ - void close(); - - /** - * This method resets the Thread HAL internal state. The callback registered by - * `open()` won’t be reset and the resource allocated by `open()` won’t be free. - * - */ - void reset(); - - /** - * This method sends a spinel frame to the Thread HAL. - * - * This method should block until the frame is sent out successfully or - * the method throws errors immediately. - * - * Spinel Protocol: - * https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h - * - * @param frame The spinel frame to be sent. - * - * @throws ServiceSpecificException with one of the following values: - * - ERROR_FAILED The Thread HAL failed to send the frame for an internal reason. - * - ERROR_NO_BUFS Insufficient buffer space to send the frame. - * - ERROR_BUSY The Thread HAL is busy. - */ - void sendSpinelFrame(in byte[] frame); -} diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl deleted file mode 100644 index a0fe88cf8d..0000000000 --- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.threadnetwork; - -interface IThreadChipCallback { - /** - * This method is called when a spinel frame is received. Thread network - * will process the received spinel frame. - * - * Spinel Protocol: - * https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h - * - * @param frame The received spinel frame. - */ - oneway void onReceiveSpinelFrame(in byte[] frame); -} diff --git a/staging/threadnetwork/aidl/default/Android.bp b/staging/threadnetwork/aidl/default/Android.bp deleted file mode 100644 index 8fc22ad538..0000000000 --- a/staging/threadnetwork/aidl/default/Android.bp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -cc_defaults { - name: "threadnetwork_service_default", - vendor: true, - relative_install_path: "hw", - - shared_libs: [ - "android.hardware.threadnetwork-ndk", - "libbase", - "libbinder_ndk", - "libcutils", - "liblog", - "libutils", - ], - - static_libs: [ - "openthread-common", - "openthread-hdlc", - "openthread-platform", - "openthread-posix", - "openthread-url", - ], - - srcs: [ - "main.cpp", - "service.cpp", - "thread_chip.cpp", - "utils.cpp", - ], -} - -cc_binary { - name: "android.hardware.threadnetwork-service.sim", - defaults: ["threadnetwork_service_default"], - init_rc: ["android.hardware.threadnetwork-service.sim.rc"], -} - -cc_binary { - name: "android.hardware.threadnetwork-service", - defaults: ["threadnetwork_service_default"], -} diff --git a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc b/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc deleted file mode 100644 index 2fb409cd93..0000000000 --- a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc +++ /dev/null @@ -1,3 +0,0 @@ -service vendor.threadnetwork_hal /vendor/bin/hw/android.hardware.threadnetwork-service.sim spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=1 - class hal - user thread_network diff --git a/staging/threadnetwork/aidl/default/main.cpp b/staging/threadnetwork/aidl/default/main.cpp deleted file mode 100644 index b6c8bbb7ba..0000000000 --- a/staging/threadnetwork/aidl/default/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "service.hpp" - -int main(int argc, char* argv[]) { - CHECK_GT(argc, 1); - aidl::android::hardware::threadnetwork::Service service(&argv[1], argc - 1); - - ALOGI("Thread Network HAL is running"); - - service.startLoop(); - return EXIT_FAILURE; // should not reach -} diff --git a/staging/threadnetwork/aidl/default/service.cpp b/staging/threadnetwork/aidl/default/service.cpp deleted file mode 100644 index 8047214f24..0000000000 --- a/staging/threadnetwork/aidl/default/service.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "service.hpp" - -#include -#include -#include -#include - -#include "thread_chip.hpp" - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -Service::Service(char* urls[], int numUrls) : mBinderFd(-1) { - int fd; - - CHECK_NE(urls, nullptr); - CHECK_GT(numUrls, 0); - - for (int i = 0; i < numUrls; i++) { - auto threadChip = ndk::SharedRefBase::make(i, urls[i]); - CHECK_NE(threadChip, nullptr); - mThreadChips.push_back(std::move(threadChip)); - } - - binder_status_t status = ABinderProcess_setupPolling(&fd); - CHECK_EQ(status, ::STATUS_OK); - CHECK_GE(fd, 0); - mBinderFd.reset(fd); -} - -void Service::Update(otSysMainloopContext& context) { - FD_SET(mBinderFd.get(), &context.mReadFdSet); - context.mMaxFd = std::max(context.mMaxFd, mBinderFd.get()); -} - -void Service::Process(const otSysMainloopContext& context) { - if (FD_ISSET(mBinderFd.get(), &context.mReadFdSet)) { - ABinderProcess_handlePolledCommands(); - } -} - -void Service::startLoop(void) { - const struct timeval kPollTimeout = {1, 0}; - otSysMainloopContext context; - int rval; - - ot::Posix::Mainloop::Manager::Get().Add(*this); - - while (true) { - context.mMaxFd = -1; - context.mTimeout = kPollTimeout; - - FD_ZERO(&context.mReadFdSet); - FD_ZERO(&context.mWriteFdSet); - FD_ZERO(&context.mErrorFdSet); - - ot::Posix::Mainloop::Manager::Get().Update(context); - - rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, - &context.mErrorFdSet, &context.mTimeout); - - if (rval >= 0) { - ot::Posix::Mainloop::Manager::Get().Process(context); - } else if (errno != EINTR) { - ALOGE("select() failed: %s", strerror(errno)); - break; - } - } -} -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/service.hpp b/staging/threadnetwork/aidl/default/service.hpp deleted file mode 100644 index 6e6e86845a..0000000000 --- a/staging/threadnetwork/aidl/default/service.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "mainloop.hpp" -#include "thread_chip.hpp" - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -class Service : public ot::Posix::Mainloop::Source { - public: - Service(char* urls[], int numUrls); - - void Update(otSysMainloopContext& context) override; - void Process(const otSysMainloopContext& context) override; - void startLoop(void); - - private: - ::android::base::unique_fd mBinderFd; - std::vector> mThreadChips; -}; -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/thread_chip.cpp b/staging/threadnetwork/aidl/default/thread_chip.cpp deleted file mode 100644 index 9bd729d57e..0000000000 --- a/staging/threadnetwork/aidl/default/thread_chip.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "thread_chip.hpp" - -#include -#include -#include -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -static ndk::ScopedAStatus errorStatus(int32_t error, const char* message) { - return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message)); -} - -ThreadChip::ThreadChip(uint8_t id, char* url) - : mUrl(), - mInterface(handleReceivedFrame, this, mRxFrameBuffer), - mRxFrameBuffer(), - mCallback(nullptr) { - const std::string name(std::string() + IThreadChip::descriptor + "/chip" + std::to_string(id)); - binder_status_t status; - - ALOGI("ServiceName: %s, Url: %s", name.c_str(), url); - CHECK_EQ(mUrl.Init(url), 0); - status = AServiceManager_addService(asBinder().get(), name.c_str()); - CHECK_EQ(status, STATUS_OK); - - mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient( - AIBinder_DeathRecipient_new(ThreadChip::onBinderDied)); - AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinked); -} - -ThreadChip::~ThreadChip() { - AIBinder_DeathRecipient_delete(mDeathRecipient.get()); -} - -void ThreadChip::onBinderDied(void* context) { - reinterpret_cast(context)->onBinderDied(); -} - -void ThreadChip::onBinderDied(void) { - ALOGW("Thread Network HAL client is dead."); -} - -void ThreadChip::onBinderUnlinked(void* context) { - reinterpret_cast(context)->onBinderUnlinked(); -} - -void ThreadChip::onBinderUnlinked(void) { - ALOGW("ThreadChip binder is unlinked."); - deinitChip(); -} - -void ThreadChip::handleReceivedFrame(void* context) { - reinterpret_cast(context)->handleReceivedFrame(); -} - -void ThreadChip::handleReceivedFrame(void) { - if (mCallback != nullptr) { - mCallback->onReceiveSpinelFrame(std::vector( - mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength())); - } - - mRxFrameBuffer.DiscardFrame(); -} - -ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr& in_callback) { - ndk::ScopedAStatus status = initChip(in_callback); - - if (status.isOk()) { - AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this); - ALOGI("Open IThreadChip successfully."); - } else { - ALOGW("Open IThreadChip failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr& in_callback) { - if (in_callback == nullptr) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } else if (mCallback == nullptr) { - if (mInterface.Init(mUrl) != OT_ERROR_NONE) { - return errorStatus(ERROR_FAILED, "Failed to initialize the interface"); - } - - mCallback = in_callback; - ot::Posix::Mainloop::Manager::Get().Add(*this); - return ndk::ScopedAStatus::ok(); - } else { - return errorStatus(ERROR_BUSY, "Interface is already opened"); - } -} - -ndk::ScopedAStatus ThreadChip::close() { - ndk::ScopedAStatus status; - std::shared_ptr callback = mCallback; - - status = deinitChip(); - if (status.isOk()) { - if (callback != nullptr) { - AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this); - } - - ALOGI("Close IThreadChip successfully"); - } else { - ALOGW("Close IThreadChip failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::deinitChip() { - if (mCallback != nullptr) { - mInterface.Deinit(); - ot::Posix::Mainloop::Manager::Get().Remove(*this); - mCallback = nullptr; - return ndk::ScopedAStatus::ok(); - } - - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); -} - -ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector& in_frame) { - ndk::ScopedAStatus status; - otError error; - - if (mCallback == nullptr) { - status = errorStatus(ERROR_FAILED, "The interface is not open"); - } else { - error = mInterface.SendFrame(reinterpret_cast(in_frame.data()), - in_frame.size()); - if (error == OT_ERROR_NONE) { - status = ndk::ScopedAStatus::ok(); - } else if (error == OT_ERROR_NO_BUFS) { - status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send"); - } else if (error == OT_ERROR_BUSY) { - status = errorStatus(ERROR_BUSY, "The interface is busy"); - } else { - status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame"); - } - } - - if (!status.isOk()) { - ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::reset() { - mInterface.HardwareReset(); - ALOGI("reset()"); - return ndk::ScopedAStatus::ok(); -} - -void ThreadChip::Update(otSysMainloopContext& context) { - if (mCallback != nullptr) { - mInterface.UpdateFdSet(context.mReadFdSet, context.mWriteFdSet, context.mMaxFd, - context.mTimeout); - } -} - -void ThreadChip::Process(const otSysMainloopContext& context) { - struct RadioProcessContext radioContext; - - if (mCallback != nullptr) { - radioContext.mReadFdSet = &context.mReadFdSet; - radioContext.mWriteFdSet = &context.mWriteFdSet; - mInterface.Process(radioContext); - } -} -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/thread_chip.hpp b/staging/threadnetwork/aidl/default/thread_chip.hpp deleted file mode 100644 index da5cba7585..0000000000 --- a/staging/threadnetwork/aidl/default/thread_chip.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "hdlc_interface.hpp" -#include "lib/spinel/spinel_interface.hpp" -#include "mainloop.hpp" - -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source { - public: - ThreadChip(uint8_t id, char* url); - ~ThreadChip(); - - ndk::ScopedAStatus open(const std::shared_ptr& in_callback) override; - ndk::ScopedAStatus close() override; - ndk::ScopedAStatus sendSpinelFrame(const std::vector& in_frame) override; - ndk::ScopedAStatus reset() override; - void Update(otSysMainloopContext& context) override; - void Process(const otSysMainloopContext& context) override; - - private: - static void onBinderDied(void* context); - void onBinderDied(void); - static void onBinderUnlinked(void* context); - void onBinderUnlinked(void); - static void handleReceivedFrame(void* context); - void handleReceivedFrame(void); - - ndk::ScopedAStatus initChip(const std::shared_ptr& in_callback); - ndk::ScopedAStatus deinitChip(); - - ot::Url::Url mUrl; - ot::Posix::HdlcInterface mInterface; - ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer; - std::shared_ptr mCallback; - ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; -}; - -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/utils.cpp b/staging/threadnetwork/aidl/default/utils.cpp deleted file mode 100644 index d3b4062ee3..0000000000 --- a/staging/threadnetwork/aidl/default/utils.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -void otLogCritPlat(const char* format, ...) { - va_list args; - - va_start(args, format); - __android_log_vprint(ANDROID_LOG_FATAL, LOG_TAG, format, args); - va_end(args); -} - -void otLogWarnPlat(const char* format, ...) { - va_list args; - - va_start(args, format); - __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, args); - va_end(args); -} diff --git a/staging/threadnetwork/aidl/vts/Android.bp b/staging/threadnetwork/aidl/vts/Android.bp deleted file mode 100644 index e2609ed1b5..0000000000 --- a/staging/threadnetwork/aidl/vts/Android.bp +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -cc_test { - name: "VtsHalThreadNetworkTargetTest", - defaults: [ - "VtsHalTargetTestDefaults", - "use_libaidlvintf_gtest_helper_static", - ], - srcs: [ - "VtsHalThreadNetworkTargetTest.cpp", - ], - - shared_libs: [ - "libbinder", - "libbinder_ndk", - ], - static_libs: [ - "android.hardware.threadnetwork-ndk", - ], - test_suites: [ - "general-tests", - "vts", - ], -} diff --git a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp deleted file mode 100644 index 3e43f9c8b7..0000000000 --- a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "ThreadNetworkHalTargetTest" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using aidl::android::hardware::threadnetwork::BnThreadChipCallback; -using aidl::android::hardware::threadnetwork::IThreadChip; -using android::ProcessState; -using ndk::ScopedAStatus; -using ndk::SpAIBinder; - -namespace { -constexpr static int kCallbackTimeoutMs = 5000; -} // namespace - -class ThreadChipCallback : public BnThreadChipCallback { - public: - ThreadChipCallback(const std::function&)>& on_spinel_message_cb) - : on_spinel_message_cb_(on_spinel_message_cb) {} - - ScopedAStatus onReceiveSpinelFrame(const std::vector& in_aFrame) { - on_spinel_message_cb_(in_aFrame); - return ScopedAStatus::ok(); - } - - private: - std::function&)> on_spinel_message_cb_; -}; - -class ThreadNetworkAidl : public testing::TestWithParam { - public: - virtual void SetUp() override { - std::string serviceName = GetParam(); - - ALOGI("serviceName: %s", serviceName.c_str()); - - thread_chip = IThreadChip::fromBinder( - SpAIBinder(AServiceManager_waitForService(serviceName.c_str()))); - ASSERT_NE(thread_chip, nullptr); - } - - virtual void TearDown() override { thread_chip->close(); } - - std::shared_ptr thread_chip; -}; - -TEST_P(ThreadNetworkAidl, Open) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_EQ(thread_chip->open(callback).getServiceSpecificError(), IThreadChip::ERROR_BUSY); -} - -TEST_P(ThreadNetworkAidl, Close) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_TRUE(thread_chip->close().isOk()); - EXPECT_EQ(thread_chip->close().getExceptionCode(), EX_ILLEGAL_STATE); -} - -TEST_P(ThreadNetworkAidl, Reset) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_TRUE(thread_chip->reset().isOk()); -} - -TEST_P(ThreadNetworkAidl, SendSpinelFrame) { - const uint8_t kCmdOffset = 2; - const uint8_t kMajorVersionOffset = 3; - const uint8_t kMinorVersionOffset = 4; - const std::vector kGetSpinelProtocolVersion({0x81, 0x02, 0x01}); - const std::vector kGetSpinelProtocolVersionResponse({0x81, 0x06, 0x01, 0x04, 0x03}); - uint8_t min_major_version = kGetSpinelProtocolVersionResponse[kMajorVersionOffset]; - uint8_t min_minor_version = kGetSpinelProtocolVersionResponse[kMinorVersionOffset]; - uint8_t major_version; - uint8_t minor_version; - std::promise open_cb_promise; - std::future open_cb_future{open_cb_promise.get_future()}; - std::shared_ptr callback; - std::vector received_frame; - std::chrono::milliseconds timeout{kCallbackTimeoutMs}; - - callback = ndk::SharedRefBase::make( - [&](const std::vector& in_aFrame) { - if (in_aFrame.size() == kGetSpinelProtocolVersionResponse.size() && - in_aFrame[kCmdOffset] == kGetSpinelProtocolVersionResponse[kCmdOffset]) { - major_version = in_aFrame[kMajorVersionOffset]; - minor_version = in_aFrame[kMinorVersionOffset]; - open_cb_promise.set_value(); - } - }); - - ASSERT_NE(callback, nullptr); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - - EXPECT_TRUE(thread_chip->sendSpinelFrame(kGetSpinelProtocolVersion).isOk()); - EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); - - EXPECT_GE(major_version, min_major_version); - if (major_version == min_major_version) { - EXPECT_GE(minor_version, min_minor_version); - } -} - -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThreadNetworkAidl); -INSTANTIATE_TEST_SUITE_P( - Thread, ThreadNetworkAidl, - testing::ValuesIn(android::getAidlHalInstanceNames(IThreadChip::descriptor)), - android::PrintInstanceNameToString); - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - ProcessState::self()->setThreadPoolMaxThreadCount(1); - ProcessState::self()->startThreadPool(); - return RUN_ALL_TESTS(); -} From 06c521f24c8e396925bb1d30be9294ae0196190a Mon Sep 17 00:00:00 2001 From: Android Culprit Assistant Date: Tue, 13 Jun 2023 13:53:38 +0000 Subject: [PATCH 011/152] Revert "remove the Thread Network HAL from the stage folder" This revert was created by Android Culprit Assistant. The culprit was identified in the following culprit search session (http://go/aca-get/be814502-22df-405b-acc7-1caa64d24729). Change-Id: Ib283005ea10f6057dd7972e4c8350e527cf4abdd --- staging/threadnetwork/OWNERS | 5 + staging/threadnetwork/README.md | 12 ++ staging/threadnetwork/aidl/Android.bp | 26 +++ .../hardware/threadnetwork/IThreadChip.aidl | 88 ++++++++ .../threadnetwork/IThreadChipCallback.aidl | 30 +++ staging/threadnetwork/aidl/default/Android.bp | 63 ++++++ ...roid.hardware.threadnetwork-service.sim.rc | 3 + staging/threadnetwork/aidl/default/main.cpp | 30 +++ .../threadnetwork/aidl/default/service.cpp | 90 ++++++++ .../threadnetwork/aidl/default/service.hpp | 42 ++++ .../aidl/default/thread_chip.cpp | 197 ++++++++++++++++++ .../aidl/default/thread_chip.hpp | 68 ++++++ staging/threadnetwork/aidl/default/utils.cpp | 34 +++ staging/threadnetwork/aidl/vts/Android.bp | 47 +++++ .../vts/VtsHalThreadNetworkTargetTest.cpp | 149 +++++++++++++ 15 files changed, 884 insertions(+) create mode 100644 staging/threadnetwork/OWNERS create mode 100644 staging/threadnetwork/README.md create mode 100644 staging/threadnetwork/aidl/Android.bp create mode 100644 staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl create mode 100644 staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl create mode 100644 staging/threadnetwork/aidl/default/Android.bp create mode 100644 staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc create mode 100644 staging/threadnetwork/aidl/default/main.cpp create mode 100644 staging/threadnetwork/aidl/default/service.cpp create mode 100644 staging/threadnetwork/aidl/default/service.hpp create mode 100644 staging/threadnetwork/aidl/default/thread_chip.cpp create mode 100644 staging/threadnetwork/aidl/default/thread_chip.hpp create mode 100644 staging/threadnetwork/aidl/default/utils.cpp create mode 100644 staging/threadnetwork/aidl/vts/Android.bp create mode 100644 staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp diff --git a/staging/threadnetwork/OWNERS b/staging/threadnetwork/OWNERS new file mode 100644 index 0000000000..037215d70f --- /dev/null +++ b/staging/threadnetwork/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 1203089 + +wgtdkp@google.com +xyk@google.com +zhanglongxia@google.com diff --git a/staging/threadnetwork/README.md b/staging/threadnetwork/README.md new file mode 100644 index 0000000000..12104e5f4d --- /dev/null +++ b/staging/threadnetwork/README.md @@ -0,0 +1,12 @@ +# Staging threadnetwork HAL interface + +The directory includes the unstable/unreleased version of `hardware/interfaces/threadnetwork` +code which should **NOT** be used in production. But vendors may start verifying their hardware +with the HAL interface. + +This directory will be cleaned up when the stable Thread HAL interface is added in +`hardware/interfaces/threadnetwork` by version `V` or later. + +More information about _Thread_: +- https://www.threadgroup.org +- https://openthread.io diff --git a/staging/threadnetwork/aidl/Android.bp b/staging/threadnetwork/aidl/Android.bp new file mode 100644 index 0000000000..b59d6da3f5 --- /dev/null +++ b/staging/threadnetwork/aidl/Android.bp @@ -0,0 +1,26 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +aidl_interface { + name: "android.hardware.threadnetwork", + host_supported: true, + vendor_available: true, + + srcs: [ + "android/hardware/threadnetwork/*.aidl", + ], + + unstable: true, + + backend: { + ndk: { + enabled: true, + }, + }, +} diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl new file mode 100644 index 0000000000..3c57149324 --- /dev/null +++ b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.threadnetwork; + +import android.hardware.threadnetwork.IThreadChipCallback; + +/** + * Controls a Thread radio chip on the device. + */ + +interface IThreadChip { + /** + * The operation failed for the internal error. + */ + const int ERROR_FAILED = 1; + + /** + * Insufficient buffers available to send frames. + */ + const int ERROR_NO_BUFS = 2; + + /** + * Service is busy and could not service the operation. + */ + const int ERROR_BUSY = 3; + + /** + * This method initializes the Thread HAL instance. If open completes + * successfully, then the Thread HAL instance is ready to accept spinel + * messages through sendSpinelFrame() API. + * + * @param callback A IThreadChipCallback callback instance. If multiple + * callbacks are passed in, the open() will return ERROR_BUSY. + * + * @throws EX_ILLEGAL_ARGUMENT if the callback handle is invalid (for example, it is null). + * @throws ServiceSpecificException with one of the following values: + * - ERROR_FAILED The interface cannot be opened due to an internal error. + * - ERROR_BUSY This interface is in use. + */ + void open(in IThreadChipCallback callback); + + /** + * Close the Thread HAL instance. Must free all resources. + * + * @throws EX_ILLEGAL_STATE if the Thread HAL instance is not opened. + * + */ + void close(); + + /** + * This method resets the Thread HAL internal state. The callback registered by + * `open()` won’t be reset and the resource allocated by `open()` won’t be free. + * + */ + void reset(); + + /** + * This method sends a spinel frame to the Thread HAL. + * + * This method should block until the frame is sent out successfully or + * the method throws errors immediately. + * + * Spinel Protocol: + * https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h + * + * @param frame The spinel frame to be sent. + * + * @throws ServiceSpecificException with one of the following values: + * - ERROR_FAILED The Thread HAL failed to send the frame for an internal reason. + * - ERROR_NO_BUFS Insufficient buffer space to send the frame. + * - ERROR_BUSY The Thread HAL is busy. + */ + void sendSpinelFrame(in byte[] frame); +} diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl new file mode 100644 index 0000000000..a0fe88cf8d --- /dev/null +++ b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.threadnetwork; + +interface IThreadChipCallback { + /** + * This method is called when a spinel frame is received. Thread network + * will process the received spinel frame. + * + * Spinel Protocol: + * https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h + * + * @param frame The received spinel frame. + */ + oneway void onReceiveSpinelFrame(in byte[] frame); +} diff --git a/staging/threadnetwork/aidl/default/Android.bp b/staging/threadnetwork/aidl/default/Android.bp new file mode 100644 index 0000000000..8fc22ad538 --- /dev/null +++ b/staging/threadnetwork/aidl/default/Android.bp @@ -0,0 +1,63 @@ +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +cc_defaults { + name: "threadnetwork_service_default", + vendor: true, + relative_install_path: "hw", + + shared_libs: [ + "android.hardware.threadnetwork-ndk", + "libbase", + "libbinder_ndk", + "libcutils", + "liblog", + "libutils", + ], + + static_libs: [ + "openthread-common", + "openthread-hdlc", + "openthread-platform", + "openthread-posix", + "openthread-url", + ], + + srcs: [ + "main.cpp", + "service.cpp", + "thread_chip.cpp", + "utils.cpp", + ], +} + +cc_binary { + name: "android.hardware.threadnetwork-service.sim", + defaults: ["threadnetwork_service_default"], + init_rc: ["android.hardware.threadnetwork-service.sim.rc"], +} + +cc_binary { + name: "android.hardware.threadnetwork-service", + defaults: ["threadnetwork_service_default"], +} diff --git a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc b/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc new file mode 100644 index 0000000000..2fb409cd93 --- /dev/null +++ b/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc @@ -0,0 +1,3 @@ +service vendor.threadnetwork_hal /vendor/bin/hw/android.hardware.threadnetwork-service.sim spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=1 + class hal + user thread_network diff --git a/staging/threadnetwork/aidl/default/main.cpp b/staging/threadnetwork/aidl/default/main.cpp new file mode 100644 index 0000000000..b6c8bbb7ba --- /dev/null +++ b/staging/threadnetwork/aidl/default/main.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "service.hpp" + +int main(int argc, char* argv[]) { + CHECK_GT(argc, 1); + aidl::android::hardware::threadnetwork::Service service(&argv[1], argc - 1); + + ALOGI("Thread Network HAL is running"); + + service.startLoop(); + return EXIT_FAILURE; // should not reach +} diff --git a/staging/threadnetwork/aidl/default/service.cpp b/staging/threadnetwork/aidl/default/service.cpp new file mode 100644 index 0000000000..8047214f24 --- /dev/null +++ b/staging/threadnetwork/aidl/default/service.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "service.hpp" + +#include +#include +#include +#include + +#include "thread_chip.hpp" + +namespace aidl { +namespace android { +namespace hardware { +namespace threadnetwork { + +Service::Service(char* urls[], int numUrls) : mBinderFd(-1) { + int fd; + + CHECK_NE(urls, nullptr); + CHECK_GT(numUrls, 0); + + for (int i = 0; i < numUrls; i++) { + auto threadChip = ndk::SharedRefBase::make(i, urls[i]); + CHECK_NE(threadChip, nullptr); + mThreadChips.push_back(std::move(threadChip)); + } + + binder_status_t status = ABinderProcess_setupPolling(&fd); + CHECK_EQ(status, ::STATUS_OK); + CHECK_GE(fd, 0); + mBinderFd.reset(fd); +} + +void Service::Update(otSysMainloopContext& context) { + FD_SET(mBinderFd.get(), &context.mReadFdSet); + context.mMaxFd = std::max(context.mMaxFd, mBinderFd.get()); +} + +void Service::Process(const otSysMainloopContext& context) { + if (FD_ISSET(mBinderFd.get(), &context.mReadFdSet)) { + ABinderProcess_handlePolledCommands(); + } +} + +void Service::startLoop(void) { + const struct timeval kPollTimeout = {1, 0}; + otSysMainloopContext context; + int rval; + + ot::Posix::Mainloop::Manager::Get().Add(*this); + + while (true) { + context.mMaxFd = -1; + context.mTimeout = kPollTimeout; + + FD_ZERO(&context.mReadFdSet); + FD_ZERO(&context.mWriteFdSet); + FD_ZERO(&context.mErrorFdSet); + + ot::Posix::Mainloop::Manager::Get().Update(context); + + rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, + &context.mErrorFdSet, &context.mTimeout); + + if (rval >= 0) { + ot::Posix::Mainloop::Manager::Get().Process(context); + } else if (errno != EINTR) { + ALOGE("select() failed: %s", strerror(errno)); + break; + } + } +} +} // namespace threadnetwork +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/service.hpp b/staging/threadnetwork/aidl/default/service.hpp new file mode 100644 index 0000000000..6e6e86845a --- /dev/null +++ b/staging/threadnetwork/aidl/default/service.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "mainloop.hpp" +#include "thread_chip.hpp" + +namespace aidl { +namespace android { +namespace hardware { +namespace threadnetwork { + +class Service : public ot::Posix::Mainloop::Source { + public: + Service(char* urls[], int numUrls); + + void Update(otSysMainloopContext& context) override; + void Process(const otSysMainloopContext& context) override; + void startLoop(void); + + private: + ::android::base::unique_fd mBinderFd; + std::vector> mThreadChips; +}; +} // namespace threadnetwork +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/thread_chip.cpp b/staging/threadnetwork/aidl/default/thread_chip.cpp new file mode 100644 index 0000000000..9bd729d57e --- /dev/null +++ b/staging/threadnetwork/aidl/default/thread_chip.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "thread_chip.hpp" + +#include +#include +#include +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace threadnetwork { + +static ndk::ScopedAStatus errorStatus(int32_t error, const char* message) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message)); +} + +ThreadChip::ThreadChip(uint8_t id, char* url) + : mUrl(), + mInterface(handleReceivedFrame, this, mRxFrameBuffer), + mRxFrameBuffer(), + mCallback(nullptr) { + const std::string name(std::string() + IThreadChip::descriptor + "/chip" + std::to_string(id)); + binder_status_t status; + + ALOGI("ServiceName: %s, Url: %s", name.c_str(), url); + CHECK_EQ(mUrl.Init(url), 0); + status = AServiceManager_addService(asBinder().get(), name.c_str()); + CHECK_EQ(status, STATUS_OK); + + mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient( + AIBinder_DeathRecipient_new(ThreadChip::onBinderDied)); + AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinked); +} + +ThreadChip::~ThreadChip() { + AIBinder_DeathRecipient_delete(mDeathRecipient.get()); +} + +void ThreadChip::onBinderDied(void* context) { + reinterpret_cast(context)->onBinderDied(); +} + +void ThreadChip::onBinderDied(void) { + ALOGW("Thread Network HAL client is dead."); +} + +void ThreadChip::onBinderUnlinked(void* context) { + reinterpret_cast(context)->onBinderUnlinked(); +} + +void ThreadChip::onBinderUnlinked(void) { + ALOGW("ThreadChip binder is unlinked."); + deinitChip(); +} + +void ThreadChip::handleReceivedFrame(void* context) { + reinterpret_cast(context)->handleReceivedFrame(); +} + +void ThreadChip::handleReceivedFrame(void) { + if (mCallback != nullptr) { + mCallback->onReceiveSpinelFrame(std::vector( + mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength())); + } + + mRxFrameBuffer.DiscardFrame(); +} + +ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr& in_callback) { + ndk::ScopedAStatus status = initChip(in_callback); + + if (status.isOk()) { + AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this); + ALOGI("Open IThreadChip successfully."); + } else { + ALOGW("Open IThreadChip failed, error: %s", status.getDescription().c_str()); + } + + return status; +} + +ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr& in_callback) { + if (in_callback == nullptr) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } else if (mCallback == nullptr) { + if (mInterface.Init(mUrl) != OT_ERROR_NONE) { + return errorStatus(ERROR_FAILED, "Failed to initialize the interface"); + } + + mCallback = in_callback; + ot::Posix::Mainloop::Manager::Get().Add(*this); + return ndk::ScopedAStatus::ok(); + } else { + return errorStatus(ERROR_BUSY, "Interface is already opened"); + } +} + +ndk::ScopedAStatus ThreadChip::close() { + ndk::ScopedAStatus status; + std::shared_ptr callback = mCallback; + + status = deinitChip(); + if (status.isOk()) { + if (callback != nullptr) { + AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this); + } + + ALOGI("Close IThreadChip successfully"); + } else { + ALOGW("Close IThreadChip failed, error: %s", status.getDescription().c_str()); + } + + return status; +} + +ndk::ScopedAStatus ThreadChip::deinitChip() { + if (mCallback != nullptr) { + mInterface.Deinit(); + ot::Posix::Mainloop::Manager::Get().Remove(*this); + mCallback = nullptr; + return ndk::ScopedAStatus::ok(); + } + + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); +} + +ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector& in_frame) { + ndk::ScopedAStatus status; + otError error; + + if (mCallback == nullptr) { + status = errorStatus(ERROR_FAILED, "The interface is not open"); + } else { + error = mInterface.SendFrame(reinterpret_cast(in_frame.data()), + in_frame.size()); + if (error == OT_ERROR_NONE) { + status = ndk::ScopedAStatus::ok(); + } else if (error == OT_ERROR_NO_BUFS) { + status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send"); + } else if (error == OT_ERROR_BUSY) { + status = errorStatus(ERROR_BUSY, "The interface is busy"); + } else { + status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame"); + } + } + + if (!status.isOk()) { + ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str()); + } + + return status; +} + +ndk::ScopedAStatus ThreadChip::reset() { + mInterface.HardwareReset(); + ALOGI("reset()"); + return ndk::ScopedAStatus::ok(); +} + +void ThreadChip::Update(otSysMainloopContext& context) { + if (mCallback != nullptr) { + mInterface.UpdateFdSet(context.mReadFdSet, context.mWriteFdSet, context.mMaxFd, + context.mTimeout); + } +} + +void ThreadChip::Process(const otSysMainloopContext& context) { + struct RadioProcessContext radioContext; + + if (mCallback != nullptr) { + radioContext.mReadFdSet = &context.mReadFdSet; + radioContext.mWriteFdSet = &context.mWriteFdSet; + mInterface.Process(radioContext); + } +} +} // namespace threadnetwork +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/thread_chip.hpp b/staging/threadnetwork/aidl/default/thread_chip.hpp new file mode 100644 index 0000000000..da5cba7585 --- /dev/null +++ b/staging/threadnetwork/aidl/default/thread_chip.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "hdlc_interface.hpp" +#include "lib/spinel/spinel_interface.hpp" +#include "mainloop.hpp" + +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace threadnetwork { + +class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source { + public: + ThreadChip(uint8_t id, char* url); + ~ThreadChip(); + + ndk::ScopedAStatus open(const std::shared_ptr& in_callback) override; + ndk::ScopedAStatus close() override; + ndk::ScopedAStatus sendSpinelFrame(const std::vector& in_frame) override; + ndk::ScopedAStatus reset() override; + void Update(otSysMainloopContext& context) override; + void Process(const otSysMainloopContext& context) override; + + private: + static void onBinderDied(void* context); + void onBinderDied(void); + static void onBinderUnlinked(void* context); + void onBinderUnlinked(void); + static void handleReceivedFrame(void* context); + void handleReceivedFrame(void); + + ndk::ScopedAStatus initChip(const std::shared_ptr& in_callback); + ndk::ScopedAStatus deinitChip(); + + ot::Url::Url mUrl; + ot::Posix::HdlcInterface mInterface; + ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer; + std::shared_ptr mCallback; + ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; +}; + +} // namespace threadnetwork +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/utils.cpp b/staging/threadnetwork/aidl/default/utils.cpp new file mode 100644 index 0000000000..d3b4062ee3 --- /dev/null +++ b/staging/threadnetwork/aidl/default/utils.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +void otLogCritPlat(const char* format, ...) { + va_list args; + + va_start(args, format); + __android_log_vprint(ANDROID_LOG_FATAL, LOG_TAG, format, args); + va_end(args); +} + +void otLogWarnPlat(const char* format, ...) { + va_list args; + + va_start(args, format); + __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, args); + va_end(args); +} diff --git a/staging/threadnetwork/aidl/vts/Android.bp b/staging/threadnetwork/aidl/vts/Android.bp new file mode 100644 index 0000000000..e2609ed1b5 --- /dev/null +++ b/staging/threadnetwork/aidl/vts/Android.bp @@ -0,0 +1,47 @@ +// +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +cc_test { + name: "VtsHalThreadNetworkTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "VtsHalThreadNetworkTargetTest.cpp", + ], + + shared_libs: [ + "libbinder", + "libbinder_ndk", + ], + static_libs: [ + "android.hardware.threadnetwork-ndk", + ], + test_suites: [ + "general-tests", + "vts", + ], +} diff --git a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp new file mode 100644 index 0000000000..3e43f9c8b7 --- /dev/null +++ b/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "ThreadNetworkHalTargetTest" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using aidl::android::hardware::threadnetwork::BnThreadChipCallback; +using aidl::android::hardware::threadnetwork::IThreadChip; +using android::ProcessState; +using ndk::ScopedAStatus; +using ndk::SpAIBinder; + +namespace { +constexpr static int kCallbackTimeoutMs = 5000; +} // namespace + +class ThreadChipCallback : public BnThreadChipCallback { + public: + ThreadChipCallback(const std::function&)>& on_spinel_message_cb) + : on_spinel_message_cb_(on_spinel_message_cb) {} + + ScopedAStatus onReceiveSpinelFrame(const std::vector& in_aFrame) { + on_spinel_message_cb_(in_aFrame); + return ScopedAStatus::ok(); + } + + private: + std::function&)> on_spinel_message_cb_; +}; + +class ThreadNetworkAidl : public testing::TestWithParam { + public: + virtual void SetUp() override { + std::string serviceName = GetParam(); + + ALOGI("serviceName: %s", serviceName.c_str()); + + thread_chip = IThreadChip::fromBinder( + SpAIBinder(AServiceManager_waitForService(serviceName.c_str()))); + ASSERT_NE(thread_chip, nullptr); + } + + virtual void TearDown() override { thread_chip->close(); } + + std::shared_ptr thread_chip; +}; + +TEST_P(ThreadNetworkAidl, Open) { + std::shared_ptr callback = + ndk::SharedRefBase::make([](auto /* data */) {}); + + EXPECT_TRUE(thread_chip->open(callback).isOk()); + EXPECT_EQ(thread_chip->open(callback).getServiceSpecificError(), IThreadChip::ERROR_BUSY); +} + +TEST_P(ThreadNetworkAidl, Close) { + std::shared_ptr callback = + ndk::SharedRefBase::make([](auto /* data */) {}); + + EXPECT_TRUE(thread_chip->open(callback).isOk()); + EXPECT_TRUE(thread_chip->close().isOk()); + EXPECT_EQ(thread_chip->close().getExceptionCode(), EX_ILLEGAL_STATE); +} + +TEST_P(ThreadNetworkAidl, Reset) { + std::shared_ptr callback = + ndk::SharedRefBase::make([](auto /* data */) {}); + + EXPECT_TRUE(thread_chip->open(callback).isOk()); + EXPECT_TRUE(thread_chip->reset().isOk()); +} + +TEST_P(ThreadNetworkAidl, SendSpinelFrame) { + const uint8_t kCmdOffset = 2; + const uint8_t kMajorVersionOffset = 3; + const uint8_t kMinorVersionOffset = 4; + const std::vector kGetSpinelProtocolVersion({0x81, 0x02, 0x01}); + const std::vector kGetSpinelProtocolVersionResponse({0x81, 0x06, 0x01, 0x04, 0x03}); + uint8_t min_major_version = kGetSpinelProtocolVersionResponse[kMajorVersionOffset]; + uint8_t min_minor_version = kGetSpinelProtocolVersionResponse[kMinorVersionOffset]; + uint8_t major_version; + uint8_t minor_version; + std::promise open_cb_promise; + std::future open_cb_future{open_cb_promise.get_future()}; + std::shared_ptr callback; + std::vector received_frame; + std::chrono::milliseconds timeout{kCallbackTimeoutMs}; + + callback = ndk::SharedRefBase::make( + [&](const std::vector& in_aFrame) { + if (in_aFrame.size() == kGetSpinelProtocolVersionResponse.size() && + in_aFrame[kCmdOffset] == kGetSpinelProtocolVersionResponse[kCmdOffset]) { + major_version = in_aFrame[kMajorVersionOffset]; + minor_version = in_aFrame[kMinorVersionOffset]; + open_cb_promise.set_value(); + } + }); + + ASSERT_NE(callback, nullptr); + + EXPECT_TRUE(thread_chip->open(callback).isOk()); + + EXPECT_TRUE(thread_chip->sendSpinelFrame(kGetSpinelProtocolVersion).isOk()); + EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); + + EXPECT_GE(major_version, min_major_version); + if (major_version == min_major_version) { + EXPECT_GE(minor_version, min_minor_version); + } +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThreadNetworkAidl); +INSTANTIATE_TEST_SUITE_P( + Thread, ThreadNetworkAidl, + testing::ValuesIn(android::getAidlHalInstanceNames(IThreadChip::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ProcessState::self()->setThreadPoolMaxThreadCount(1); + ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} From 7fd1a4ef3a45bf1484acdbec6c226c1ba99b92d5 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Wed, 14 Jun 2023 04:20:27 +0000 Subject: [PATCH 012/152] Revert "Revert "remove the Thread Network HAL from the stage folder"" This reverts commit 06c521f24c8e396925bb1d30be9294ae0196190a. Reason for revert: The reverted CL caused the issue b/287137082 Change-Id: I54f678f9b0c7979b56e895055d44ebde83a42a53 --- staging/threadnetwork/OWNERS | 5 - staging/threadnetwork/README.md | 12 -- staging/threadnetwork/aidl/Android.bp | 26 --- .../hardware/threadnetwork/IThreadChip.aidl | 88 -------- .../threadnetwork/IThreadChipCallback.aidl | 30 --- staging/threadnetwork/aidl/default/Android.bp | 63 ------ ...roid.hardware.threadnetwork-service.sim.rc | 3 - staging/threadnetwork/aidl/default/main.cpp | 30 --- .../threadnetwork/aidl/default/service.cpp | 90 -------- .../threadnetwork/aidl/default/service.hpp | 42 ---- .../aidl/default/thread_chip.cpp | 197 ------------------ .../aidl/default/thread_chip.hpp | 68 ------ staging/threadnetwork/aidl/default/utils.cpp | 34 --- staging/threadnetwork/aidl/vts/Android.bp | 47 ----- .../vts/VtsHalThreadNetworkTargetTest.cpp | 149 ------------- 15 files changed, 884 deletions(-) delete mode 100644 staging/threadnetwork/OWNERS delete mode 100644 staging/threadnetwork/README.md delete mode 100644 staging/threadnetwork/aidl/Android.bp delete mode 100644 staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl delete mode 100644 staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl delete mode 100644 staging/threadnetwork/aidl/default/Android.bp delete mode 100644 staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc delete mode 100644 staging/threadnetwork/aidl/default/main.cpp delete mode 100644 staging/threadnetwork/aidl/default/service.cpp delete mode 100644 staging/threadnetwork/aidl/default/service.hpp delete mode 100644 staging/threadnetwork/aidl/default/thread_chip.cpp delete mode 100644 staging/threadnetwork/aidl/default/thread_chip.hpp delete mode 100644 staging/threadnetwork/aidl/default/utils.cpp delete mode 100644 staging/threadnetwork/aidl/vts/Android.bp delete mode 100644 staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp diff --git a/staging/threadnetwork/OWNERS b/staging/threadnetwork/OWNERS deleted file mode 100644 index 037215d70f..0000000000 --- a/staging/threadnetwork/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# Bug component: 1203089 - -wgtdkp@google.com -xyk@google.com -zhanglongxia@google.com diff --git a/staging/threadnetwork/README.md b/staging/threadnetwork/README.md deleted file mode 100644 index 12104e5f4d..0000000000 --- a/staging/threadnetwork/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Staging threadnetwork HAL interface - -The directory includes the unstable/unreleased version of `hardware/interfaces/threadnetwork` -code which should **NOT** be used in production. But vendors may start verifying their hardware -with the HAL interface. - -This directory will be cleaned up when the stable Thread HAL interface is added in -`hardware/interfaces/threadnetwork` by version `V` or later. - -More information about _Thread_: -- https://www.threadgroup.org -- https://openthread.io diff --git a/staging/threadnetwork/aidl/Android.bp b/staging/threadnetwork/aidl/Android.bp deleted file mode 100644 index b59d6da3f5..0000000000 --- a/staging/threadnetwork/aidl/Android.bp +++ /dev/null @@ -1,26 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -aidl_interface { - name: "android.hardware.threadnetwork", - host_supported: true, - vendor_available: true, - - srcs: [ - "android/hardware/threadnetwork/*.aidl", - ], - - unstable: true, - - backend: { - ndk: { - enabled: true, - }, - }, -} diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl deleted file mode 100644 index 3c57149324..0000000000 --- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.threadnetwork; - -import android.hardware.threadnetwork.IThreadChipCallback; - -/** - * Controls a Thread radio chip on the device. - */ - -interface IThreadChip { - /** - * The operation failed for the internal error. - */ - const int ERROR_FAILED = 1; - - /** - * Insufficient buffers available to send frames. - */ - const int ERROR_NO_BUFS = 2; - - /** - * Service is busy and could not service the operation. - */ - const int ERROR_BUSY = 3; - - /** - * This method initializes the Thread HAL instance. If open completes - * successfully, then the Thread HAL instance is ready to accept spinel - * messages through sendSpinelFrame() API. - * - * @param callback A IThreadChipCallback callback instance. If multiple - * callbacks are passed in, the open() will return ERROR_BUSY. - * - * @throws EX_ILLEGAL_ARGUMENT if the callback handle is invalid (for example, it is null). - * @throws ServiceSpecificException with one of the following values: - * - ERROR_FAILED The interface cannot be opened due to an internal error. - * - ERROR_BUSY This interface is in use. - */ - void open(in IThreadChipCallback callback); - - /** - * Close the Thread HAL instance. Must free all resources. - * - * @throws EX_ILLEGAL_STATE if the Thread HAL instance is not opened. - * - */ - void close(); - - /** - * This method resets the Thread HAL internal state. The callback registered by - * `open()` won’t be reset and the resource allocated by `open()` won’t be free. - * - */ - void reset(); - - /** - * This method sends a spinel frame to the Thread HAL. - * - * This method should block until the frame is sent out successfully or - * the method throws errors immediately. - * - * Spinel Protocol: - * https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h - * - * @param frame The spinel frame to be sent. - * - * @throws ServiceSpecificException with one of the following values: - * - ERROR_FAILED The Thread HAL failed to send the frame for an internal reason. - * - ERROR_NO_BUFS Insufficient buffer space to send the frame. - * - ERROR_BUSY The Thread HAL is busy. - */ - void sendSpinelFrame(in byte[] frame); -} diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl deleted file mode 100644 index a0fe88cf8d..0000000000 --- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.threadnetwork; - -interface IThreadChipCallback { - /** - * This method is called when a spinel frame is received. Thread network - * will process the received spinel frame. - * - * Spinel Protocol: - * https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h - * - * @param frame The received spinel frame. - */ - oneway void onReceiveSpinelFrame(in byte[] frame); -} diff --git a/staging/threadnetwork/aidl/default/Android.bp b/staging/threadnetwork/aidl/default/Android.bp deleted file mode 100644 index 8fc22ad538..0000000000 --- a/staging/threadnetwork/aidl/default/Android.bp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -cc_defaults { - name: "threadnetwork_service_default", - vendor: true, - relative_install_path: "hw", - - shared_libs: [ - "android.hardware.threadnetwork-ndk", - "libbase", - "libbinder_ndk", - "libcutils", - "liblog", - "libutils", - ], - - static_libs: [ - "openthread-common", - "openthread-hdlc", - "openthread-platform", - "openthread-posix", - "openthread-url", - ], - - srcs: [ - "main.cpp", - "service.cpp", - "thread_chip.cpp", - "utils.cpp", - ], -} - -cc_binary { - name: "android.hardware.threadnetwork-service.sim", - defaults: ["threadnetwork_service_default"], - init_rc: ["android.hardware.threadnetwork-service.sim.rc"], -} - -cc_binary { - name: "android.hardware.threadnetwork-service", - defaults: ["threadnetwork_service_default"], -} diff --git a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc b/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc deleted file mode 100644 index 2fb409cd93..0000000000 --- a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc +++ /dev/null @@ -1,3 +0,0 @@ -service vendor.threadnetwork_hal /vendor/bin/hw/android.hardware.threadnetwork-service.sim spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=1 - class hal - user thread_network diff --git a/staging/threadnetwork/aidl/default/main.cpp b/staging/threadnetwork/aidl/default/main.cpp deleted file mode 100644 index b6c8bbb7ba..0000000000 --- a/staging/threadnetwork/aidl/default/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "service.hpp" - -int main(int argc, char* argv[]) { - CHECK_GT(argc, 1); - aidl::android::hardware::threadnetwork::Service service(&argv[1], argc - 1); - - ALOGI("Thread Network HAL is running"); - - service.startLoop(); - return EXIT_FAILURE; // should not reach -} diff --git a/staging/threadnetwork/aidl/default/service.cpp b/staging/threadnetwork/aidl/default/service.cpp deleted file mode 100644 index 8047214f24..0000000000 --- a/staging/threadnetwork/aidl/default/service.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "service.hpp" - -#include -#include -#include -#include - -#include "thread_chip.hpp" - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -Service::Service(char* urls[], int numUrls) : mBinderFd(-1) { - int fd; - - CHECK_NE(urls, nullptr); - CHECK_GT(numUrls, 0); - - for (int i = 0; i < numUrls; i++) { - auto threadChip = ndk::SharedRefBase::make(i, urls[i]); - CHECK_NE(threadChip, nullptr); - mThreadChips.push_back(std::move(threadChip)); - } - - binder_status_t status = ABinderProcess_setupPolling(&fd); - CHECK_EQ(status, ::STATUS_OK); - CHECK_GE(fd, 0); - mBinderFd.reset(fd); -} - -void Service::Update(otSysMainloopContext& context) { - FD_SET(mBinderFd.get(), &context.mReadFdSet); - context.mMaxFd = std::max(context.mMaxFd, mBinderFd.get()); -} - -void Service::Process(const otSysMainloopContext& context) { - if (FD_ISSET(mBinderFd.get(), &context.mReadFdSet)) { - ABinderProcess_handlePolledCommands(); - } -} - -void Service::startLoop(void) { - const struct timeval kPollTimeout = {1, 0}; - otSysMainloopContext context; - int rval; - - ot::Posix::Mainloop::Manager::Get().Add(*this); - - while (true) { - context.mMaxFd = -1; - context.mTimeout = kPollTimeout; - - FD_ZERO(&context.mReadFdSet); - FD_ZERO(&context.mWriteFdSet); - FD_ZERO(&context.mErrorFdSet); - - ot::Posix::Mainloop::Manager::Get().Update(context); - - rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, - &context.mErrorFdSet, &context.mTimeout); - - if (rval >= 0) { - ot::Posix::Mainloop::Manager::Get().Process(context); - } else if (errno != EINTR) { - ALOGE("select() failed: %s", strerror(errno)); - break; - } - } -} -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/service.hpp b/staging/threadnetwork/aidl/default/service.hpp deleted file mode 100644 index 6e6e86845a..0000000000 --- a/staging/threadnetwork/aidl/default/service.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "mainloop.hpp" -#include "thread_chip.hpp" - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -class Service : public ot::Posix::Mainloop::Source { - public: - Service(char* urls[], int numUrls); - - void Update(otSysMainloopContext& context) override; - void Process(const otSysMainloopContext& context) override; - void startLoop(void); - - private: - ::android::base::unique_fd mBinderFd; - std::vector> mThreadChips; -}; -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/thread_chip.cpp b/staging/threadnetwork/aidl/default/thread_chip.cpp deleted file mode 100644 index 9bd729d57e..0000000000 --- a/staging/threadnetwork/aidl/default/thread_chip.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "thread_chip.hpp" - -#include -#include -#include -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -static ndk::ScopedAStatus errorStatus(int32_t error, const char* message) { - return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message)); -} - -ThreadChip::ThreadChip(uint8_t id, char* url) - : mUrl(), - mInterface(handleReceivedFrame, this, mRxFrameBuffer), - mRxFrameBuffer(), - mCallback(nullptr) { - const std::string name(std::string() + IThreadChip::descriptor + "/chip" + std::to_string(id)); - binder_status_t status; - - ALOGI("ServiceName: %s, Url: %s", name.c_str(), url); - CHECK_EQ(mUrl.Init(url), 0); - status = AServiceManager_addService(asBinder().get(), name.c_str()); - CHECK_EQ(status, STATUS_OK); - - mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient( - AIBinder_DeathRecipient_new(ThreadChip::onBinderDied)); - AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinked); -} - -ThreadChip::~ThreadChip() { - AIBinder_DeathRecipient_delete(mDeathRecipient.get()); -} - -void ThreadChip::onBinderDied(void* context) { - reinterpret_cast(context)->onBinderDied(); -} - -void ThreadChip::onBinderDied(void) { - ALOGW("Thread Network HAL client is dead."); -} - -void ThreadChip::onBinderUnlinked(void* context) { - reinterpret_cast(context)->onBinderUnlinked(); -} - -void ThreadChip::onBinderUnlinked(void) { - ALOGW("ThreadChip binder is unlinked."); - deinitChip(); -} - -void ThreadChip::handleReceivedFrame(void* context) { - reinterpret_cast(context)->handleReceivedFrame(); -} - -void ThreadChip::handleReceivedFrame(void) { - if (mCallback != nullptr) { - mCallback->onReceiveSpinelFrame(std::vector( - mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength())); - } - - mRxFrameBuffer.DiscardFrame(); -} - -ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr& in_callback) { - ndk::ScopedAStatus status = initChip(in_callback); - - if (status.isOk()) { - AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this); - ALOGI("Open IThreadChip successfully."); - } else { - ALOGW("Open IThreadChip failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr& in_callback) { - if (in_callback == nullptr) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } else if (mCallback == nullptr) { - if (mInterface.Init(mUrl) != OT_ERROR_NONE) { - return errorStatus(ERROR_FAILED, "Failed to initialize the interface"); - } - - mCallback = in_callback; - ot::Posix::Mainloop::Manager::Get().Add(*this); - return ndk::ScopedAStatus::ok(); - } else { - return errorStatus(ERROR_BUSY, "Interface is already opened"); - } -} - -ndk::ScopedAStatus ThreadChip::close() { - ndk::ScopedAStatus status; - std::shared_ptr callback = mCallback; - - status = deinitChip(); - if (status.isOk()) { - if (callback != nullptr) { - AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this); - } - - ALOGI("Close IThreadChip successfully"); - } else { - ALOGW("Close IThreadChip failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::deinitChip() { - if (mCallback != nullptr) { - mInterface.Deinit(); - ot::Posix::Mainloop::Manager::Get().Remove(*this); - mCallback = nullptr; - return ndk::ScopedAStatus::ok(); - } - - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); -} - -ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector& in_frame) { - ndk::ScopedAStatus status; - otError error; - - if (mCallback == nullptr) { - status = errorStatus(ERROR_FAILED, "The interface is not open"); - } else { - error = mInterface.SendFrame(reinterpret_cast(in_frame.data()), - in_frame.size()); - if (error == OT_ERROR_NONE) { - status = ndk::ScopedAStatus::ok(); - } else if (error == OT_ERROR_NO_BUFS) { - status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send"); - } else if (error == OT_ERROR_BUSY) { - status = errorStatus(ERROR_BUSY, "The interface is busy"); - } else { - status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame"); - } - } - - if (!status.isOk()) { - ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str()); - } - - return status; -} - -ndk::ScopedAStatus ThreadChip::reset() { - mInterface.HardwareReset(); - ALOGI("reset()"); - return ndk::ScopedAStatus::ok(); -} - -void ThreadChip::Update(otSysMainloopContext& context) { - if (mCallback != nullptr) { - mInterface.UpdateFdSet(context.mReadFdSet, context.mWriteFdSet, context.mMaxFd, - context.mTimeout); - } -} - -void ThreadChip::Process(const otSysMainloopContext& context) { - struct RadioProcessContext radioContext; - - if (mCallback != nullptr) { - radioContext.mReadFdSet = &context.mReadFdSet; - radioContext.mWriteFdSet = &context.mWriteFdSet; - mInterface.Process(radioContext); - } -} -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/thread_chip.hpp b/staging/threadnetwork/aidl/default/thread_chip.hpp deleted file mode 100644 index da5cba7585..0000000000 --- a/staging/threadnetwork/aidl/default/thread_chip.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "hdlc_interface.hpp" -#include "lib/spinel/spinel_interface.hpp" -#include "mainloop.hpp" - -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace threadnetwork { - -class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source { - public: - ThreadChip(uint8_t id, char* url); - ~ThreadChip(); - - ndk::ScopedAStatus open(const std::shared_ptr& in_callback) override; - ndk::ScopedAStatus close() override; - ndk::ScopedAStatus sendSpinelFrame(const std::vector& in_frame) override; - ndk::ScopedAStatus reset() override; - void Update(otSysMainloopContext& context) override; - void Process(const otSysMainloopContext& context) override; - - private: - static void onBinderDied(void* context); - void onBinderDied(void); - static void onBinderUnlinked(void* context); - void onBinderUnlinked(void); - static void handleReceivedFrame(void* context); - void handleReceivedFrame(void); - - ndk::ScopedAStatus initChip(const std::shared_ptr& in_callback); - ndk::ScopedAStatus deinitChip(); - - ot::Url::Url mUrl; - ot::Posix::HdlcInterface mInterface; - ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer; - std::shared_ptr mCallback; - ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; -}; - -} // namespace threadnetwork -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/staging/threadnetwork/aidl/default/utils.cpp b/staging/threadnetwork/aidl/default/utils.cpp deleted file mode 100644 index d3b4062ee3..0000000000 --- a/staging/threadnetwork/aidl/default/utils.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -void otLogCritPlat(const char* format, ...) { - va_list args; - - va_start(args, format); - __android_log_vprint(ANDROID_LOG_FATAL, LOG_TAG, format, args); - va_end(args); -} - -void otLogWarnPlat(const char* format, ...) { - va_list args; - - va_start(args, format); - __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, args); - va_end(args); -} diff --git a/staging/threadnetwork/aidl/vts/Android.bp b/staging/threadnetwork/aidl/vts/Android.bp deleted file mode 100644 index e2609ed1b5..0000000000 --- a/staging/threadnetwork/aidl/vts/Android.bp +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -cc_test { - name: "VtsHalThreadNetworkTargetTest", - defaults: [ - "VtsHalTargetTestDefaults", - "use_libaidlvintf_gtest_helper_static", - ], - srcs: [ - "VtsHalThreadNetworkTargetTest.cpp", - ], - - shared_libs: [ - "libbinder", - "libbinder_ndk", - ], - static_libs: [ - "android.hardware.threadnetwork-ndk", - ], - test_suites: [ - "general-tests", - "vts", - ], -} diff --git a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp deleted file mode 100644 index 3e43f9c8b7..0000000000 --- a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "ThreadNetworkHalTargetTest" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using aidl::android::hardware::threadnetwork::BnThreadChipCallback; -using aidl::android::hardware::threadnetwork::IThreadChip; -using android::ProcessState; -using ndk::ScopedAStatus; -using ndk::SpAIBinder; - -namespace { -constexpr static int kCallbackTimeoutMs = 5000; -} // namespace - -class ThreadChipCallback : public BnThreadChipCallback { - public: - ThreadChipCallback(const std::function&)>& on_spinel_message_cb) - : on_spinel_message_cb_(on_spinel_message_cb) {} - - ScopedAStatus onReceiveSpinelFrame(const std::vector& in_aFrame) { - on_spinel_message_cb_(in_aFrame); - return ScopedAStatus::ok(); - } - - private: - std::function&)> on_spinel_message_cb_; -}; - -class ThreadNetworkAidl : public testing::TestWithParam { - public: - virtual void SetUp() override { - std::string serviceName = GetParam(); - - ALOGI("serviceName: %s", serviceName.c_str()); - - thread_chip = IThreadChip::fromBinder( - SpAIBinder(AServiceManager_waitForService(serviceName.c_str()))); - ASSERT_NE(thread_chip, nullptr); - } - - virtual void TearDown() override { thread_chip->close(); } - - std::shared_ptr thread_chip; -}; - -TEST_P(ThreadNetworkAidl, Open) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_EQ(thread_chip->open(callback).getServiceSpecificError(), IThreadChip::ERROR_BUSY); -} - -TEST_P(ThreadNetworkAidl, Close) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_TRUE(thread_chip->close().isOk()); - EXPECT_EQ(thread_chip->close().getExceptionCode(), EX_ILLEGAL_STATE); -} - -TEST_P(ThreadNetworkAidl, Reset) { - std::shared_ptr callback = - ndk::SharedRefBase::make([](auto /* data */) {}); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - EXPECT_TRUE(thread_chip->reset().isOk()); -} - -TEST_P(ThreadNetworkAidl, SendSpinelFrame) { - const uint8_t kCmdOffset = 2; - const uint8_t kMajorVersionOffset = 3; - const uint8_t kMinorVersionOffset = 4; - const std::vector kGetSpinelProtocolVersion({0x81, 0x02, 0x01}); - const std::vector kGetSpinelProtocolVersionResponse({0x81, 0x06, 0x01, 0x04, 0x03}); - uint8_t min_major_version = kGetSpinelProtocolVersionResponse[kMajorVersionOffset]; - uint8_t min_minor_version = kGetSpinelProtocolVersionResponse[kMinorVersionOffset]; - uint8_t major_version; - uint8_t minor_version; - std::promise open_cb_promise; - std::future open_cb_future{open_cb_promise.get_future()}; - std::shared_ptr callback; - std::vector received_frame; - std::chrono::milliseconds timeout{kCallbackTimeoutMs}; - - callback = ndk::SharedRefBase::make( - [&](const std::vector& in_aFrame) { - if (in_aFrame.size() == kGetSpinelProtocolVersionResponse.size() && - in_aFrame[kCmdOffset] == kGetSpinelProtocolVersionResponse[kCmdOffset]) { - major_version = in_aFrame[kMajorVersionOffset]; - minor_version = in_aFrame[kMinorVersionOffset]; - open_cb_promise.set_value(); - } - }); - - ASSERT_NE(callback, nullptr); - - EXPECT_TRUE(thread_chip->open(callback).isOk()); - - EXPECT_TRUE(thread_chip->sendSpinelFrame(kGetSpinelProtocolVersion).isOk()); - EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); - - EXPECT_GE(major_version, min_major_version); - if (major_version == min_major_version) { - EXPECT_GE(minor_version, min_minor_version); - } -} - -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThreadNetworkAidl); -INSTANTIATE_TEST_SUITE_P( - Thread, ThreadNetworkAidl, - testing::ValuesIn(android::getAidlHalInstanceNames(IThreadChip::descriptor)), - android::PrintInstanceNameToString); - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - ProcessState::self()->setThreadPoolMaxThreadCount(1); - ProcessState::self()->startThreadPool(); - return RUN_ALL_TESTS(); -} From def5b04848655ac61a26ca8a291a729237f4615d Mon Sep 17 00:00:00 2001 From: Jeff Pu Date: Thu, 25 May 2023 14:28:16 -0400 Subject: [PATCH 013/152] Simulate finger touch with virtual fingerprint hal Bug: 277780272 Test: atest BiometricsE2eTests Change-Id: I9330b3eeca52321c59d0af63782d38cd3b5f901f --- .../aidl/default/FakeFingerprintEngine.cpp | 85 +++++++++++++++---- .../default/FakeFingerprintEngineSide.cpp | 8 +- .../default/FakeFingerprintEngineUdfps.cpp | 63 ++------------ .../fingerprint/aidl/default/Fingerprint.cpp | 14 +-- .../default/include/FakeFingerprintEngine.h | 24 +++++- .../include/FakeFingerprintEngineUdfps.h | 25 +----- .../aidl/default/include/Fingerprint.h | 1 + .../tests/FakeFingerprintEngineTest.cpp | 21 +++++ 8 files changed, 135 insertions(+), 106 deletions(-) diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp index 90ec8f26ee..584d31ff1b 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp @@ -31,6 +31,9 @@ using ::android::base::ParseInt; namespace aidl::android::hardware::biometrics::fingerprint { +FakeFingerprintEngine::FakeFingerprintEngine() + : mRandom(std::mt19937::default_seed), mWorkMode(WorkMode::kIdle) {} + void FakeFingerprintEngine::generateChallengeImpl(ISessionCallback* cb) { BEGIN_OP(0); std::uniform_int_distribution dist; @@ -48,6 +51,64 @@ void FakeFingerprintEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t ch void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat, const std::future& cancel) { + BEGIN_OP(0); + updateContext(WorkMode::kEnroll, cb, const_cast&>(cancel), 0, hat); +} + +void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t operationId, + const std::future& cancel) { + BEGIN_OP(0); + updateContext(WorkMode::kAuthenticate, cb, const_cast&>(cancel), operationId, + keymaster::HardwareAuthToken()); +} + +void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb, + const std::future& cancel) { + BEGIN_OP(0); + + auto detectInteractionSupported = + FingerprintHalProperties::detect_interaction().value_or(false); + if (!detectInteractionSupported) { + LOG(ERROR) << "Detect interaction is not supported"; + cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); + return; + } + + updateContext(WorkMode::kDetectInteract, cb, const_cast&>(cancel), 0, + keymaster::HardwareAuthToken()); +} + +void FakeFingerprintEngine::updateContext(WorkMode mode, ISessionCallback* cb, + std::future& cancel, int64_t operationId, + const keymaster::HardwareAuthToken& hat) { + mCancel = std::move(cancel); + mWorkMode = mode; + mCb = cb; + mOperationId = operationId; + mHat = hat; +} + +void FakeFingerprintEngine::fingerDownAction() { + LOG(INFO) << __func__; + switch (mWorkMode) { + case WorkMode::kAuthenticate: + onAuthenticateFingerDown(mCb, mOperationId, mCancel); + break; + case WorkMode::kEnroll: + onEnrollFingerDown(mCb, mHat, mCancel); + break; + case WorkMode::kDetectInteract: + onDetectInteractFingerDown(mCb, mCancel); + break; + default: + LOG(WARNING) << "unexpected mode: on fingerDownAction(), " << (int)mWorkMode; + break; + } +} + +void FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, + const keymaster::HardwareAuthToken& hat, + const std::future& cancel) { BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency())); // Do proper HAT verification in the real implementation. @@ -116,8 +177,9 @@ void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb, } } -void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* operationId */, - const std::future& cancel) { +void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, + int64_t /* operationId */, + const std::future& cancel) { BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency())); int64_t now = Util::getSystemNanoTime(); @@ -197,21 +259,13 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op } } -void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb, - const std::future& cancel) { +void FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb, + const std::future& cancel) { BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency())); int64_t duration = FingerprintHalProperties::operation_detect_interaction_duration().value_or(10); - auto detectInteractionSupported = - FingerprintHalProperties::detect_interaction().value_or(false); - if (!detectInteractionSupported) { - LOG(ERROR) << "Detect interaction is not supported"; - cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); - return; - } - auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1"); auto acquiredInfos = parseIntSequence(acquired); int N = acquiredInfos.size(); @@ -339,6 +393,7 @@ ndk::ScopedAStatus FakeFingerprintEngine::onPointerDownImpl(int32_t /*pointerId* int32_t /*y*/, float /*minor*/, float /*major*/) { BEGIN_OP(0); + fingerDownAction(); return ndk::ScopedAStatus::ok(); } @@ -369,7 +424,8 @@ bool FakeFingerprintEngine::getSensorLocationConfig(SensorLocation& out) { if (dim.size() >= 4) { d = dim[3]; } - if (isValidStr) out = {0, x, y, r, d}; + if (isValidStr) + out = {.sensorLocationX = x, .sensorLocationY = y, .sensorRadius = r, .display = d}; return isValidStr; } @@ -385,8 +441,7 @@ SensorLocation FakeFingerprintEngine::getSensorLocation() { } SensorLocation FakeFingerprintEngine::defaultSensorLocation() { - return {0 /* displayId (not used) */, 0 /* sensorLocationX */, 0 /* sensorLocationY */, - 0 /* sensorRadius */, "" /* display */}; + return SensorLocation(); } std::vector FakeFingerprintEngine::parseIntSequence(const std::string& str, diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp index 9f736e7abf..6982072dc4 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp @@ -28,10 +28,8 @@ using namespace ::android::fingerprint::virt; namespace aidl::android::hardware::biometrics::fingerprint { SensorLocation FakeFingerprintEngineSide::defaultSensorLocation() { - SensorLocation location; - - return {0 /* displayId (not used) */, defaultSensorLocationX /* sensorLocationX */, - defaultSensorLocationY /* sensorLocationY */, defaultSensorRadius /* sensorRadius */, - "" /* display */}; + return SensorLocation{.sensorLocationX = defaultSensorLocationX, + .sensorLocationY = defaultSensorLocationY, + .sensorRadius = defaultSensorRadius}; } } // namespace aidl::android::hardware::biometrics::fingerprint diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp index 3cdfc70008..68b0f0d0de 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp @@ -31,12 +31,12 @@ using namespace ::android::fingerprint::virt; namespace aidl::android::hardware::biometrics::fingerprint { FakeFingerprintEngineUdfps::FakeFingerprintEngineUdfps() - : FakeFingerprintEngine(), mWorkMode(WorkMode::kIdle), mPointerDownTime(0), mUiReadyTime(0) {} + : FakeFingerprintEngine(), mPointerDownTime(0), mUiReadyTime(0) {} SensorLocation FakeFingerprintEngineUdfps::defaultSensorLocation() { - return {0 /* displayId (not used) */, defaultSensorLocationX /* sensorLocationX */, - defaultSensorLocationY /* sensorLocationY */, defaultSensorRadius /* sensorRadius */, - "" /* display */}; + return SensorLocation{.sensorLocationX = defaultSensorLocationX, + .sensorLocationY = defaultSensorLocationY, + .sensorRadius = defaultSensorRadius}; } ndk::ScopedAStatus FakeFingerprintEngineUdfps::onPointerDownImpl(int32_t /*pointerId*/, @@ -70,68 +70,17 @@ ndk::ScopedAStatus FakeFingerprintEngineUdfps::onUiReadyImpl() { } void FakeFingerprintEngineUdfps::fingerDownAction() { - switch (mWorkMode) { - case WorkMode::kAuthenticate: - onAuthenticateFingerDown(); - break; - case WorkMode::kEnroll: - onEnrollFingerDown(); - break; - case WorkMode::kDetectInteract: - onDetectInteractFingerDown(); - break; - default: - LOG(WARNING) << "unexpected call: onUiReady()"; - break; - } - + FakeFingerprintEngine::fingerDownAction(); mUiReadyTime = 0; mPointerDownTime = 0; } -void FakeFingerprintEngineUdfps::onAuthenticateFingerDown() { - FakeFingerprintEngine::authenticateImpl(mCb, mOperationId, mCancelVec[0]); -} - -void FakeFingerprintEngineUdfps::onEnrollFingerDown() { - // Any use case to emulate display touch for each capture during enrollment? - FakeFingerprintEngine::enrollImpl(mCb, mHat, mCancelVec[0]); -} - -void FakeFingerprintEngineUdfps::onDetectInteractFingerDown() { - FakeFingerprintEngine::detectInteractionImpl(mCb, mCancelVec[0]); -} - -void FakeFingerprintEngineUdfps::enrollImpl(ISessionCallback* cb, - const keymaster::HardwareAuthToken& hat, - const std::future& cancel) { - updateContext(WorkMode::kEnroll, cb, const_cast&>(cancel), 0, hat); -} - -void FakeFingerprintEngineUdfps::authenticateImpl(ISessionCallback* cb, int64_t operationId, - const std::future& cancel) { - updateContext(WorkMode::kAuthenticate, cb, const_cast&>(cancel), operationId, - keymaster::HardwareAuthToken()); -} - -void FakeFingerprintEngineUdfps::detectInteractionImpl(ISessionCallback* cb, - const std::future& cancel) { - updateContext(WorkMode::kDetectInteract, cb, const_cast&>(cancel), 0, - keymaster::HardwareAuthToken()); -} - void FakeFingerprintEngineUdfps::updateContext(WorkMode mode, ISessionCallback* cb, std::future& cancel, int64_t operationId, const keymaster::HardwareAuthToken& hat) { + FakeFingerprintEngine::updateContext(mode, cb, cancel, operationId, hat); mPointerDownTime = 0; mUiReadyTime = 0; - mCancelVec.clear(); - - mCancelVec.push_back(std::move(cancel)); - mWorkMode = mode; - mCb = cb; - mOperationId = operationId; - mHat = hat; } } // namespace aidl::android::hardware::biometrics::fingerprint diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp index f00a49d26e..79b563e5ad 100644 --- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp +++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp @@ -17,6 +17,7 @@ #include "Fingerprint.h" #include "Session.h" +#include #include #include @@ -59,6 +60,7 @@ Fingerprint::Fingerprint() : mWorker(MAX_WORKER_QUEUE_SIZE) { << sensorTypeProp; } LOG(INFO) << "sensorTypeProp:" << sensorTypeProp; + LOG(INFO) << "ro.product.name=" << ::android::base::GetProperty("ro.product.name", "UNKNOWN"); } ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector* out) { @@ -105,16 +107,16 @@ ndk::ScopedAStatus Fingerprint::createSession(int32_t sensorId, int32_t userId, mSession->linkToDeath(cb->asBinder().get()); - LOG(INFO) << "createSession: sensorId:" << sensorId << " userId:" << userId; + LOG(INFO) << __func__ << ": sensorId:" << sensorId << " userId:" << userId; return ndk::ScopedAStatus::ok(); } binder_status_t Fingerprint::dump(int fd, const char** /*args*/, uint32_t numArgs) { if (fd < 0) { - LOG(ERROR) << "Fingerprint::dump fd invalid: " << fd; + LOG(ERROR) << __func__ << "fd invalid: " << fd; return STATUS_BAD_VALUE; } else { - LOG(INFO) << "Fingerprint::dump fd:" << fd << "numArgs:" << numArgs; + LOG(INFO) << __func__ << " fd:" << fd << "numArgs:" << numArgs; } dprintf(fd, "----- FingerprintVirtualHal::dump -----\n"); @@ -131,11 +133,11 @@ binder_status_t Fingerprint::dump(int fd, const char** /*args*/, uint32_t numArg binder_status_t Fingerprint::handleShellCommand(int in, int out, int err, const char** args, uint32_t numArgs) { - LOG(INFO) << "Fingerprint::handleShellCommand in:" << in << " out:" << out << " err:" << err + LOG(INFO) << __func__ << " in:" << in << " out:" << out << " err:" << err << " numArgs:" << numArgs; if (numArgs == 0) { - LOG(INFO) << "Fingerprint::handleShellCommand: available commands"; + LOG(INFO) << __func__ << ": available commands"; onHelp(out); return STATUS_OK; } @@ -163,7 +165,7 @@ void Fingerprint::onHelp(int fd) { } void Fingerprint::resetConfigToDefault() { - LOG(INFO) << "reset virtual HAL configuration to default"; + LOG(INFO) << __func__ << ": reset virtual HAL configuration to default"; #define RESET_CONFIG_O(__NAME__) \ if (FingerprintHalProperties::__NAME__()) FingerprintHalProperties::__NAME__(std::nullopt) #define RESET_CONFIG_V(__NAME__) \ diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h index 1279cd92a5..f9d02a72fa 100644 --- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h +++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h @@ -38,7 +38,7 @@ namespace aidl::android::hardware::biometrics::fingerprint { // A fake engine that is backed by system properties instead of hardware. class FakeFingerprintEngine { public: - FakeFingerprintEngine() : mRandom(std::mt19937::default_seed) {} + FakeFingerprintEngine(); virtual ~FakeFingerprintEngine() {} void generateChallengeImpl(ISessionCallback* cb); @@ -66,6 +66,8 @@ class FakeFingerprintEngine { virtual SensorLocation defaultSensorLocation(); + virtual void fingerDownAction(); + std::vector parseIntSequence(const std::string& str, const std::string& sep = ","); std::vector> parseEnrollmentCapture(const std::string& str); @@ -74,15 +76,35 @@ class FakeFingerprintEngine { std::mt19937 mRandom; + enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract }; + + WorkMode getWorkMode() { return mWorkMode; } + virtual std::string toString() const { std::ostringstream os; os << "----- FakeFingerprintEngine:: -----" << std::endl; + os << "mWorkMode:" << (int)mWorkMode; os << "acquiredVendorInfoBase:" << FINGERPRINT_ACQUIRED_VENDOR_BASE; os << ", errorVendorBase:" << FINGERPRINT_ERROR_VENDOR_BASE << std::endl; os << mLockoutTracker.toString(); return os.str(); } + protected: + virtual void updateContext(WorkMode mode, ISessionCallback* cb, std::future& cancel, + int64_t operationId, const keymaster::HardwareAuthToken& hat); + + void onEnrollFingerDown(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat, + const std::future& cancel); + void onAuthenticateFingerDown(ISessionCallback* cb, int64_t, const std::future& cancel); + void onDetectInteractFingerDown(ISessionCallback* cb, const std::future& cancel); + + WorkMode mWorkMode; + ISessionCallback* mCb; + keymaster::HardwareAuthToken mHat; + std::future mCancel; + int64_t mOperationId; + private: static constexpr int32_t FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000; diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h index c5e93e72aa..2270eca532 100644 --- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h +++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h @@ -42,39 +42,20 @@ class FakeFingerprintEngineUdfps : public FakeFingerprintEngine { SensorLocation defaultSensorLocation() override; - void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat, - const std::future& cancel); - void authenticateImpl(ISessionCallback* cb, int64_t operationId, - const std::future& cancel); - void detectInteractionImpl(ISessionCallback* cb, const std::future& cancel); - - enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract }; - - WorkMode getWorkMode() { return mWorkMode; } + void updateContext(WorkMode mode, ISessionCallback* cb, std::future& cancel, + int64_t operationId, const keymaster::HardwareAuthToken& hat); + void fingerDownAction(); std::string toString() const { std::ostringstream os; os << FakeFingerprintEngine::toString(); os << "----- FakeFingerprintEngineUdfps -----" << std::endl; - os << "mWorkMode:" << (int)mWorkMode; os << ", mUiReadyTime:" << mUiReadyTime; os << ", mPointerDownTime:" << mPointerDownTime << std::endl; return os.str(); } private: - void onAuthenticateFingerDown(); - void onEnrollFingerDown(); - void onDetectInteractFingerDown(); - void fingerDownAction(); - void updateContext(WorkMode mode, ISessionCallback* cb, std::future& cancel, - int64_t operationId, const keymaster::HardwareAuthToken& hat); - - WorkMode mWorkMode; - ISessionCallback* mCb; - keymaster::HardwareAuthToken mHat; - std::vector> mCancelVec; - int64_t mOperationId; int64_t mPointerDownTime; int64_t mUiReadyTime; }; diff --git a/biometrics/fingerprint/aidl/default/include/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h index fc4fb8dbff..2bd66d4e0b 100644 --- a/biometrics/fingerprint/aidl/default/include/Fingerprint.h +++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h @@ -43,6 +43,7 @@ class Fingerprint : public BnFingerprint { private: void resetConfigToDefault(); void onHelp(int); + void onSimFingerDown(); std::unique_ptr mEngine; WorkerThread mWorker; diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp index a200b39739..c34f5d7c15 100644 --- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp +++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp @@ -178,6 +178,8 @@ TEST_F(FakeFingerprintEngineTest, Enroll) { FingerprintHalProperties::next_enrollment("4:0,0:true"); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future()); + ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kEnroll); + mEngine.fingerDownAction(); ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value()); ASSERT_EQ(1, FingerprintHalProperties::enrollments().size()); ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value()); @@ -192,6 +194,7 @@ TEST_F(FakeFingerprintEngineTest, EnrollCancel) { keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mCancel.set_value(); mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(Error::CANCELED, mCallback->mError); ASSERT_EQ(-1, mCallback->mLastEnrolled); ASSERT_EQ(0, FingerprintHalProperties::enrollments().size()); @@ -204,6 +207,7 @@ TEST_F(FakeFingerprintEngineTest, EnrollFail) { FingerprintHalProperties::next_enrollment(next); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError); ASSERT_EQ(-1, mCallback->mLastEnrolled); ASSERT_EQ(0, FingerprintHalProperties::enrollments().size()); @@ -216,6 +220,7 @@ TEST_F(FakeFingerprintEngineTest, EnrollAcquired) { keymaster::HardwareAuthToken hat{.mac = {2, 4}}; int32_t prevCnt = mCallback->mLastAcquiredCount; mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value()); ASSERT_EQ(1, FingerprintHalProperties::enrollments().size()); ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value()); @@ -229,6 +234,8 @@ TEST_F(FakeFingerprintEngineTest, Authenticate) { FingerprintHalProperties::enrollments({1, 2}); FingerprintHalProperties::enrollment_hit(2); mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate); + mEngine.fingerDownAction(); ASSERT_FALSE(mCallback->mAuthenticateFailed); ASSERT_EQ(2, mCallback->mLastAuthenticated); ASSERT_EQ(1, mCallback->mLastAcquiredInfo); @@ -239,6 +246,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) { FingerprintHalProperties::enrollment_hit(2); mCancel.set_value(); mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(Error::CANCELED, mCallback->mError); ASSERT_EQ(-1, mCallback->mLastAuthenticated); } @@ -247,6 +255,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateNotSet) { FingerprintHalProperties::enrollments({1, 2}); FingerprintHalProperties::enrollment_hit({}); mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_TRUE(mCallback->mAuthenticateFailed); } @@ -254,6 +263,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateNotEnrolled) { FingerprintHalProperties::enrollments({1, 2}); FingerprintHalProperties::enrollment_hit(3); mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_TRUE(mCallback->mAuthenticateFailed); } @@ -262,6 +272,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) { FingerprintHalProperties::enrollment_hit(2); FingerprintHalProperties::lockout(true); mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_TRUE(mCallback->mLockoutPermanent); ASSERT_NE(mCallback->mError, Error::UNKNOWN); } @@ -269,6 +280,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) { TEST_F(FakeFingerprintEngineTest, AuthenticateError8) { FingerprintHalProperties::operation_authenticate_error(8); mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(mCallback->mError, (Error)8); ASSERT_EQ(mCallback->mErrorVendorCode, 0); } @@ -276,6 +288,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateError8) { TEST_F(FakeFingerprintEngineTest, AuthenticateError9) { FingerprintHalProperties::operation_authenticate_error(1009); mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(mCallback->mError, (Error)7); ASSERT_EQ(mCallback->mErrorVendorCode, 9); } @@ -287,6 +300,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateAcquired) { FingerprintHalProperties::operation_authenticate_acquired("4,1009"); int32_t prevCount = mCallback->mLastAcquiredCount; mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_FALSE(mCallback->mAuthenticateFailed); ASSERT_EQ(2, mCallback->mLastAuthenticated); ASSERT_EQ(prevCount + 2, mCallback->mLastAcquiredCount); @@ -300,6 +314,8 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetect) { FingerprintHalProperties::enrollment_hit(2); FingerprintHalProperties::operation_detect_interaction_acquired(""); mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future()); + ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kDetectInteract); + mEngine.fingerDownAction(); ASSERT_EQ(1, mCallback->mInteractionDetectedCount); ASSERT_EQ(1, mCallback->mLastAcquiredInfo); } @@ -310,6 +326,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) { FingerprintHalProperties::enrollment_hit(2); mCancel.set_value(); mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(Error::CANCELED, mCallback->mError); ASSERT_EQ(0, mCallback->mInteractionDetectedCount); } @@ -319,6 +336,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectNotSet) { FingerprintHalProperties::enrollments({1, 2}); FingerprintHalProperties::enrollment_hit({}); mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(0, mCallback->mInteractionDetectedCount); } @@ -326,6 +344,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectNotEnrolled) { FingerprintHalProperties::enrollments({1, 2}); FingerprintHalProperties::enrollment_hit(25); mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(0, mCallback->mInteractionDetectedCount); } @@ -333,6 +352,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectError) { FingerprintHalProperties::detect_interaction(true); FingerprintHalProperties::operation_detect_interaction_error(8); mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(0, mCallback->mInteractionDetectedCount); ASSERT_EQ(mCallback->mError, (Error)8); ASSERT_EQ(mCallback->mErrorVendorCode, 0); @@ -345,6 +365,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectAcquired) { FingerprintHalProperties::operation_detect_interaction_acquired("4,1013"); int32_t prevCount = mCallback->mLastAcquiredCount; mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future()); + mEngine.fingerDownAction(); ASSERT_EQ(1, mCallback->mInteractionDetectedCount); ASSERT_EQ(prevCount + 2, mCallback->mLastAcquiredCount); ASSERT_EQ(7, mCallback->mLastAcquiredInfo); From 0e4f9eb2aacb1f57fd088b8ead9c43d06fde7636 Mon Sep 17 00:00:00 2001 From: Jeff Pu Date: Mon, 5 Jun 2023 21:07:16 +0000 Subject: [PATCH 014/152] Remove the workaround of extra enrollment for the fixed b/243129174 Bug: 284475725 Test: atest BiometricsE2eTests Change-Id: I92a2153d45e01543dcfdccf131905b6fd557fb34 --- .../fingerprint/aidl/default/FakeFingerprintEngine.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp index 90ec8f26ee..55462c2a68 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp @@ -263,11 +263,6 @@ void FakeFingerprintEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) { BEGIN_OP(0); std::vector ids; - // There are some enrollment sync issue with framework, which results in - // a single template removal during the very firt sync command after reboot. - // This is a workaround for now. TODO(b/243129174) - ids.push_back(-1); - for (auto& enrollment : FingerprintHalProperties::enrollments()) { auto id = enrollment.value_or(0); if (id > 0) { From 0576dbcee85dd3d8b12c73d0fc92c3a10645324a Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Sat, 17 Jun 2023 03:59:51 +0000 Subject: [PATCH 015/152] Fixed metadata label in AIDL radio HAL Metadata Bug: 287517076 Test: atest VtsHalBroadcastradioAidlTargetTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:285598dde00128cfc5fa5a9f7b7847d31daf3620) Merged-In: I612ca079bda6f47446ec75ca7b4fece7317bd56d Change-Id: I612ca079bda6f47446ec75ca7b4fece7317bd56d --- .../hardware/broadcastradio/Metadata.aidl | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl index 3298cac969..7769b8c373 100644 --- a/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl +++ b/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl @@ -70,9 +70,9 @@ union Metadata { /** * Station name. * - * This is a generic field to cover any radio technology. + *

This is a generic field to cover any radio technology. * - * If the PROGRAM_NAME has the same content as DAB_*_NAME or RDS_PS, + *

Note: If the program name has the same content as dab*Name or ({@link Metadata#rdsPs}, * it may not be present, to preserve space - framework must repopulate * it on the client side. */ @@ -86,10 +86,10 @@ union Metadata { /** * DAB ensemble name abbreviated (string). * - * The string must be up to 8 characters long. + *

Note: The string must be up to 8 characters long. * - * If the short variant is present, the long (DAB_ENSEMBLE_NAME) one must be - * present as well. + *

Note: If the short variant is present, the long ({@link Metadata#dabEnsembleName}) + * one must be present as well. */ String dabEnsembleNameShort; @@ -99,7 +99,9 @@ union Metadata { String dabServiceName; /** - * DAB service name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string) + * DAB service name abbreviated (string) + * + *

Note: The string must be up to 8 characters long. */ String dabServiceNameShort; @@ -109,7 +111,9 @@ union Metadata { String dabComponentName; /** - * DAB component name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string) + * DAB component name abbreviated (string) + * + *

Note: The string must be up to 8 characters long. */ String dabComponentNameShort; } From 84310761ce899047b07f4616beed8a7c25f71a3f Mon Sep 17 00:00:00 2001 From: Ye Jiao Date: Fri, 16 Jun 2023 17:21:01 +0800 Subject: [PATCH 016/152] Fix memory leak in WifiLegacyHal. `WifiLegacyHal::getSupportedRadioCombinationsMatrix()` allocs a buffer and returns it to `WifiChip::getSupportedRadioCombinationsInternal()`, but `WifiChip::getSupportedRadioCombinationsInternal()` never frees it. Bug: 287883356 Test: manually test Change-Id: I0e9d529e93cbb5fe254d48947661a2ae3d99d763 --- wifi/aidl/default/wifi_chip.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp index 6dd9156414..8265e5bdc9 100644 --- a/wifi/aidl/default/wifi_chip.cpp +++ b/wifi/aidl/default/wifi_chip.cpp @@ -1452,14 +1452,24 @@ WifiChip::getSupportedRadioCombinationsInternal() { if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to get SupportedRadioCombinations matrix from legacy HAL: " << legacyErrorToString(legacy_status); + if (legacy_matrix != nullptr) { + free(legacy_matrix); + } return {aidl_combinations, createWifiStatusFromLegacyError(legacy_status)}; } if (!aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix, &aidl_combinations)) { LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToAidl() "; + if (legacy_matrix != nullptr) { + free(legacy_matrix); + } return {aidl_combinations, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; } + + if (legacy_matrix != nullptr) { + free(legacy_matrix); + } return {aidl_combinations, ndk::ScopedAStatus::ok()}; } From 8687b2a585f4d8ba3365d62d966b99d5dfd40d1d Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Fri, 23 Jun 2023 23:46:42 +0000 Subject: [PATCH 017/152] Remove unnecessary assert to fix flaky test Bug: 285214482 Test: atest VtsHalGnssTargetTest --iterations=100 -- --test-arg com.android.tradefed.testtype.GTest:native-test-flag:"--gtest_filter=*TestGnssMeasurementIntervals_WithoutLocation*" Change-Id: Ib6aa8e5be17c50d00faea5096e7cee481acb8584 --- gnss/aidl/vts/gnss_hal_test.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp index 4f5e6a0b6b..5e2cbe3c52 100644 --- a/gnss/aidl/vts/gnss_hal_test.cpp +++ b/gnss/aidl/vts/gnss_hal_test.cpp @@ -486,8 +486,6 @@ void GnssHalTest::collectSvInfoListTimestamps(const int numMeasurementEvents, auto status = aidl_gnss_hal_->startSvStatus(); EXPECT_TRUE(status.isOk()); - ASSERT_TRUE(aidl_gnss_cb_->sv_info_list_timestamps_millis_cbq_.size() == - aidl_gnss_cb_->sv_info_list_cbq_.size()); long lastElapsedRealtimeMillis = 0; for (int i = 0; i < numMeasurementEvents; i++) { long timeStamp; From 8b39328dccd796888aeb566f60f145a70e6d503a Mon Sep 17 00:00:00 2001 From: mike liao Date: Mon, 26 Jun 2023 14:12:48 +0800 Subject: [PATCH 018/152] Add fix vts fail when configureMonitorEvent [Description] VTS StartFilterInDemux failed when configureMonitorEvent is called [Root Cause] Scrambling status event is not notified when configureMonitorEvent is called so test case failed. [Solution] Scrambling status event is not notified because of no input data. Add input setting and check event notified or not after data is input. Test: Manual bug: 288193021 Change-Id: If5875d064fd67b72f8299205a5e35b1a2bd61934 (cherry picked from commit def46527927875efad5a3fbfb5e6a695a9106d51) --- tv/tuner/1.1/vts/functional/FilterTests.cpp | 17 +++++++++++------ tv/tuner/1.1/vts/functional/FilterTests.h | 1 + .../functional/VtsHalTvTunerV1_1TargetTest.cpp | 5 +++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp index 8bdf8f68b8..a24cd63f42 100644 --- a/tv/tuner/1.1/vts/functional/FilterTests.cpp +++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp @@ -311,12 +311,6 @@ AssertionResult FilterTests::configureMonitorEvent(uint64_t filterId, uint32_t m android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilters[filterId]); if (filter_v1_1 != NULL) { status = filter_v1_1->configureMonitorEvent(monitorEventTypes); - if (monitorEventTypes & DemuxFilterMonitorEventType::SCRAMBLING_STATUS) { - mFilterCallbacks[filterId]->testFilterScramblingEvent(); - } - if (monitorEventTypes & DemuxFilterMonitorEventType::IP_CID_CHANGE) { - mFilterCallbacks[filterId]->testFilterIpCidEvent(); - } } else { ALOGW("[vts] Can't cast IFilter into v1_1."); return failure(); @@ -324,6 +318,17 @@ AssertionResult FilterTests::configureMonitorEvent(uint64_t filterId, uint32_t m return AssertionResult(status == Result::SUCCESS); } +AssertionResult FilterTests::testMonitorEvent(uint64_t filterId, uint32_t monitorEventTypes) { + EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first."; + if (monitorEventTypes & DemuxFilterMonitorEventType::SCRAMBLING_STATUS) { + mFilterCallbacks[filterId]->testFilterScramblingEvent(); + } + if (monitorEventTypes & DemuxFilterMonitorEventType::IP_CID_CHANGE) { + mFilterCallbacks[filterId]->testFilterIpCidEvent(); + } + return AssertionResult(true); +} + AssertionResult FilterTests::startIdTest(uint64_t filterId) { EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first."; mFilterCallbacks[filterId]->testStartIdAfterReconfigure(); diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h index 1a1273ecb4..e652154b36 100644 --- a/tv/tuner/1.1/vts/functional/FilterTests.h +++ b/tv/tuner/1.1/vts/functional/FilterTests.h @@ -159,6 +159,7 @@ class FilterTests { AssertionResult configAvFilterStreamType(AvStreamType type, uint64_t filterId); AssertionResult configIpFilterCid(uint32_t ipCid, uint64_t filterId); AssertionResult configureMonitorEvent(uint64_t filterId, uint32_t monitorEventTypes); + AssertionResult testMonitorEvent(uint64_t filterId, uint32_t monitorEventTypes); AssertionResult getFilterMQDescriptor(uint64_t filterId, bool getMqDesc); AssertionResult startFilter(uint64_t filterId); AssertionResult stopFilter(uint64_t filterId); diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp index 41acaa1704..fccd2ede9b 100644 --- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp +++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp @@ -48,6 +48,11 @@ void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig1_1 filterCo } ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId, filterConf.config1_0.getMqDesc)); ASSERT_TRUE(mFilterTests.startFilter(filterId)); + ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/)); + if (filterConf.monitorEventTypes > 0) { + ASSERT_TRUE(mFilterTests.testMonitorEvent(filterId, filterConf.monitorEventTypes)); + } + ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/)); ASSERT_TRUE(mFilterTests.stopFilter(filterId)); ASSERT_TRUE(mFilterTests.closeFilter(filterId)); ASSERT_TRUE(mDemuxTests.closeDemux()); From 4ff3cf8e73ff700d8eda5abe7fbe06b9de50c288 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 16 Jun 2023 12:16:16 -0700 Subject: [PATCH 019/152] audio: Facilitate extension of Module class by vendors Make interface methods protected so that subclasses can augment them. Provide getters for private fields. Bug: 282568751 Test: atest VtsHalAudioCoreTargetTest Merged-In: I0e4810f8a4c816c4f673139816e9768f6dc8da7c Change-Id: I0e4810f8a4c816c4f673139816e9768f6dc8da7c (cherry picked from commit 57f0dcf78d2a0ecf3dc44a43fbeb9dd116fbcab9) --- audio/aidl/default/include/core-impl/Module.h | 122 ++++++++++-------- audio/aidl/default/usb/ModuleUsb.cpp | 4 +- 2 files changed, 70 insertions(+), 56 deletions(-) diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index 83ecfaa8c6..e8b3d899c3 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -39,33 +39,9 @@ class Module : public BnModule { static StreamIn::CreateInstance getStreamInCreator(Type type); static StreamOut::CreateInstance getStreamOutCreator(Type type); - private: - struct VendorDebug { - static const std::string kForceTransientBurstName; - static const std::string kForceSynchronousDrainName; - bool forceTransientBurst = false; - bool forceSynchronousDrain = false; - }; - // Helper used for interfaces that require a persistent instance. We hold them via a strong - // pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'. - template - struct ChildInterface : private std::pair, ndk::SpAIBinder> { - ChildInterface() {} - ChildInterface& operator=(const std::shared_ptr& c) { - return operator=(std::shared_ptr(c)); - } - ChildInterface& operator=(std::shared_ptr&& c) { - this->first = std::move(c); - this->second = this->first->asBinder(); - AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL, - ANDROID_PRIORITY_AUDIO); - return *this; - } - explicit operator bool() const { return !!this->first; } - C& operator*() const { return *(this->first); } - C* operator->() const { return this->first; } - std::shared_ptr getPtr() const { return this->first; } - }; + protected: + // The vendor extension done via inheritance can override interface methods and augment + // a call to the base implementation. ndk::ScopedAStatus setModuleDebug( const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override; @@ -146,29 +122,46 @@ class Module : public BnModule { ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t* _aidl_return) override; ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override; - void cleanUpPatch(int32_t patchId); - ndk::ScopedAStatus createStreamContext( - int32_t in_portConfigId, int64_t in_bufferSizeFrames, - std::shared_ptr asyncCallback, - std::shared_ptr outEventCallback, - ::aidl::android::hardware::audio::core::StreamContext* out_context); - std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices( - int32_t portConfigId); - std::set findConnectedPortConfigIds(int32_t portConfigId); - ndk::ScopedAStatus findPortIdForNewStream( - int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port); - internal::Configuration& getConfig(); - template - std::set portIdsFromPortConfigIds(C portConfigIds); - void registerPatch(const AudioPatch& patch); - void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch); - bool isMmapSupported(); - // This value is used for all AudioPatches. static constexpr int32_t kMinimumStreamBufferSizeFrames = 256; // The maximum stream buffer size is 1 GiB = 2 ** 30 bytes; static constexpr int32_t kMaximumStreamBufferSizeBytes = 1 << 30; + private: + struct VendorDebug { + static const std::string kForceTransientBurstName; + static const std::string kForceSynchronousDrainName; + bool forceTransientBurst = false; + bool forceSynchronousDrain = false; + }; + // Helper used for interfaces that require a persistent instance. We hold them via a strong + // pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'. + template + struct ChildInterface : private std::pair, ndk::SpAIBinder> { + ChildInterface() {} + ChildInterface& operator=(const std::shared_ptr& c) { + return operator=(std::shared_ptr(c)); + } + ChildInterface& operator=(std::shared_ptr&& c) { + this->first = std::move(c); + this->second = this->first->asBinder(); + AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL, + ANDROID_PRIORITY_AUDIO); + return *this; + } + explicit operator bool() const { return !!this->first; } + C& operator*() const { return *(this->first); } + C* operator->() const { return this->first; } + std::shared_ptr getPtr() const { return this->first; } + }; + // ids of device ports created at runtime via 'connectExternalDevice'. + // Also stores a list of ids of mix ports with dynamic profiles that were populated from + // the connected port. This list can be empty, thus an int->int multimap can't be used. + using ConnectedDevicePorts = std::map>; + // Maps port ids and port config ids to patch ids. + // Multimap because both ports and configs can be used by multiple patches. + using Patches = std::multimap; + const Type mType; std::unique_ptr mConfig; ModuleDebug mDebug; @@ -177,19 +170,18 @@ class Module : public BnModule { ChildInterface mBluetooth; ChildInterface mBluetoothA2dp; ChildInterface mBluetoothLe; - // ids of device ports created at runtime via 'connectExternalDevice'. - // Also stores ids of mix ports with dynamic profiles which got populated from the connected - // port. - std::map> mConnectedDevicePorts; + ConnectedDevicePorts mConnectedDevicePorts; Streams mStreams; - // Maps port ids and port config ids to patch ids. - // Multimap because both ports and configs can be used by multiple patches. - std::multimap mPatches; + Patches mPatches; bool mMicMute = false; + bool mMasterMute = false; + float mMasterVolume = 1.0f; ChildInterface mSoundDose; std::optional mIsMmapSupported; protected: + // The following virtual functions are intended for vendor extension via inheritance. + // If the module is unable to populate the connected device port correctly, the returned error // code must correspond to the errors of `IModule.connectedExternalDevice` method. virtual ndk::ScopedAStatus populateConnectedDevicePort( @@ -204,8 +196,30 @@ class Module : public BnModule { virtual ndk::ScopedAStatus onMasterMuteChanged(bool mute); virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume); - bool mMasterMute = false; - float mMasterVolume = 1.0f; + // Utility and helper functions accessible to subclasses. + void cleanUpPatch(int32_t patchId); + ndk::ScopedAStatus createStreamContext( + int32_t in_portConfigId, int64_t in_bufferSizeFrames, + std::shared_ptr asyncCallback, + std::shared_ptr outEventCallback, + ::aidl::android::hardware::audio::core::StreamContext* out_context); + std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices( + int32_t portConfigId); + std::set findConnectedPortConfigIds(int32_t portConfigId); + ndk::ScopedAStatus findPortIdForNewStream( + int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port); + internal::Configuration& getConfig(); + const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; } + bool getMasterMute() const { return mMasterMute; } + bool getMasterVolume() const { return mMasterVolume; } + bool getMicMute() const { return mMicMute; } + const Patches& getPatches() const { return mPatches; } + const Streams& getStreams() const { return mStreams; } + bool isMmapSupported(); + template + std::set portIdsFromPortConfigIds(C portConfigIds); + void registerPatch(const AudioPatch& patch); + void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch); }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp index ecdbd5cb77..627f854dac 100644 --- a/audio/aidl/default/usb/ModuleUsb.cpp +++ b/audio/aidl/default/usb/ModuleUsb.cpp @@ -175,8 +175,8 @@ void ModuleUsb::onExternalDeviceConnectionChanged( return; } const int card = address.get()[0]; - usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(card, mMasterMute, - mMasterVolume, connected); + usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(card, getMasterMute(), + getMasterVolume(), connected); } ndk::ScopedAStatus ModuleUsb::onMasterMuteChanged(bool mute) { From 45ab8f315ade70335510aa57897690029b2ad23e Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 16 Jun 2023 12:38:25 -0700 Subject: [PATCH 020/152] audio: Pass flags and I/O handle to StreamContext Vendor implementations may need to see the value of flags and the I/O handle of the mix port used to open the stream. Bug: 282568751 Test: atest VtsHalAudioCoreTargetTest Merged-In: If1f346793f3b3a725bc19358909f5b461cb159c1 Change-Id: If1f346793f3b3a725bc19358909f5b461cb159c1 (cherry picked from commit b42a69ef681f3447bb9cb84f9ff3120552b1f3cd) --- audio/aidl/default/Module.cpp | 3 ++- audio/aidl/default/include/core-impl/Stream.h | 14 +++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 6885a49d6b..8a7f9f0d8d 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -207,7 +207,8 @@ ndk::ScopedAStatus Module::createStreamContext( std::make_unique(1, true /*configureEventFlagWord*/), std::make_unique(1, true /*configureEventFlagWord*/), portConfigIt->format.value(), portConfigIt->channelMask.value(), - portConfigIt->sampleRate.value().value, + portConfigIt->sampleRate.value().value, flags, + portConfigIt->ext.get().handle, std::make_unique(frameSize * in_bufferSizeFrames), asyncCallback, outEventCallback, params); if (temp.isValid()) { diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 476f1ff30d..4f84de900b 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,8 @@ class StreamContext { StreamContext(std::unique_ptr commandMQ, std::unique_ptr replyMQ, const ::aidl::android::media::audio::common::AudioFormatDescription& format, const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout, - int sampleRate, std::unique_ptr dataMQ, + int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags, + int32_t mixPortHandle, std::unique_ptr dataMQ, std::shared_ptr asyncCallback, std::shared_ptr outEventCallback, DebugParameters debugParameters) @@ -87,6 +89,8 @@ class StreamContext { mFormat(format), mChannelLayout(channelLayout), mSampleRate(sampleRate), + mFlags(flags), + mMixPortHandle(mixPortHandle), mDataMQ(std::move(dataMQ)), mAsyncCallback(asyncCallback), mOutEventCallback(outEventCallback), @@ -98,6 +102,8 @@ class StreamContext { mFormat(other.mFormat), mChannelLayout(other.mChannelLayout), mSampleRate(other.mSampleRate), + mFlags(std::move(other.mFlags)), + mMixPortHandle(other.mMixPortHandle), mDataMQ(std::move(other.mDataMQ)), mAsyncCallback(std::move(other.mAsyncCallback)), mOutEventCallback(std::move(other.mOutEventCallback)), @@ -109,6 +115,8 @@ class StreamContext { mFormat = std::move(other.mFormat); mChannelLayout = std::move(other.mChannelLayout); mSampleRate = other.mSampleRate; + mFlags = std::move(other.mFlags); + mMixPortHandle = other.mMixPortHandle; mDataMQ = std::move(other.mDataMQ); mAsyncCallback = std::move(other.mAsyncCallback); mOutEventCallback = std::move(other.mOutEventCallback); @@ -126,10 +134,12 @@ class StreamContext { ::aidl::android::media::audio::common::AudioFormatDescription getFormat() const { return mFormat; } + ::aidl::android::media::audio::common::AudioIoFlags getFlags() const { return mFlags; } bool getForceTransientBurst() const { return mDebugParameters.forceTransientBurst; } bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; } size_t getFrameSize() const; int getInternalCommandCookie() const { return mInternalCommandCookie; } + int32_t getMixPortHandle() const { return mMixPortHandle; } std::shared_ptr getOutEventCallback() const { return mOutEventCallback; } @@ -146,6 +156,8 @@ class StreamContext { ::aidl::android::media::audio::common::AudioFormatDescription mFormat; ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout; int mSampleRate; + ::aidl::android::media::audio::common::AudioIoFlags mFlags; + int32_t mMixPortHandle; std::unique_ptr mDataMQ; std::shared_ptr mAsyncCallback; std::shared_ptr mOutEventCallback; // Only used by output streams From f27ff142002697354440b7a9bde6fb4592c66af7 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 23 Jun 2023 13:55:37 -0700 Subject: [PATCH 021/152] audio: Enable use of 'expected_utils' for ScopedAStatus Add necessary helper functions and use RETURN_STATUS_IF_ERROR where possible. Bug: 282568751 Test: atest VtsHalAudioCoreTargetTest Merged-In: If68c995da0e5e0cb2e9c142ba40af6503ff628b2 Change-Id: If68c995da0e5e0cb2e9c142ba40af6503ff628b2 (cherry picked from commit 26dc9add8dd217cbd2d03d2ee9b201869820ac44) --- audio/aidl/common/include/Utils.h | 15 +++++++++ audio/aidl/default/Module.cpp | 54 +++++++++---------------------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h index dd7975d1be..d354859a87 100644 --- a/audio/aidl/common/include/Utils.h +++ b/audio/aidl/common/include/Utils.h @@ -29,6 +29,21 @@ #include #include #include +#include + +namespace ndk { + +// This enables use of 'error/expected_utils' for ScopedAStatus. + +inline bool errorIsOk(const ScopedAStatus& s) { + return s.isOk(); +} + +inline std::string errorToString(const ScopedAStatus& s) { + return s.getDescription(); +} + +} // namespace ndk namespace aidl::android::hardware::audio::common { diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 8a7f9f0d8d..ab71ef4ed2 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -18,12 +18,12 @@ #include #define LOG_TAG "AHAL_Module" -#include -#include - #include #include #include +#include +#include +#include #include "core-impl/Bluetooth.h" #include "core-impl/Module.h" @@ -470,10 +470,7 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA } if (!mDebug.simulateDeviceConnections) { - if (ndk::ScopedAStatus status = populateConnectedDevicePort(&connectedPort); - !status.isOk()) { - return status; - } + RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort)); } else { auto& connectedProfiles = getConfig().connectedProfiles; if (auto connectedProfilesIt = connectedProfiles.find(templateId); @@ -648,27 +645,19 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar LOG(DEBUG) << __func__ << ": port config id " << in_args.portConfigId << ", buffer size " << in_args.bufferSizeFrames << " frames"; AudioPort* port = nullptr; - if (auto status = findPortIdForNewStream(in_args.portConfigId, &port); !status.isOk()) { - return status; - } + RETURN_STATUS_IF_ERROR(findPortIdForNewStream(in_args.portConfigId, &port)); if (port->flags.getTag() != AudioIoFlags::Tag::input) { LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId << " does not correspond to an input mix port"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } StreamContext context; - if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, nullptr, - nullptr, &context); - !status.isOk()) { - return status; - } + RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, + nullptr, nullptr, &context)); context.fillDescriptor(&_aidl_return->desc); std::shared_ptr stream; - ndk::ScopedAStatus status = getStreamInCreator(mType)(in_args.sinkMetadata, std::move(context), - mConfig->microphones, &stream); - if (!status.isOk()) { - return status; - } + RETURN_STATUS_IF_ERROR(getStreamInCreator(mType)(in_args.sinkMetadata, std::move(context), + mConfig->microphones, &stream)); StreamWrapper streamWrapper(stream); AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); @@ -687,9 +676,7 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_ << (in_args.offloadInfo.has_value()) << ", buffer size " << in_args.bufferSizeFrames << " frames"; AudioPort* port = nullptr; - if (auto status = findPortIdForNewStream(in_args.portConfigId, &port); !status.isOk()) { - return status; - } + RETURN_STATUS_IF_ERROR(findPortIdForNewStream(in_args.portConfigId, &port)); if (port->flags.getTag() != AudioIoFlags::Tag::output) { LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId << " does not correspond to an output mix port"; @@ -710,19 +697,13 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } StreamContext context; - if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, - isNonBlocking ? in_args.callback : nullptr, - in_args.eventCallback, &context); - !status.isOk()) { - return status; - } + RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, + isNonBlocking ? in_args.callback : nullptr, + in_args.eventCallback, &context)); context.fillDescriptor(&_aidl_return->desc); std::shared_ptr stream; - ndk::ScopedAStatus status = getStreamOutCreator(mType)( - in_args.sourceMetadata, std::move(context), in_args.offloadInfo, &stream); - if (!status.isOk()) { - return status; - } + RETURN_STATUS_IF_ERROR(getStreamOutCreator(mType)(in_args.sourceMetadata, std::move(context), + in_args.offloadInfo, &stream)); StreamWrapper streamWrapper(stream); AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); @@ -797,10 +778,7 @@ ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPa return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } } - - if (auto status = checkAudioPatchEndpointsMatch(sources, sinks); !status.isOk()) { - return status; - } + RETURN_STATUS_IF_ERROR(checkAudioPatchEndpointsMatch(sources, sinks)); auto& patches = getConfig().patches; auto existing = patches.end(); From ef1345a869352cbcb1d035c9aa114eec2e86fe07 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 23 Jun 2023 13:39:40 -0700 Subject: [PATCH 022/152] audio: Propagate errors from Driver::setConnectedDevices Plumb propagation of errors reported by the implementations of DriverInterface::setConnectedDevices up to the Module. This allows returning the reported errors from the corresponding IModule interface methods. Implement handling of errors from connection state update by the Module implementation. When updating streams about the connection status ensure that the list of connected devices is not empty. Also, add an extra check to AudioStreamIn#ActiveMicrophones to validate the size of the returned active microphones list. Bug: 282568751 Test: atest VtsHalAudioCoreTargetTest Merged-In: I62a422d95c37a672fce4ad221bea435cc7b4ebfa Change-Id: I62a422d95c37a672fce4ad221bea435cc7b4ebfa (cherry picked from commit 75b59dfb4e19c7f60f80e942aebfaae730eb7df2) --- audio/aidl/default/Module.cpp | 86 ++++++++++++++----- audio/aidl/default/include/core-impl/Module.h | 3 +- audio/aidl/default/include/core-impl/Stream.h | 16 ++-- audio/aidl/default/usb/StreamUsb.cpp | 2 +- .../vts/VtsHalAudioCoreModuleTargetTest.cpp | 1 + 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index ab71ef4ed2..c0c6c4889d 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -340,30 +340,61 @@ void Module::registerPatch(const AudioPatch& patch) { do_insert(patch.sinkPortConfigIds); } -void Module::updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch) { +ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatch, + const AudioPatch& newPatch) { // Streams from the old patch need to be disconnected, streams from the new // patch need to be connected. If the stream belongs to both patches, no need // to update it. - std::set idsToDisconnect, idsToConnect; + auto maybeFailure = ndk::ScopedAStatus::ok(); + std::set idsToDisconnect, idsToConnect, idsToDisconnectOnFailure; idsToDisconnect.insert(oldPatch.sourcePortConfigIds.begin(), oldPatch.sourcePortConfigIds.end()); idsToDisconnect.insert(oldPatch.sinkPortConfigIds.begin(), oldPatch.sinkPortConfigIds.end()); idsToConnect.insert(newPatch.sourcePortConfigIds.begin(), newPatch.sourcePortConfigIds.end()); idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end()); std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) { - if (idsToConnect.count(portConfigId) == 0) { - LOG(DEBUG) << "The stream on port config id " << portConfigId << " is not connected"; - mStreams.setStreamIsConnected(portConfigId, {}); + if (idsToConnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) { + if (auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); status.isOk()) { + LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id " + << portConfigId << " has been disconnected"; + } else { + // Disconnection is tricky to roll back, just register a failure. + maybeFailure = std::move(status); + } } }); + if (!maybeFailure.isOk()) return maybeFailure; std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) { - if (idsToDisconnect.count(portConfigId) == 0) { + if (idsToDisconnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) { const auto connectedDevices = findConnectedDevices(portConfigId); - LOG(DEBUG) << "The stream on port config id " << portConfigId - << " is connected to: " << ::android::internal::ToString(connectedDevices); - mStreams.setStreamIsConnected(portConfigId, connectedDevices); + if (connectedDevices.empty()) { + // This is important as workers use the vector size to derive the connection status. + LOG(FATAL) << "updateStreamsConnectedState: No connected devices found for port " + "config id " + << portConfigId; + } + if (auto status = mStreams.setStreamConnectedDevices(portConfigId, connectedDevices); + status.isOk()) { + LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id " + << portConfigId << " has been connected to: " + << ::android::internal::ToString(connectedDevices); + } else { + maybeFailure = std::move(status); + idsToDisconnectOnFailure.insert(portConfigId); + } } }); + if (!maybeFailure.isOk()) { + LOG(WARNING) << __func__ << ": Due to a failure, disconnecting streams on port config ids " + << ::android::internal::ToString(idsToDisconnectOnFailure); + std::for_each(idsToDisconnectOnFailure.begin(), idsToDisconnectOnFailure.end(), + [&](const auto& portConfigId) { + auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); + (void)status.isOk(); // Can't do much about a failure here. + }); + return maybeFailure; + } + return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Module::setModuleDebug( @@ -659,12 +690,12 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar RETURN_STATUS_IF_ERROR(getStreamInCreator(mType)(in_args.sinkMetadata, std::move(context), mConfig->microphones, &stream)); StreamWrapper streamWrapper(stream); + if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) { + RETURN_STATUS_IF_ERROR( + streamWrapper.setConnectedDevices(findConnectedDevices(in_args.portConfigId))); + } AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); - auto patchIt = mPatches.find(in_args.portConfigId); - if (patchIt != mPatches.end()) { - streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId)); - } mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper)); _aidl_return->stream = std::move(stream); return ndk::ScopedAStatus::ok(); @@ -705,12 +736,12 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_ RETURN_STATUS_IF_ERROR(getStreamOutCreator(mType)(in_args.sourceMetadata, std::move(context), in_args.offloadInfo, &stream)); StreamWrapper streamWrapper(stream); + if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) { + RETURN_STATUS_IF_ERROR( + streamWrapper.setConnectedDevices(findConnectedDevices(in_args.portConfigId))); + } AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); - auto patchIt = mPatches.find(in_args.portConfigId); - if (patchIt != mPatches.end()) { - streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId)); - } mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper)); _aidl_return->stream = std::move(stream); return ndk::ScopedAStatus::ok(); @@ -813,13 +844,20 @@ ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPa if (existing == patches.end()) { _aidl_return->id = getConfig().nextPatchId++; patches.push_back(*_aidl_return); - existing = patches.begin() + (patches.size() - 1); } else { oldPatch = *existing; - *existing = *_aidl_return; } - registerPatch(*existing); - updateStreamsConnectedState(oldPatch, *_aidl_return); + patchesBackup = mPatches; + registerPatch(*_aidl_return); + if (auto status = updateStreamsConnectedState(oldPatch, *_aidl_return); !status.isOk()) { + mPatches = std::move(*patchesBackup); + if (existing == patches.end()) { + patches.pop_back(); + } else { + *existing = oldPatch; + } + return status; + } LOG(DEBUG) << __func__ << ": " << (oldPatch.id == 0 ? "created" : "updated") << " patch " << _aidl_return->toString(); @@ -971,8 +1009,12 @@ ndk::ScopedAStatus Module::resetAudioPatch(int32_t in_patchId) { auto& patches = getConfig().patches; auto patchIt = findById(patches, in_patchId); if (patchIt != patches.end()) { + auto patchesBackup = mPatches; cleanUpPatch(patchIt->id); - updateStreamsConnectedState(*patchIt, AudioPatch{}); + if (auto status = updateStreamsConnectedState(*patchIt, AudioPatch{}); !status.isOk()) { + mPatches = std::move(patchesBackup); + return status; + } patches.erase(patchIt); LOG(DEBUG) << __func__ << ": erased patch " << in_patchId; return ndk::ScopedAStatus::ok(); diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index e8b3d899c3..212cfd9570 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -219,7 +219,8 @@ class Module : public BnModule { template std::set portIdsFromPortConfigIds(C portConfigIds); void registerPatch(const AudioPatch& patch); - void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch); + ndk::ScopedAStatus updateStreamsConnectedState(const AudioPatch& oldPatch, + const AudioPatch& newPatch); }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 4f84de900b..826b0f1ec9 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -395,11 +395,11 @@ class StreamCommonImpl : public StreamCommonInterface { : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } bool isClosed() const { return mWorker->isClosed(); } - void setIsConnected( + ndk::ScopedAStatus setConnectedDevices( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { mWorker->setIsConnected(!devices.empty()); mConnectedDevices = devices; - mDriver->setConnectedDevices(devices); + return ndk::ScopedAStatus::fromStatus(mDriver->setConnectedDevices(devices)); } ndk::ScopedAStatus updateMetadata(const Metadata& metadata); @@ -547,12 +547,13 @@ class StreamWrapper { }, mStream); } - void setStreamIsConnected( + ndk::ScopedAStatus setConnectedDevices( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { - std::visit( + return std::visit( [&](auto&& ws) { auto s = ws.lock(); - if (s) s->setIsConnected(devices); + if (s) return s->setConnectedDevices(devices); + return ndk::ScopedAStatus::ok(); }, mStream); } @@ -576,12 +577,13 @@ class Streams { mStreams.insert(std::pair{portConfigId, sw}); mStreams.insert(std::pair{portId, std::move(sw)}); } - void setStreamIsConnected( + ndk::ScopedAStatus setStreamConnectedDevices( int32_t portConfigId, const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { if (auto it = mStreams.find(portConfigId); it != mStreams.end()) { - it->second.setStreamIsConnected(devices); + return it->second.setConnectedDevices(devices); } + return ndk::ScopedAStatus::ok(); } private: diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index 9ac1cc9b77..d2ee484c2d 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -72,7 +72,7 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput) if (mIsInput && connectedDevices.size() > 1) { LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size() << ") for input stream"; - return ::android::BAD_VALUE; + return ::android::INVALID_OPERATION; } for (const auto& connectedDevice : connectedDevices) { if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) { diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index 825b865ef1..0012cd559e 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -2763,6 +2763,7 @@ TEST_P(AudioStreamIn, ActiveMicrophones) { ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get())); std::vector activeMics; EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics)); + EXPECT_FALSE(activeMics.empty()); for (const auto& mic : activeMics) { EXPECT_NE(micInfos.end(), std::find_if(micInfos.begin(), micInfos.end(), From efe980bb4478b91489982deeb30b2106f3fc29dd Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 21 Jun 2023 15:20:31 -0700 Subject: [PATCH 023/152] audio: Refactor streams implementation Simplify the experience of implementing stream variants. Stream class now exposes two interfaces: DriverInterface and StreamCommonInterface, which represent the two aspects of its usage: via the FMQ on the worker thread, and via IStreamCommon Binder interface. Input/output streams now inherit the concrete stream variant, and implement interface methods specific for IStreamIn and IStreamOut. Added DriverInterface::shutdown method which is called on the worker thread prior to the exit. Bug: 282568751 Test: atest VtsHalAudioCoreTargetTest Merged-In: I5bf8da2f22b27f0e284a41fc30b920d87ac2936c Change-Id: I5bf8da2f22b27f0e284a41fc30b920d87ac2936c (cherry picked from commit d5554cfae2a2b7af14c770f4f2f9aded76f64ea1) --- audio/aidl/default/Stream.cpp | 88 +++----- audio/aidl/default/StreamStub.cpp | 51 ++--- audio/aidl/default/include/core-impl/Stream.h | 191 +++++++++--------- .../default/include/core-impl/StreamStub.h | 14 +- .../default/include/core-impl/StreamUsb.h | 23 +-- audio/aidl/default/usb/StreamUsb.cpp | 77 ++++--- 6 files changed, 192 insertions(+), 252 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 77b06011c6..73f1293007 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -152,6 +152,7 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { case Tag::halReservedExit: if (const int32_t cookie = command.get(); cookie == mInternalCommandCookie) { + mDriver->shutdown(); setClosed(); // This is an internal command, no need to reply. return Status::EXIT; @@ -364,6 +365,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { case Tag::halReservedExit: if (const int32_t cookie = command.get(); cookie == mInternalCommandCookie) { + mDriver->shutdown(); setClosed(); // This is an internal command, no need to reply. return Status::EXIT; @@ -567,8 +569,7 @@ bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* rep return !fatal; } -template -StreamCommonImpl::~StreamCommonImpl() { +StreamCommonImpl::~StreamCommonImpl() { if (!isClosed()) { LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak"; stopWorker(); @@ -576,19 +577,16 @@ StreamCommonImpl::~StreamCommonImpl() { } } -template -void StreamCommonImpl::createStreamCommon( +ndk::ScopedAStatus StreamCommonImpl::initInstance( const std::shared_ptr& delegate) { - if (mCommon != nullptr) { - LOG(FATAL) << __func__ << ": attempting to create the common interface twice"; - } - mCommon = ndk::SharedRefBase::make(delegate); + mCommon = ndk::SharedRefBase::make(delegate); mCommonBinder = mCommon->asBinder(); AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); + return mWorker->start() ? ndk::ScopedAStatus::ok() + : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } -template -ndk::ScopedAStatus StreamCommonImpl::getStreamCommon( +ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon( std::shared_ptr* _aidl_return) { if (mCommon == nullptr) { LOG(FATAL) << __func__ << ": the common interface was not created"; @@ -598,30 +596,26 @@ ndk::ScopedAStatus StreamCommonImpl::getStreamCommon( return ndk::ScopedAStatus::ok(); } -template -ndk::ScopedAStatus StreamCommonImpl::updateHwAvSyncId(int32_t in_hwAvSyncId) { +ndk::ScopedAStatus StreamCommonImpl::updateHwAvSyncId(int32_t in_hwAvSyncId) { LOG(DEBUG) << __func__ << ": id " << in_hwAvSyncId; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::getVendorParameters( +ndk::ScopedAStatus StreamCommonImpl::getVendorParameters( const std::vector& in_ids, std::vector* _aidl_return) { LOG(DEBUG) << __func__ << ": id count: " << in_ids.size(); (void)_aidl_return; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::setVendorParameters( +ndk::ScopedAStatus StreamCommonImpl::setVendorParameters( const std::vector& in_parameters, bool in_async) { LOG(DEBUG) << __func__ << ": parameters count " << in_parameters.size() << ", async: " << in_async; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::addEffect( +ndk::ScopedAStatus StreamCommonImpl::addEffect( const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) { if (in_effect == nullptr) { LOG(DEBUG) << __func__ << ": null effect"; @@ -631,8 +625,7 @@ ndk::ScopedAStatus StreamCommonImpl::addEffect( return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::removeEffect( +ndk::ScopedAStatus StreamCommonImpl::removeEffect( const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) { if (in_effect == nullptr) { LOG(DEBUG) << __func__ << ": null effect"; @@ -642,8 +635,7 @@ ndk::ScopedAStatus StreamCommonImpl::removeEffect( return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::close() { +ndk::ScopedAStatus StreamCommonImpl::close() { LOG(DEBUG) << __func__; if (!isClosed()) { stopWorker(); @@ -659,8 +651,7 @@ ndk::ScopedAStatus StreamCommonImpl::close() { } } -template -ndk::ScopedAStatus StreamCommonImpl::prepareToClose() { +ndk::ScopedAStatus StreamCommonImpl::prepareToClose() { LOG(DEBUG) << __func__; if (!isClosed()) { return ndk::ScopedAStatus::ok(); @@ -669,8 +660,7 @@ ndk::ScopedAStatus StreamCommonImpl::prepareToClose() { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } -template -void StreamCommonImpl::stopWorker() { +void StreamCommonImpl::stopWorker() { if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) { LOG(DEBUG) << __func__ << ": asking the worker to exit..."; auto cmd = StreamDescriptor::Command::make( @@ -686,10 +676,12 @@ void StreamCommonImpl::stopWorker() { } } -template -ndk::ScopedAStatus StreamCommonImpl::updateMetadata(const Metadata& metadata) { +ndk::ScopedAStatus StreamCommonImpl::updateMetadataCommon(const Metadata& metadata) { LOG(DEBUG) << __func__; if (!isClosed()) { + if (metadata.index() != mMetadata.index()) { + LOG(FATAL) << __func__ << ": changing metadata variant is not allowed"; + } mMetadata = metadata; return ndk::ScopedAStatus::ok(); } @@ -697,12 +689,10 @@ ndk::ScopedAStatus StreamCommonImpl::updateMetadata(const Metadata& me return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } -// static -ndk::ScopedAStatus StreamIn::initInstance(const std::shared_ptr& stream) { - if (auto status = stream->init(); !status.isOk()) { - return status; - } - stream->createStreamCommon(stream); +ndk::ScopedAStatus StreamCommonImpl::setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { + mWorker->setIsConnected(!devices.empty()); + mConnectedDevices = devices; return ndk::ScopedAStatus::ok(); } @@ -716,12 +706,8 @@ static std::map transformMicrophones( } } // namespace -StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext&& context, - const DriverInterface::CreateInstance& createDriver, - const StreamWorkerInterface::CreateInstance& createWorker, - const std::vector& microphones) - : StreamCommonImpl(sinkMetadata, std::move(context), createDriver, createWorker), - mMicrophones(transformMicrophones(microphones)) { +StreamIn::StreamIn(const std::vector& microphones) + : mMicrophones(transformMicrophones(microphones)) { LOG(DEBUG) << __func__; } @@ -729,9 +715,9 @@ ndk::ScopedAStatus StreamIn::getActiveMicrophones( std::vector* _aidl_return) { std::vector result; std::vector channelMapping{ - getChannelCount(mContext.getChannelLayout()), + getChannelCount(getContext().getChannelLayout()), MicrophoneDynamicInfo::ChannelMapping::DIRECT}; - for (auto it = mConnectedDevices.begin(); it != mConnectedDevices.end(); ++it) { + for (auto it = getConnectedDevices().begin(); it != getConnectedDevices().end(); ++it) { if (auto micIt = mMicrophones.find(*it); micIt != mMicrophones.end()) { MicrophoneDynamicInfo dynMic; dynMic.id = micIt->second; @@ -777,22 +763,8 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector& in_channelGains return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -// static -ndk::ScopedAStatus StreamOut::initInstance(const std::shared_ptr& stream) { - if (auto status = stream->init(); !status.isOk()) { - return status; - } - stream->createStreamCommon(stream); - return ndk::ScopedAStatus::ok(); -} - -StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext&& context, - const DriverInterface::CreateInstance& createDriver, - const StreamWorkerInterface::CreateInstance& createWorker, - const std::optional& offloadInfo) - : StreamCommonImpl(sourceMetadata, std::move(context), createDriver, - createWorker), - mOffloadInfo(offloadInfo) { +StreamOut::StreamOut(const std::optional& offloadInfo) + : mOffloadInfo(offloadInfo) { LOG(DEBUG) << __func__; } diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/StreamStub.cpp index 2467320f0c..289afa1c85 100644 --- a/audio/aidl/default/StreamStub.cpp +++ b/audio/aidl/default/StreamStub.cpp @@ -31,33 +31,34 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -DriverStub::DriverStub(const StreamContext& context, bool isInput) - : mFrameSizeBytes(context.getFrameSize()), +StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context) + : StreamCommonImpl(metadata, std::move(context)), + mFrameSizeBytes(context.getFrameSize()), mSampleRate(context.getSampleRate()), mIsAsynchronous(!!context.getAsyncCallback()), - mIsInput(isInput) {} + mIsInput(isInput(metadata)) {} -::android::status_t DriverStub::init() { +::android::status_t StreamStub::init() { usleep(500); return ::android::OK; } -::android::status_t DriverStub::drain(StreamDescriptor::DrainMode) { +::android::status_t StreamStub::drain(StreamDescriptor::DrainMode) { usleep(500); return ::android::OK; } -::android::status_t DriverStub::flush() { +::android::status_t StreamStub::flush() { usleep(500); return ::android::OK; } -::android::status_t DriverStub::pause() { +::android::status_t StreamStub::pause() { usleep(500); return ::android::OK; } -::android::status_t DriverStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, +::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { static constexpr float kMicrosPerSecond = MICROS_PER_SECOND; static constexpr float kScaleFactor = .8f; @@ -79,16 +80,12 @@ DriverStub::DriverStub(const StreamContext& context, bool isInput) return ::android::OK; } -::android::status_t DriverStub::standby() { +::android::status_t StreamStub::standby() { usleep(500); return ::android::OK; } -::android::status_t DriverStub::setConnectedDevices( - const std::vector& connectedDevices __unused) { - usleep(500); - return ::android::OK; -} +void StreamStub::shutdown() {} // static ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata, @@ -97,7 +94,7 @@ ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata std::shared_ptr* result) { std::shared_ptr stream = ndk::SharedRefBase::make(sinkMetadata, std::move(context), microphones); - if (auto status = initInstance(stream); !status.isOk()) { + if (auto status = stream->initInstance(stream); !status.isOk()) { return status; } *result = std::move(stream); @@ -106,16 +103,7 @@ ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector& microphones) - : StreamIn( - sinkMetadata, std::move(context), - [](const StreamContext& ctx) -> DriverInterface* { - return new DriverStub(ctx, true /*isInput*/); - }, - [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* { - // The default worker implementation is used. - return new StreamInWorker(ctx, driver); - }, - microphones) {} + : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {} // static ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMetadata, @@ -124,7 +112,7 @@ ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMet std::shared_ptr* result) { std::shared_ptr stream = ndk::SharedRefBase::make( sourceMetadata, std::move(context), offloadInfo); - if (auto status = initInstance(stream); !status.isOk()) { + if (auto status = stream->initInstance(stream); !status.isOk()) { return status; } *result = std::move(stream); @@ -133,15 +121,6 @@ ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMet StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional& offloadInfo) - : StreamOut( - sourceMetadata, std::move(context), - [](const StreamContext& ctx) -> DriverInterface* { - return new DriverStub(ctx, false /*isInput*/); - }, - [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* { - // The default worker implementation is used. - return new StreamOutWorker(ctx, driver); - }, - offloadInfo) {} + : StreamStub(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {} } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 826b0f1ec9..ff5b5a0ab1 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -164,8 +164,8 @@ class StreamContext { DebugParameters mDebugParameters; }; +// This interface provides operations of the stream which are executed on the worker thread. struct DriverInterface { - using CreateInstance = std::function; virtual ~DriverInterface() = default; // All the methods below are called on the worker thread. virtual ::android::status_t init() = 0; // This function is only called once. @@ -175,11 +175,7 @@ struct DriverInterface { virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) = 0; virtual ::android::status_t standby() = 0; - // The method below is called from a thread of the Binder pool. Access to data shared with other - // methods of this interface must be done in a thread-safe manner. - virtual ::android::status_t setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& - connectedDevices) = 0; + virtual void shutdown() = 0; // This function is only called once. }; class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic { @@ -296,14 +292,20 @@ class StreamOutWorkerLogic : public StreamWorkerCommonLogic { }; using StreamOutWorker = StreamWorkerImpl; -// This provides a C++ interface with methods of the IStreamCommon Binder interface, -// but intentionally does not inherit from it. This is needed to avoid inheriting -// StreamIn and StreamOut from two Binder interface classes, as these parts of the class -// will be reference counted separately. -// -// The implementation of these common methods is in the StreamCommonImpl template class. +// This interface provides operations of the stream which are executed on a Binder pool thread. +// These methods originate both from the AIDL interface and its implementation. struct StreamCommonInterface { + using ConnectedDevices = std::vector<::aidl::android::media::audio::common::AudioDevice>; + using Metadata = + std::variant<::aidl::android::hardware::audio::common::SinkMetadata /*IStreamIn*/, + ::aidl::android::hardware::audio::common::SourceMetadata /*IStreamOut*/>; + + static constexpr bool isInput(const Metadata& metadata) { return metadata.index() == 0; } + virtual ~StreamCommonInterface() = default; + // Methods below originate from the 'IStreamCommon' interface. + // This is semantically equivalent to inheriting from 'IStreamCommon' with a benefit + // that concrete stream implementations can inherit both from this interface and IStreamIn/Out. virtual ndk::ScopedAStatus close() = 0; virtual ndk::ScopedAStatus prepareToClose() = 0; virtual ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) = 0; @@ -317,11 +319,30 @@ struct StreamCommonInterface { virtual ndk::ScopedAStatus removeEffect( const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) = 0; + // Methods below are common for both 'IStreamIn' and 'IStreamOut'. Note that + // 'updateMetadata' in them uses an individual structure which is wrapped here. + // The 'Common' suffix is added to distinguish them from the methods from 'IStreamIn/Out'. + virtual ndk::ScopedAStatus getStreamCommonCommon( + std::shared_ptr* _aidl_return) = 0; + virtual ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) = 0; + // Methods below are called by implementation of 'IModule', 'IStreamIn' and 'IStreamOut'. + virtual ndk::ScopedAStatus initInstance( + const std::shared_ptr& delegate) = 0; + virtual const StreamContext& getContext() const = 0; + virtual bool isClosed() const = 0; + virtual const ConnectedDevices& getConnectedDevices() const = 0; + virtual ndk::ScopedAStatus setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0; }; -class StreamCommon : public BnStreamCommon { +// This is equivalent to automatically generated 'IStreamCommonDelegator' but uses +// a weak pointer to avoid creating a reference loop. The loop will occur because +// 'IStreamIn/Out.getStreamCommon' must return the same instance every time, thus +// the stream implementation must hold a strong pointer to an instance of 'IStreamCommon'. +// Also, we use 'StreamCommonInterface' here instead of 'IStreamCommon'. +class StreamCommonDelegator : public BnStreamCommon { public: - explicit StreamCommon(const std::shared_ptr& delegate) + explicit StreamCommonDelegator(const std::shared_ptr& delegate) : mDelegate(delegate) {} private: @@ -372,9 +393,20 @@ class StreamCommon : public BnStreamCommon { std::weak_ptr mDelegate; }; -template -class StreamCommonImpl : public StreamCommonInterface { +// The implementation of DriverInterface must be provided by each concrete stream implementation. +class StreamCommonImpl : virtual public StreamCommonInterface, virtual public DriverInterface { public: + StreamCommonImpl(const Metadata& metadata, StreamContext&& context, + const StreamWorkerInterface::CreateInstance& createWorker) + : mMetadata(metadata), + mContext(std::move(context)), + mWorker(createWorker(mContext, this)) {} + StreamCommonImpl(const Metadata& metadata, StreamContext&& context) + : StreamCommonImpl( + metadata, std::move(context), + isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {} + ~StreamCommonImpl(); + ndk::ScopedAStatus close() override; ndk::ScopedAStatus prepareToClose() override; ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override; @@ -389,46 +421,50 @@ class StreamCommonImpl : public StreamCommonInterface { const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) override; - ndk::ScopedAStatus getStreamCommon(std::shared_ptr* _aidl_return); - ndk::ScopedAStatus init() { - return mWorker->start() ? ndk::ScopedAStatus::ok() - : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - bool isClosed() const { return mWorker->isClosed(); } + ndk::ScopedAStatus getStreamCommonCommon(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override; + + ndk::ScopedAStatus initInstance( + const std::shared_ptr& delegate) override; + const StreamContext& getContext() const override { return mContext; } + bool isClosed() const override { return mWorker->isClosed(); } + const ConnectedDevices& getConnectedDevices() const override { return mConnectedDevices; } ndk::ScopedAStatus setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { - mWorker->setIsConnected(!devices.empty()); - mConnectedDevices = devices; - return ndk::ScopedAStatus::fromStatus(mDriver->setConnectedDevices(devices)); - } - ndk::ScopedAStatus updateMetadata(const Metadata& metadata); + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; protected: - StreamCommonImpl(const Metadata& metadata, StreamContext&& context, - const DriverInterface::CreateInstance& createDriver, - const StreamWorkerInterface::CreateInstance& createWorker) - : mMetadata(metadata), - mContext(std::move(context)), - mDriver(createDriver(mContext)), - mWorker(createWorker(mContext, mDriver.get())) {} - ~StreamCommonImpl(); - void stopWorker(); - void createStreamCommon(const std::shared_ptr& delegate); + static StreamWorkerInterface::CreateInstance getDefaultInWorkerCreator() { + return [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* { + return new StreamInWorker(ctx, driver); + }; + } + static StreamWorkerInterface::CreateInstance getDefaultOutWorkerCreator() { + return [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* { + return new StreamOutWorker(ctx, driver); + }; + } + + void stopWorker(); - std::shared_ptr mCommon; - ndk::SpAIBinder mCommonBinder; Metadata mMetadata; StreamContext mContext; - std::unique_ptr mDriver; std::unique_ptr mWorker; - std::vector<::aidl::android::media::audio::common::AudioDevice> mConnectedDevices; + std::shared_ptr mCommon; + ndk::SpAIBinder mCommonBinder; + ConnectedDevices mConnectedDevices; }; -class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>, - public BnStreamIn { +// Note: 'StreamIn/Out' can not be used on their own. Instead, they must be used for defining +// concrete input/output stream implementations. +class StreamIn : virtual public StreamCommonInterface, public BnStreamIn { + protected: ndk::ScopedAStatus getStreamCommon(std::shared_ptr* _aidl_return) override { - return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>:: - getStreamCommon(_aidl_return); + return getStreamCommonCommon(_aidl_return); + } + ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata& + in_sinkMetadata) override { + return updateMetadataCommon(in_sinkMetadata); } ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) @@ -437,27 +473,13 @@ class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::commo ndk::ScopedAStatus setMicrophoneDirection(MicrophoneDirection in_direction) override; ndk::ScopedAStatus getMicrophoneFieldDimension(float* _aidl_return) override; ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override; - ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata& - in_sinkMetadata) override { - return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>:: - updateMetadata(in_sinkMetadata); - } ndk::ScopedAStatus getHwGain(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwGain(const std::vector& in_channelGains) override; - protected: friend class ndk::SharedRefBase; - static ndk::ScopedAStatus initInstance(const std::shared_ptr& stream); - - StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, - StreamContext&& context, const DriverInterface::CreateInstance& createDriver, - const StreamWorkerInterface::CreateInstance& createWorker, - const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); - void createStreamCommon(const std::shared_ptr& myPtr) { - StreamCommonImpl< - ::aidl::android::hardware::audio::common::SinkMetadata>::createStreamCommon(myPtr); - } + explicit StreamIn( + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones; @@ -469,17 +491,15 @@ class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::commo std::shared_ptr* result)>; }; -class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>, - public BnStreamOut { +class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { + protected: ndk::ScopedAStatus getStreamCommon(std::shared_ptr* _aidl_return) override { - return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>:: - getStreamCommon(_aidl_return); + return getStreamCommonCommon(_aidl_return); } ndk::ScopedAStatus updateMetadata( const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata) override { - return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>:: - updateMetadata(in_sourceMetadata); + return updateMetadataCommon(in_sourceMetadata); } ndk::ScopedAStatus updateOffloadMetadata( const ::aidl::android::hardware::audio::common::AudioOffloadMetadata& @@ -504,21 +524,10 @@ class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::comm override; ndk::ScopedAStatus selectPresentation(int32_t in_presentationId, int32_t in_programId) override; - void createStreamCommon(const std::shared_ptr& myPtr) { - StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>:: - createStreamCommon(myPtr); - } - - protected: friend class ndk::SharedRefBase; - static ndk::ScopedAStatus initInstance(const std::shared_ptr& stream); - - StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, - StreamContext&& context, const DriverInterface::CreateInstance& createDriver, - const StreamWorkerInterface::CreateInstance& createWorker, - const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& - offloadInfo); + explicit StreamOut(const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo); std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo; std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata; @@ -540,26 +549,18 @@ class StreamWrapper { : mStream(streamOut), mStreamBinder(streamOut->asBinder()) {} ndk::SpAIBinder getBinder() const { return mStreamBinder; } bool isStreamOpen() const { - return std::visit( - [](auto&& ws) -> bool { - auto s = ws.lock(); - return s && !s->isClosed(); - }, - mStream); + auto s = mStream.lock(); + return s && !s->isClosed(); } ndk::ScopedAStatus setConnectedDevices( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { - return std::visit( - [&](auto&& ws) { - auto s = ws.lock(); - if (s) return s->setConnectedDevices(devices); - return ndk::ScopedAStatus::ok(); - }, - mStream); + auto s = mStream.lock(); + if (s) return s->setConnectedDevices(devices); + return ndk::ScopedAStatus::ok(); } private: - std::variant, std::weak_ptr> mStream; + std::weak_ptr mStream; ndk::SpAIBinder mStreamBinder; }; diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index 436e610ccf..def98b7986 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -20,9 +20,10 @@ namespace aidl::android::hardware::audio::core { -class DriverStub : public DriverInterface { +class StreamStub : public StreamCommonImpl { public: - DriverStub(const StreamContext& context, bool isInput); + StreamStub(const Metadata& metadata, StreamContext&& context); + // Methods of 'DriverInterface'. ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; @@ -30,10 +31,7 @@ class DriverStub : public DriverInterface { ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; ::android::status_t standby() override; - // Note: called on a different thread. - ::android::status_t setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices) - override; + void shutdown() override; private: const size_t mFrameSizeBytes; @@ -42,7 +40,7 @@ class DriverStub : public DriverInterface { const bool mIsInput; }; -class StreamInStub final : public StreamIn { +class StreamInStub final : public StreamStub, public StreamIn { public: static ndk::ScopedAStatus createInstance( const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, @@ -58,7 +56,7 @@ class StreamInStub final : public StreamIn { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); }; -class StreamOutStub final : public StreamOut { +class StreamOutStub final : public StreamStub, public StreamOut { public: static ndk::ScopedAStatus createInstance( const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 05d889a713..24ea8be51c 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -30,9 +30,10 @@ extern "C" { namespace aidl::android::hardware::audio::core { -class DriverUsb : public DriverInterface { +class StreamUsb : public StreamCommonImpl { public: - DriverUsb(const StreamContext& context, bool isInput); + StreamUsb(const Metadata& metadata, StreamContext&& context); + // Methods of 'DriverInterface'. ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; @@ -40,27 +41,25 @@ class DriverUsb : public DriverInterface { ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; ::android::status_t standby() override; - // Note: called on a different thread. - ::android::status_t setConnectedDevices( - const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices) - override; + void shutdown() override; + + // Overridden methods of 'StreamCommonImpl', called on a Binder thread. + const ConnectedDevices& getConnectedDevices() const override; + ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override; private: ::android::status_t exitStandby(); - std::mutex mLock; + mutable std::mutex mLock; const size_t mFrameSizeBytes; std::optional mConfig; const bool mIsInput; - // Cached device addresses for connected devices. - std::vector<::aidl::android::media::audio::common::AudioDeviceAddress> mConnectedDevices - GUARDED_BY(mLock); std::vector> mAlsaDeviceProxies GUARDED_BY(mLock); bool mIsStandby = true; }; -class StreamInUsb final : public StreamIn { +class StreamInUsb final : public StreamUsb, public StreamIn { ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; @@ -80,7 +79,7 @@ class StreamInUsb final : public StreamIn { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); }; -class StreamOutUsb final : public StreamOut { +class StreamOutUsb final : public StreamUsb, public StreamOut { public: static ndk::ScopedAStatus createInstance( const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index d2ee484c2d..fcac5dfc49 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "UsbAlsaMixerControl.h" #include "UsbAlsaUtils.h" @@ -42,10 +43,12 @@ using android::status_t; namespace aidl::android::hardware::audio::core { -DriverUsb::DriverUsb(const StreamContext& context, bool isInput) - : mFrameSizeBytes(context.getFrameSize()), mIsInput(isInput) { +StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context) + : StreamCommonImpl(metadata, std::move(context)), + mFrameSizeBytes(context.getFrameSize()), + mIsInput(isInput(metadata)) { struct pcm_config config; - config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput); + config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), mIsInput); if (config.channels == 0) { LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString(); return; @@ -63,48 +66,50 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput) mConfig = config; } -::android::status_t DriverUsb::init() { +::android::status_t StreamUsb::init() { return mConfig.has_value() ? ::android::OK : ::android::NO_INIT; } -::android::status_t DriverUsb::setConnectedDevices( +const StreamCommonInterface::ConnectedDevices& StreamUsb::getConnectedDevices() const { + std::lock_guard guard(mLock); + return mConnectedDevices; +} + +ndk::ScopedAStatus StreamUsb::setConnectedDevices( const std::vector& connectedDevices) { if (mIsInput && connectedDevices.size() > 1) { LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size() << ") for input stream"; - return ::android::INVALID_OPERATION; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } for (const auto& connectedDevice : connectedDevices) { if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) { LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString(); - return ::android::BAD_VALUE; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } } std::lock_guard guard(mLock); mAlsaDeviceProxies.clear(); - mConnectedDevices.clear(); - for (const auto& connectedDevice : connectedDevices) { - mConnectedDevices.push_back(connectedDevice.address); - } - return ::android::OK; + RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices)); + return ndk::ScopedAStatus::ok(); } -::android::status_t DriverUsb::drain(StreamDescriptor::DrainMode) { +::android::status_t StreamUsb::drain(StreamDescriptor::DrainMode) { usleep(1000); return ::android::OK; } -::android::status_t DriverUsb::flush() { +::android::status_t StreamUsb::flush() { usleep(1000); return ::android::OK; } -::android::status_t DriverUsb::pause() { +::android::status_t StreamUsb::pause() { usleep(1000); return ::android::OK; } -::android::status_t DriverUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, +::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { { std::lock_guard guard(mLock); @@ -139,7 +144,7 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput) return ::android::OK; } -::android::status_t DriverUsb::standby() { +::android::status_t StreamUsb::standby() { if (!mIsStandby) { std::lock_guard guard(mLock); mAlsaDeviceProxies.clear(); @@ -148,11 +153,15 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput) return ::android::OK; } -::android::status_t DriverUsb::exitStandby() { +void StreamUsb::shutdown() {} + +::android::status_t StreamUsb::exitStandby() { std::vector connectedDevices; { std::lock_guard guard(mLock); - connectedDevices = mConnectedDevices; + std::transform(mConnectedDevices.begin(), mConnectedDevices.end(), + std::back_inserter(connectedDevices), + [](const auto& device) { return device.address; }); } std::vector> alsaDeviceProxies; for (const auto& device : connectedDevices) { @@ -203,7 +212,7 @@ ndk::ScopedAStatus StreamInUsb::createInstance(const SinkMetadata& sinkMetadata, std::shared_ptr* result) { std::shared_ptr stream = ndk::SharedRefBase::make(sinkMetadata, std::move(context), microphones); - if (auto status = initInstance(stream); !status.isOk()) { + if (auto status = stream->initInstance(stream); !status.isOk()) { return status; } *result = std::move(stream); @@ -212,16 +221,7 @@ ndk::ScopedAStatus StreamInUsb::createInstance(const SinkMetadata& sinkMetadata, StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector& microphones) - : StreamIn( - sinkMetadata, std::move(context), - [](const StreamContext& ctx) -> DriverInterface* { - return new DriverUsb(ctx, true /*isInput*/); - }, - [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* { - // The default worker implementation is used. - return new StreamInWorker(ctx, driver); - }, - microphones) {} + : StreamUsb(sinkMetadata, std::move(context)), StreamIn(microphones) {} ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( std::vector* _aidl_return __unused) { @@ -240,7 +240,7 @@ ndk::ScopedAStatus StreamOutUsb::createInstance(const SourceMetadata& sourceMeta } std::shared_ptr stream = ndk::SharedRefBase::make(sourceMetadata, std::move(context), offloadInfo); - if (auto status = initInstance(stream); !status.isOk()) { + if (auto status = stream->initInstance(stream); !status.isOk()) { return status; } *result = std::move(stream); @@ -249,17 +249,8 @@ ndk::ScopedAStatus StreamOutUsb::createInstance(const SourceMetadata& sourceMeta StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional& offloadInfo) - : StreamOut( - sourceMetadata, std::move(context), - [](const StreamContext& ctx) -> DriverInterface* { - return new DriverUsb(ctx, false /*isInput*/); - }, - [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* { - // The default worker implementation is used. - return new StreamOutWorker(ctx, driver); - }, - offloadInfo) { - mChannelCount = getChannelCount(mContext.getChannelLayout()); + : StreamUsb(sourceMetadata, std::move(context)), StreamOut(offloadInfo) { + mChannelCount = getChannelCount(getContext().getChannelLayout()); } ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { @@ -268,7 +259,7 @@ ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { } ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector& in_channelVolumes) { - for (const auto& device : mConnectedDevices) { + for (const auto& device : getConnectedDevices()) { if (device.address.getTag() != AudioDeviceAddress::alsa) { LOG(DEBUG) << __func__ << ": skip as the device address is not alsa"; continue; From 73b06adb9aa00043e9e0013ff3a6b4f8a3ed16ca Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 26 Jun 2023 17:21:04 -0700 Subject: [PATCH 024/152] audio: Allow Module subclasses to customize stream creation Since specializations of the 'Module' class likely need to provide their own specializations for streams, provide virtual methods for them. Bug: 282568751 Test: atest VtsHalAudioCoreTargetTest Merged-In: Iddb1bff9f11bc867aba61897ea2f8b9bc3c27544 Change-Id: Iddb1bff9f11bc867aba61897ea2f8b9bc3c27544 (cherry picked from commit 9d16a6ac106f9c43200825232a7db797c8ef6e4f) --- audio/aidl/default/Module.cpp | 49 ++++++++----------- audio/aidl/default/StreamStub.cpp | 28 ----------- audio/aidl/default/include/core-impl/Module.h | 17 +++++-- .../default/include/core-impl/ModuleUsb.h | 11 +++++ audio/aidl/default/include/core-impl/Stream.h | 29 ++++++----- .../default/include/core-impl/StreamStub.h | 15 ------ .../default/include/core-impl/StreamUsb.h | 25 +++------- audio/aidl/default/usb/ModuleUsb.cpp | 24 +++++++++ audio/aidl/default/usb/StreamUsb.cpp | 32 ------------ 9 files changed, 88 insertions(+), 142 deletions(-) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index c0c6c4889d..6f89d4bc11 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -30,7 +30,6 @@ #include "core-impl/ModuleUsb.h" #include "core-impl/SoundDose.h" #include "core-impl/StreamStub.h" -#include "core-impl/StreamUsb.h" #include "core-impl/Telephony.h" #include "core-impl/utils.h" @@ -119,30 +118,6 @@ std::shared_ptr Module::createInstance(Type type) { } } -// static -StreamIn::CreateInstance Module::getStreamInCreator(Type type) { - switch (type) { - case Type::USB: - return StreamInUsb::createInstance; - case Type::DEFAULT: - case Type::R_SUBMIX: - default: - return StreamInStub::createInstance; - } -} - -// static -StreamOut::CreateInstance Module::getStreamOutCreator(Type type) { - switch (type) { - case Type::USB: - return StreamOutUsb::createInstance; - case Type::DEFAULT: - case Type::R_SUBMIX: - default: - return StreamOutStub::createInstance; - } -} - std::ostream& operator<<(std::ostream& os, Module::Type t) { switch (t) { case Module::Type::DEFAULT: @@ -687,8 +662,8 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar nullptr, nullptr, &context)); context.fillDescriptor(&_aidl_return->desc); std::shared_ptr stream; - RETURN_STATUS_IF_ERROR(getStreamInCreator(mType)(in_args.sinkMetadata, std::move(context), - mConfig->microphones, &stream)); + RETURN_STATUS_IF_ERROR(createInputStream(in_args.sinkMetadata, std::move(context), + mConfig->microphones, &stream)); StreamWrapper streamWrapper(stream); if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) { RETURN_STATUS_IF_ERROR( @@ -733,8 +708,8 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_ in_args.eventCallback, &context)); context.fillDescriptor(&_aidl_return->desc); std::shared_ptr stream; - RETURN_STATUS_IF_ERROR(getStreamOutCreator(mType)(in_args.sourceMetadata, std::move(context), - in_args.offloadInfo, &stream)); + RETURN_STATUS_IF_ERROR(createOutputStream(in_args.sourceMetadata, std::move(context), + in_args.offloadInfo, &stream)); StreamWrapper streamWrapper(stream); if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) { RETURN_STATUS_IF_ERROR( @@ -1346,6 +1321,22 @@ bool Module::isMmapSupported() { return mIsMmapSupported.value(); } +ndk::ScopedAStatus Module::createInputStream(const SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector& microphones, + std::shared_ptr* result) { + return createStreamInstance(result, sinkMetadata, std::move(context), + microphones); +} + +ndk::ScopedAStatus Module::createOutputStream(const SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional& offloadInfo, + std::shared_ptr* result) { + return createStreamInstance(result, sourceMetadata, std::move(context), + offloadInfo); +} + ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) { LOG(VERBOSE) << __func__ << ": do nothing and return ok"; return ndk::ScopedAStatus::ok(); diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/StreamStub.cpp index 289afa1c85..d88dfbc3c2 100644 --- a/audio/aidl/default/StreamStub.cpp +++ b/audio/aidl/default/StreamStub.cpp @@ -87,38 +87,10 @@ StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context) void StreamStub::shutdown() {} -// static -ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata, - StreamContext&& context, - const std::vector& microphones, - std::shared_ptr* result) { - std::shared_ptr stream = - ndk::SharedRefBase::make(sinkMetadata, std::move(context), microphones); - if (auto status = stream->initInstance(stream); !status.isOk()) { - return status; - } - *result = std::move(stream); - return ndk::ScopedAStatus::ok(); -} - StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector& microphones) : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {} -// static -ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMetadata, - StreamContext&& context, - const std::optional& offloadInfo, - std::shared_ptr* result) { - std::shared_ptr stream = ndk::SharedRefBase::make( - sourceMetadata, std::move(context), offloadInfo); - if (auto status = stream->initInstance(stream); !status.isOk()) { - return status; - } - *result = std::move(stream); - return ndk::ScopedAStatus::ok(); -} - StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional& offloadInfo) : StreamStub(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {} diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index 212cfd9570..4a23637d86 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -33,11 +33,9 @@ class Module : public BnModule { static constexpr int32_t kLatencyMs = 10; enum Type : int { DEFAULT, R_SUBMIX, USB }; - explicit Module(Type type) : mType(type) {} - static std::shared_ptr createInstance(Type type); - static StreamIn::CreateInstance getStreamInCreator(Type type); - static StreamOut::CreateInstance getStreamOutCreator(Type type); + + explicit Module(Type type) : mType(type) {} protected: // The vendor extension done via inheritance can override interface methods and augment @@ -182,6 +180,17 @@ class Module : public BnModule { protected: // The following virtual functions are intended for vendor extension via inheritance. + virtual ndk::ScopedAStatus createInputStream( + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, + std::shared_ptr* result); + virtual ndk::ScopedAStatus createOutputStream( + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo, + std::shared_ptr* result); // If the module is unable to populate the connected device port correctly, the returned error // code must correspond to the errors of `IModule.connectedExternalDevice` method. virtual ndk::ScopedAStatus populateConnectedDevicePort( diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h index 1aa22445b4..5a5429db64 100644 --- a/audio/aidl/default/include/core-impl/ModuleUsb.h +++ b/audio/aidl/default/include/core-impl/ModuleUsb.h @@ -32,6 +32,17 @@ class ModuleUsb : public Module { ndk::ScopedAStatus setMicMute(bool in_mute) override; // Module interfaces + ndk::ScopedAStatus createInputStream( + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, + std::shared_ptr* result) override; + ndk::ScopedAStatus createOutputStream( + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo, + std::shared_ptr* result) override; ndk::ScopedAStatus populateConnectedDevicePort( ::aidl::android::media::audio::common::AudioPort* audioPort) override; ndk::ScopedAStatus checkAudioPatchEndpointsMatch( diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index ff5b5a0ab1..c20a4213ed 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -482,13 +484,6 @@ class StreamIn : virtual public StreamCommonInterface, public BnStreamIn { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones; - - public: - using CreateInstance = std::function& microphones, - std::shared_ptr* result)>; }; class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { @@ -531,16 +526,20 @@ class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo; std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata; - - public: - using CreateInstance = std::function& - offloadInfo, - std::shared_ptr* result)>; }; +// The recommended way to create a stream instance. +// 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or +// 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'. +template +ndk::ScopedAStatus createStreamInstance(std::shared_ptr* result, Args&&... args) { + std::shared_ptr stream = + ::ndk::SharedRefBase::make(std::forward(args)...); + RETURN_STATUS_IF_ERROR(stream->initInstance(stream)); + *result = std::move(stream); + return ndk::ScopedAStatus::ok(); +} + class StreamWrapper { public: explicit StreamWrapper(const std::shared_ptr& streamIn) diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index def98b7986..c8900f3223 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -42,13 +42,6 @@ class StreamStub : public StreamCommonImpl { class StreamInStub final : public StreamStub, public StreamIn { public: - static ndk::ScopedAStatus createInstance( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, - StreamContext&& context, - const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, - std::shared_ptr* result); - - private: friend class ndk::SharedRefBase; StreamInStub( const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, @@ -58,14 +51,6 @@ class StreamInStub final : public StreamStub, public StreamIn { class StreamOutStub final : public StreamStub, public StreamOut { public: - static ndk::ScopedAStatus createInstance( - const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, - StreamContext&& context, - const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& - offloadInfo, - std::shared_ptr* result); - - private: friend class ndk::SharedRefBase; StreamOutStub(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 24ea8be51c..5e55cd8cb8 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -60,41 +60,28 @@ class StreamUsb : public StreamCommonImpl { }; class StreamInUsb final : public StreamUsb, public StreamIn { - ndk::ScopedAStatus getActiveMicrophones( - std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) - override; - public: - static ndk::ScopedAStatus createInstance( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, - StreamContext&& context, - const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, - std::shared_ptr* result); - - private: friend class ndk::SharedRefBase; StreamInUsb( const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + + private: + ndk::ScopedAStatus getActiveMicrophones( + std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) + override; }; class StreamOutUsb final : public StreamUsb, public StreamOut { public: - static ndk::ScopedAStatus createInstance( - const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, - StreamContext&& context, - const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& - offloadInfo, - std::shared_ptr* result); - - private: friend class ndk::SharedRefBase; StreamOutUsb(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo); + private: ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp index 627f854dac..9d3f21d505 100644 --- a/audio/aidl/default/usb/ModuleUsb.cpp +++ b/audio/aidl/default/usb/ModuleUsb.cpp @@ -25,22 +25,27 @@ #include "UsbAlsaMixerControl.h" #include "UsbAlsaUtils.h" #include "core-impl/ModuleUsb.h" +#include "core-impl/StreamUsb.h" extern "C" { #include "alsa_device_profile.h" } using aidl::android::hardware::audio::common::isUsbInputDeviceType; +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; using aidl::android::media::audio::common::AudioChannelLayout; using aidl::android::media::audio::common::AudioDeviceAddress; using aidl::android::media::audio::common::AudioDeviceDescription; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; +using aidl::android::media::audio::common::AudioOffloadInfo; using aidl::android::media::audio::common::AudioPort; using aidl::android::media::audio::common::AudioPortConfig; using aidl::android::media::audio::common::AudioPortExt; using aidl::android::media::audio::common::AudioProfile; +using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { @@ -97,6 +102,25 @@ ndk::ScopedAStatus ModuleUsb::setMicMute(bool in_mute __unused) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } +ndk::ScopedAStatus ModuleUsb::createInputStream(const SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector& microphones, + std::shared_ptr* result) { + return createStreamInstance(result, sinkMetadata, std::move(context), microphones); +} + +ndk::ScopedAStatus ModuleUsb::createOutputStream(const SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional& offloadInfo, + std::shared_ptr* result) { + if (offloadInfo.has_value()) { + LOG(ERROR) << __func__ << ": offload is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + return createStreamInstance(result, sourceMetadata, std::move(context), + offloadInfo); +} + ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) { if (audioPort->ext.getTag() != AudioPortExt::Tag::device) { LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a device port"; diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index fcac5dfc49..49bc1d67a0 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -205,20 +205,6 @@ void StreamUsb::shutdown() {} return ::android::OK; } -// static -ndk::ScopedAStatus StreamInUsb::createInstance(const SinkMetadata& sinkMetadata, - StreamContext&& context, - const std::vector& microphones, - std::shared_ptr* result) { - std::shared_ptr stream = - ndk::SharedRefBase::make(sinkMetadata, std::move(context), microphones); - if (auto status = stream->initInstance(stream); !status.isOk()) { - return status; - } - *result = std::move(stream); - return ndk::ScopedAStatus::ok(); -} - StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector& microphones) : StreamUsb(sinkMetadata, std::move(context)), StreamIn(microphones) {} @@ -229,24 +215,6 @@ ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -// static -ndk::ScopedAStatus StreamOutUsb::createInstance(const SourceMetadata& sourceMetadata, - StreamContext&& context, - const std::optional& offloadInfo, - std::shared_ptr* result) { - if (offloadInfo.has_value()) { - LOG(ERROR) << __func__ << ": offload is not supported"; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - std::shared_ptr stream = - ndk::SharedRefBase::make(sourceMetadata, std::move(context), offloadInfo); - if (auto status = stream->initInstance(stream); !status.isOk()) { - return status; - } - *result = std::move(stream); - return ndk::ScopedAStatus::ok(); -} - StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional& offloadInfo) : StreamUsb(sourceMetadata, std::move(context)), StreamOut(offloadInfo) { From 54bbf07e061ccd2c50254856a52514b960b541f9 Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Thu, 18 May 2023 17:48:27 +0900 Subject: [PATCH 025/152] Add TV devices that have MdnsOffloadManagerService to APF exempt list For Panel TV devices, the vendor can implemented TV specific mDNS offload instead of APF in U. If TV specific mDNS offload is implemented. MdnsOffloadManagerService will exist in the system ext partition. The APF vts will be skipped if MdnsOffloadManagerService exist. Bug: 283038712 Test: atest VtsHalWifiStaIfaceTargetTest Change-Id: If55ec42507460b9a2c6eee683d85b8109f2af236 --- .../functional/wifi_sta_iface_aidl_test.cpp | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp index f12d873f0c..1ea1237a2d 100644 --- a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp +++ b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include @@ -68,6 +69,50 @@ class WifiStaIfaceAidlTest : public testing::TestWithParam { std::shared_ptr wifi_sta_iface_; + // Checks if the MdnsOffloadManagerService is installed. + bool isMdnsOffloadServicePresent() { + int status = + // --query-flags MATCH_SYSTEM_ONLY(1048576) will only return matched service + // installed on system or system_ext partition. The MdnsOffloadManagerService should + // be installed on system_ext partition. + // NOLINTNEXTLINE(cert-env33-c) + system("pm query-services --query-flags 1048576" + " com.android.tv.mdnsoffloadmanager/" + "com.android.tv.mdnsoffloadmanager.MdnsOffloadManagerService" + " | egrep -q mdnsoffloadmanager"); + return status == 0; + } + + // Detected panel TV device by using ro.oem.key1 property. + // https://docs.partner.android.com/tv/build/platform/props-vars/ro-oem-key1 + bool isPanelTvDevice() { + const std::string oem_key1 = getPropertyString("ro.oem.key1"); + if (oem_key1.size() < 9) { + return false; + } + if (oem_key1.substr(0, 3) != "ATV") { + return false; + } + const std::string psz_string = oem_key1.substr(6, 3); + // If PSZ string contains non digit, then it is not a panel TV device. + for (char ch : psz_string) { + if (!isdigit(ch)) { + return false; + } + } + // If PSZ is "000", then it is not a panel TV device. + if (psz_string == "000") { + return false; + } + return true; + } + + std::string getPropertyString(const char* property_name) { + char property_string_raw_bytes[PROPERTY_VALUE_MAX] = {}; + int len = property_get(property_name, property_string_raw_bytes, ""); + return std::string(property_string_raw_bytes, len); + } + private: const char* getInstanceName() { return GetParam().c_str(); } }; @@ -99,6 +144,11 @@ TEST_P(WifiStaIfaceAidlTest, GetFeatureSet) { */ // @VsrTest = 5.3.12 TEST_P(WifiStaIfaceAidlTest, CheckApfIsSupported) { + // Flat panel TV devices that support MDNS offload do not have to implement APF if the WiFi + // chipset does not have sufficient RAM to do so. + if (isPanelTvDevice() && isMdnsOffloadServicePresent()) { + GTEST_SKIP() << "Panel TV supports mDNS offload. It is not required to support APF"; + } int vendor_api_level = property_get_int32("ro.vendor.api_level", 0); // Before VSR 14, APF support is optional. if (vendor_api_level < __ANDROID_API_U__) { From 437516ea3a4f8484dba96594ba1161d8ff804b91 Mon Sep 17 00:00:00 2001 From: Jeff Pu Date: Wed, 28 Jun 2023 15:21:21 +0000 Subject: [PATCH 026/152] Inform framework of lockout right when the failed attempts reaches threshold Bug: b/277780293 Test: atest FakeLockoutTrackerTest Change-Id: Iefe88f3ab492773844b18c525ddbf37218227256 --- .../aidl/default/FakeFingerprintEngine.cpp | 26 ++++++++++++------- .../aidl/default/FakeLockoutTracker.cpp | 8 ++++-- .../default/include/FakeFingerprintEngine.h | 1 + .../tests/FakeFingerprintEngineTest.cpp | 4 +-- .../default/tests/FakeLockoutTrackerTest.cpp | 4 +-- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp index b496a6abbe..5f5455af61 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp @@ -195,16 +195,7 @@ void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, } // got lockout? - FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode(); - if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) { - LOG(ERROR) << "Fail: lockout permanent"; - cb->onLockoutPermanent(); - return; - } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) { - int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft(); - LOG(ERROR) << "Fail: lockout timed " << timeLeft; - cb->onLockoutTimed(timeLeft); - } + if (checkSensorLockout(cb)) return; int i = 0; do { @@ -256,6 +247,7 @@ void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, LOG(ERROR) << "Fail: fingerprint not enrolled"; cb->onAuthenticationFailed(); mLockoutTracker.addFailedAttempt(); + checkSensorLockout(cb); } } @@ -563,4 +555,18 @@ int32_t FakeFingerprintEngine::getRandomInRange(int32_t bound1, int32_t bound2) return dist(mRandom); } +bool FakeFingerprintEngine::checkSensorLockout(ISessionCallback* cb) { + FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode(); + if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) { + LOG(ERROR) << "Fail: lockout permanent"; + cb->onLockoutPermanent(); + return true; + } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) { + int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft(); + LOG(ERROR) << "Fail: lockout timed " << timeLeft; + cb->onLockoutTimed(timeLeft); + return true; + } + return false; +} } // namespace aidl::android::hardware::biometrics::fingerprint diff --git a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp index 5996406fd0..b0163ee246 100644 --- a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp +++ b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp @@ -67,9 +67,13 @@ int64_t FakeLockoutTracker::getLockoutTimeLeft() { int64_t res = 0; if (mLockoutTimedStart > 0) { + int32_t lockoutTimedDuration = + FingerprintHalProperties::lockout_timed_duration().value_or(10 * 100); auto now = Util::getSystemNanoTime(); - auto left = now - mLockoutTimedStart; - res = (left > 0) ? (left / 1000000LL) : 0; + auto elapsed = (now - mLockoutTimedStart) / 1000000LL; + res = lockoutTimedDuration - elapsed; + LOG(INFO) << "xxxxxx: elapsed=" << elapsed << " now = " << now + << " mLockoutTimedStart=" << mLockoutTimedStart << " res=" << res; } return res; diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h index f9d02a72fa..8ac7a955e4 100644 --- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h +++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h @@ -113,6 +113,7 @@ class FakeFingerprintEngine { bool parseEnrollmentCaptureSingle(const std::string& str, std::vector>& res); int32_t getRandomInRange(int32_t bound1, int32_t bound2); + bool checkSensorLockout(ISessionCallback*); FakeLockoutTracker mLockoutTracker; }; diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp index c34f5d7c15..86207a5c7d 100644 --- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp +++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp @@ -375,9 +375,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectAcquired) { TEST_F(FakeFingerprintEngineTest, EnumerateEnrolled) { FingerprintHalProperties::enrollments({2, 4, 8}); mEngine.enumerateEnrollmentsImpl(mCallback.get()); - ASSERT_EQ( - 4, - mCallback->mLastEnrollmentEnumerated.size()); // Due to workaround. TODO (b/243129174) + ASSERT_EQ(3, mCallback->mLastEnrollmentEnumerated.size()); for (auto id : FingerprintHalProperties::enrollments()) { ASSERT_TRUE(std::find(mCallback->mLastEnrollmentEnumerated.begin(), mCallback->mLastEnrollmentEnumerated.end(), diff --git a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp index 1b071eecd2..93c6f844ed 100644 --- a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp +++ b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp @@ -65,11 +65,11 @@ TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) { ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed); // time left int N = 5; - int64_t prevTimeLeft = INT_MIN; + int64_t prevTimeLeft = INT_MAX; for (int i = 0; i < N; i++) { SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1); int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft(); - ASSERT_TRUE(currTimeLeft > prevTimeLeft); + ASSERT_TRUE(currTimeLeft < prevTimeLeft); prevTimeLeft = currTimeLeft; } ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone); From 251499ca9572eb421215654e8079943b83b1f7c9 Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Mon, 5 Jun 2023 15:24:38 +0000 Subject: [PATCH 027/152] Support to get EC public key from the UdsCertchain. Bug: 285896470 Test: VtsHalRemotelyProvisionedComponentTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:a18883a58cc9f6b702095bb17bbd0e4e894be49c) Merged-In: I7f829b1346feeab0fd429ad7b9714181b6668b34 Change-Id: I7f829b1346feeab0fd429ad7b9714181b6668b34 --- .../keymint/support/remote_prov_utils.cpp | 75 ++++++++++++++++--- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp index 3cb783cf0a..c9c3e4d4ae 100644 --- a/security/keymint/support/remote_prov_utils.cpp +++ b/security/keymint/support/remote_prov_utils.cpp @@ -115,6 +115,36 @@ ErrMsgOr> getAffineCoordinates(const bytevec& pubKe return std::make_tuple(std::move(pubX), std::move(pubY)); } +ErrMsgOr getRawPublicKey(const EVP_PKEY_Ptr& pubKey) { + if (pubKey.get() == nullptr) { + return "pkey is null."; + } + int keyType = EVP_PKEY_base_id(pubKey.get()); + switch (keyType) { + case EVP_PKEY_EC: { + auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pubKey.get())); + if (ecKey.get() == nullptr) { + return "Failed to get ec key"; + } + return ecKeyGetPublicKey(ecKey.get()); + } + case EVP_PKEY_ED25519: { + bytevec rawPubKey; + size_t rawKeySize = 0; + if (!EVP_PKEY_get_raw_public_key(pubKey.get(), NULL, &rawKeySize)) { + return "Failed to get raw public key."; + } + rawPubKey.resize(rawKeySize); + if (!EVP_PKEY_get_raw_public_key(pubKey.get(), rawPubKey.data(), &rawKeySize)) { + return "Failed to get raw public key."; + } + return rawPubKey; + } + default: + return "Unknown key type."; + } +} + ErrMsgOr> generateEc256KeyPair() { auto ec_key = EC_KEY_Ptr(EC_KEY_new()); if (ec_key.get() == nullptr) { @@ -706,11 +736,10 @@ std::string getX509SubjectName(const X509_Ptr& cert) { // Validates the certificate chain and returns the leaf public key. ErrMsgOr validateCertChain(const cppbor::Array& chain) { - uint8_t rawPubKey[64]; - size_t rawPubKeySize = sizeof(rawPubKey); + bytevec rawPubKey; for (size_t i = 0; i < chain.size(); ++i) { // Root must be self-signed. - size_t signingCertIndex = (i > 1) ? i - 1 : i; + size_t signingCertIndex = (i > 0) ? i - 1 : i; auto& keyCertItem = chain[i]; auto& signingCertItem = chain[signingCertIndex]; if (!keyCertItem || !keyCertItem->asBstr()) { @@ -724,7 +753,7 @@ ErrMsgOr validateCertChain(const cppbor::Array& chain) { if (!keyCert) { return keyCert.message(); } - auto signingCert = parseX509Cert(keyCertItem->asBstr()->value()); + auto signingCert = parseX509Cert(signingCertItem->asBstr()->value()); if (!signingCert) { return signingCert.message(); } @@ -749,17 +778,16 @@ ErrMsgOr validateCertChain(const cppbor::Array& chain) { return "Certificate " + std::to_string(i) + " has wrong issuer. Signer subject is " + signerSubj + " Issuer subject is " + certIssuer; } - - rawPubKeySize = sizeof(rawPubKey); - if (!EVP_PKEY_get_raw_public_key(pubKey.get(), rawPubKey, &rawPubKeySize)) { - return "Failed to get raw public key."; + if (i == chain.size() - 1) { + auto key = getRawPublicKey(pubKey); + if (!key) key.moveMessage(); + rawPubKey = key.moveValue(); } } - - return bytevec(rawPubKey, rawPubKey + rawPubKeySize); + return rawPubKey; } -std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsPub) { +std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsCoseKeyBytes) { for (const auto& [signerName, udsCertChain] : udsCerts) { if (!signerName || !signerName->asTstr()) { return "Signer Name must be a Tstr."; @@ -775,8 +803,31 @@ std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsPub) if (!leafPubKey) { return leafPubKey.message(); } + auto coseKey = CoseKey::parse(udsCoseKeyBytes); + if (!coseKey) return coseKey.moveMessage(); + + auto curve = coseKey->getIntValue(CoseKey::CURVE); + if (!curve) { + return "CoseKey must contain curve."; + } + bytevec udsPub; + if (curve == CoseKeyCurve::P256 || curve == CoseKeyCurve::P384) { + auto pubKey = coseKey->getEcPublicKey(); + if (!pubKey) return pubKey.moveMessage(); + // convert public key to uncompressed form by prepending 0x04 at begin. + pubKey->insert(pubKey->begin(), 0x04); + udsPub = pubKey.moveValue(); + } else if (curve == CoseKeyCurve::ED25519) { + auto& pubkey = coseKey->getMap().get(cppcose::CoseKey::PUBKEY_X); + if (!pubkey || !pubkey->asBstr()) { + return "Invalid public key."; + } + udsPub = pubkey->asBstr()->value(); + } else { + return "Unknown curve."; + } if (*leafPubKey != udsPub) { - return "Leaf public key in UDS certificat chain doesn't match UDS public key."; + return "Leaf public key in UDS certificate chain doesn't match UDS public key."; } } return ""; From 9d1d8b732727602e7643abde4e09473472798f4a Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Fri, 28 Apr 2023 23:37:02 +0000 Subject: [PATCH 028/152] Strongbox may not support 1024 bit key size for RSA. Strongbox may not support 1024 bit key size for RSA. So in NoUserConfirmation test updated the key size to 2048 so that the test works for both TEE and Strongbox. Bug: 280117495 Test: run VtsAidlKeyMintTarget (cherry picked from https://android-review.googlesource.com/q/commit:ce2bebdd79cf7536b06c2d67cdee8867475a3b10) Merged-In: I32bb28001aca9b69eedb1bd3d0bcff43052d06e4 Change-Id: I32bb28001aca9b69eedb1bd3d0bcff43052d06e4 --- security/keymint/aidl/vts/functional/KeyMintTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp index e99149bf17..bdec4d3fb4 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -3119,7 +3119,7 @@ TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) { */ TEST_P(SigningOperationsTest, NoUserConfirmation) { ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(1024, 65537) + .RsaSigningKey(2048, 65537) .Digest(Digest::NONE) .Padding(PaddingMode::NONE) .Authorization(TAG_NO_AUTH_REQUIRED) From 263e36209101faa1c2f5bb02f944aee2b3153712 Mon Sep 17 00:00:00 2001 From: Austin Borger Date: Thu, 15 Jun 2023 11:32:04 -0700 Subject: [PATCH 029/152] Camera VTS: Properly initialize Stream in various places useCase and colorSpace are not explicitly initialized. colorSpace must be explicitly initialized to UNSPECIFIED, as its default value is not zero. Without initialization, the HAL will receive incorrect Stream data. Bug: 287305593 Test: Ran full VTS test on Cuttlefish / OEM testing. Change-Id: I6a29600b5dc06ebdc61b38e0585204fe52d590c2 --- .../VtsAidlHalCameraProvider_TargetTest.cpp | 5 + camera/provider/aidl/vts/camera_aidl_test.cpp | 104 ++++++++++-------- camera/provider/aidl/vts/camera_aidl_test.h | 38 +++---- 3 files changed, 82 insertions(+), 65 deletions(-) diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp index aee53664b0..2845180727 100644 --- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp +++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp @@ -551,6 +551,11 @@ TEST_P(CameraAidlTest, configureStreamsAvailableOutputs) { stream.rotation = StreamRotation::ROTATION_0; stream.dynamicRangeProfile = RequestAvailableDynamicRangeProfilesMap:: ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD; + stream.useCase = ScalerAvailableStreamUseCases:: + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT; + stream.colorSpace = static_cast( + RequestAvailableColorSpaceProfilesMap:: + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED); std::vector streams = {stream}; StreamConfiguration config; diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp index 7665f797c1..08ad0bbaa0 100644 --- a/camera/provider/aidl/vts/camera_aidl_test.cpp +++ b/camera/provider/aidl/vts/camera_aidl_test.cpp @@ -45,8 +45,6 @@ using ::aidl::android::hardware::camera::common::TorchModeStatus; using ::aidl::android::hardware::camera::device::CameraMetadata; using ::aidl::android::hardware::camera::device::ICameraDevice; using ::aidl::android::hardware::camera::metadata::CameraMetadataTag; -using ::aidl::android::hardware::camera::metadata::RequestAvailableColorSpaceProfilesMap; -using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap; using ::aidl::android::hardware::camera::metadata::SensorInfoColorFilterArrangement; using ::aidl::android::hardware::camera::metadata::SensorPixelMode; using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback; @@ -2237,21 +2235,26 @@ void CameraAidlTest::configureStreamUseCaseInternal(const AvailableStream &thres } std::vector streams(1); - streams[0] = {0, - StreamType::OUTPUT, - outputPreviewStreams[0].width, - outputPreviewStreams[0].height, - static_cast(outputPreviewStreams[0].format), - static_cast<::aidl::android::hardware::graphics::common::BufferUsage>( - GRALLOC1_CONSUMER_USAGE_CPU_READ), - Dataspace::UNKNOWN, - StreamRotation::ROTATION_0, - std::string(), - 0, - -1, - {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, - RequestAvailableDynamicRangeProfilesMap:: - ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD}; + streams[0] = { + 0, + StreamType::OUTPUT, + outputPreviewStreams[0].width, + outputPreviewStreams[0].height, + static_cast(outputPreviewStreams[0].format), + static_cast<::aidl::android::hardware::graphics::common::BufferUsage>( + GRALLOC1_CONSUMER_USAGE_CPU_READ), + Dataspace::UNKNOWN, + StreamRotation::ROTATION_0, + std::string(), + 0, + -1, + {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, + RequestAvailableDynamicRangeProfilesMap:: + ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD, + ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT, + static_cast( + RequestAvailableColorSpaceProfilesMap:: + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)}; int32_t streamConfigCounter = 0; CameraMetadata req; @@ -2395,7 +2398,11 @@ void CameraAidlTest::configureSingleStream( /*groupId*/ -1, {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, RequestAvailableDynamicRangeProfilesMap:: - ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD}; + ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD, + ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT, + static_cast( + RequestAvailableColorSpaceProfilesMap:: + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)}; StreamConfiguration config; config.streams = streams; @@ -2726,21 +2733,26 @@ void CameraAidlTest::configurePreviewStreams( std::vector streams(physicalIds.size()); int32_t streamId = 0; for (auto const& physicalId : physicalIds) { - streams[streamId] = {streamId, - StreamType::OUTPUT, - outputPreviewStreams[0].width, - outputPreviewStreams[0].height, - static_cast(outputPreviewStreams[0].format), - static_cast( - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER), - Dataspace::UNKNOWN, - StreamRotation::ROTATION_0, - physicalId, - 0, - -1, - {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, - RequestAvailableDynamicRangeProfilesMap:: - ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD}; + streams[streamId] = { + streamId, + StreamType::OUTPUT, + outputPreviewStreams[0].width, + outputPreviewStreams[0].height, + static_cast(outputPreviewStreams[0].format), + static_cast( + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER), + Dataspace::UNKNOWN, + StreamRotation::ROTATION_0, + physicalId, + 0, + -1, + {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, + RequestAvailableDynamicRangeProfilesMap:: + ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD, + ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT, + static_cast( + RequestAvailableColorSpaceProfilesMap:: + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)}; streamId++; } @@ -2799,7 +2811,8 @@ void CameraAidlTest::configureStreams(const std::string& name, bool* supportsPartialResults, int32_t* partialResultCount, bool* useHalBufManager, std::shared_ptr* outCb, uint32_t streamConfigCounter, bool maxResolution, - RequestAvailableDynamicRangeProfilesMap prof) { + RequestAvailableDynamicRangeProfilesMap dynamicRangeProf, + RequestAvailableColorSpaceProfilesMap colorSpaceProf) { ASSERT_NE(nullptr, session); ASSERT_NE(nullptr, halStreams); ASSERT_NE(nullptr, previewStream); @@ -2881,7 +2894,9 @@ void CameraAidlTest::configureStreams(const std::string& name, -1, {maxResolution ? SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION : SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, - prof}; + dynamicRangeProf, + ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT, + static_cast(colorSpaceProf)}; StreamConfiguration config; config.streams = streams; @@ -3332,7 +3347,11 @@ void CameraAidlTest::configureOfflineStillStream( /*groupId*/ 0, {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, RequestAvailableDynamicRangeProfilesMap:: - ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD}; + ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD, + ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT, + static_cast( + RequestAvailableColorSpaceProfilesMap:: + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)}; StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE, CameraMetadata()}; @@ -3447,15 +3466,12 @@ void CameraAidlTest::processColorSpaceRequest( Stream previewStream; std::shared_ptr cb; - previewStream.usage = - static_cast( - GRALLOC1_CONSUMER_USAGE_HWCOMPOSER); - previewStream.dataSpace = getDataspace(PixelFormat::IMPLEMENTATION_DEFINED); - previewStream.colorSpace = static_cast(colorSpace); + previewStream.usage = static_cast( + GRALLOC1_CONSUMER_USAGE_HWCOMPOSER); configureStreams(name, mProvider, PixelFormat::IMPLEMENTATION_DEFINED, &mSession, - &previewStream, &halStreams, &supportsPartialResults, - &partialResultCount, &useHalBufManager, &cb, 0, - /*maxResolution*/ false, dynamicRangeProfile); + &previewStream, &halStreams, &supportsPartialResults, &partialResultCount, + &useHalBufManager, &cb, 0, + /*maxResolution*/ false, dynamicRangeProfile, colorSpace); ASSERT_NE(mSession, nullptr); ::aidl::android::hardware::common::fmq::MQDescriptor< diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h index 588cb503b9..6f8f380fa4 100644 --- a/camera/provider/aidl/vts/camera_aidl_test.h +++ b/camera/provider/aidl/vts/camera_aidl_test.h @@ -77,6 +77,9 @@ using ::aidl::android::hardware::camera::device::StreamBuffer; using ::aidl::android::hardware::camera::device::StreamBufferRet; using ::aidl::android::hardware::camera::device::StreamConfiguration; using ::aidl::android::hardware::camera::device::StreamConfigurationMode; +using ::aidl::android::hardware::camera::metadata::RequestAvailableColorSpaceProfilesMap; +using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap; +using ::aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases; using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination; using ::aidl::android::hardware::camera::provider::ICameraProvider; @@ -205,10 +208,12 @@ class CameraAidlTest : public ::testing::TestWithParam { bool* supportsPartialResults /*out*/, int32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/, std::shared_ptr* outCb /*out*/, uint32_t streamConfigCounter, bool maxResolution, - aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap - prof = ::aidl::android::hardware::camera::metadata:: - RequestAvailableDynamicRangeProfilesMap:: - ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD); + RequestAvailableDynamicRangeProfilesMap dynamicRangeProf = + RequestAvailableDynamicRangeProfilesMap:: + ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD, + RequestAvailableColorSpaceProfilesMap colorSpaceProf = + RequestAvailableColorSpaceProfilesMap:: + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED); void configurePreviewStreams( const std::string& name, const std::shared_ptr& provider, @@ -376,8 +381,7 @@ class CameraAidlTest : public ::testing::TestWithParam { static void get10BitDynamicRangeProfiles( const camera_metadata_t* staticMeta, - std::vector* profiles); + std::vector* profiles); static bool reportsColorSpaces(const camera_metadata_t* staticMeta); @@ -387,17 +391,13 @@ class CameraAidlTest : public ::testing::TestWithParam { RequestAvailableColorSpaceProfilesMap>* profiles); static bool isColorSpaceCompatibleWithDynamicRangeAndPixelFormat( - const camera_metadata_t* staticMeta, - aidl::android::hardware::camera::metadata:: - RequestAvailableColorSpaceProfilesMap colorSpace, - aidl::android::hardware::camera::metadata:: + const camera_metadata_t* staticMeta, RequestAvailableColorSpaceProfilesMap colorSpace, RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile, aidl::android::hardware::graphics::common::PixelFormat pixelFormat); - static const char* getColorSpaceProfileString(aidl::android::hardware::camera::metadata:: - RequestAvailableColorSpaceProfilesMap colorSpace); + static const char* getColorSpaceProfileString(RequestAvailableColorSpaceProfilesMap colorSpace); - static const char* getDynamicRangeProfileString(aidl::android::hardware::camera::metadata:: + static const char* getDynamicRangeProfileString( RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile); static int32_t halFormatToPublicFormat( @@ -408,10 +408,8 @@ class CameraAidlTest : public ::testing::TestWithParam { static Size getMinSize(Size a, Size b); - void processColorSpaceRequest(aidl::android::hardware::camera::metadata:: - RequestAvailableColorSpaceProfilesMap colorSpace, - aidl::android::hardware::camera::metadata:: - RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile); + void processColorSpaceRequest(RequestAvailableColorSpaceProfilesMap colorSpace, + RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile); void processZoomSettingsOverrideRequests( int32_t frameCount, const bool *overrideSequence, const bool *expectedResults); @@ -571,10 +569,8 @@ class CameraAidlTest : public ::testing::TestWithParam { static bool matchDeviceName(const std::string& deviceName, const std::string& providerType, std::string* deviceVersion, std::string* cameraId); - static void verify10BitMetadata( - HandleImporter& importer, const InFlightRequest& request, - aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap - profile); + static void verify10BitMetadata(HandleImporter& importer, const InFlightRequest& request, + RequestAvailableDynamicRangeProfilesMap profile); static void waitForReleaseFence( std::vector& resultOutputBuffers); From 4559d0fd394027709f52e07848dd1ebe3843215f Mon Sep 17 00:00:00 2001 From: Jaideep Sharma Date: Wed, 14 Jun 2023 19:14:44 +0530 Subject: [PATCH 030/152] aidl: Improve Effect VTS naming Use uuid in hexadecimal format in testcase name. Bug: 287430121 Test: atest VtsHalAudioEffectTargetTest Change-Id: Ib687b6617060e4400a767f23ca0b26cece4005f1 Merged-In: Ib687b6617060e4400a767f23ca0b26cece4005f1 --- audio/aidl/vts/EffectHelper.h | 11 ++++++++++- audio/aidl/vts/VtsHalAECTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalAGC1TargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalAGC2TargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp | 9 +++++++-- audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp | 5 +---- audio/aidl/vts/VtsHalBassBoostTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalDownmixTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp | 4 +--- .../aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalEqualizerTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalNSTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalVisualizerTargetTest.cpp | 4 +--- audio/aidl/vts/VtsHalVolumeTargetTest.cpp | 4 +--- 18 files changed, 33 insertions(+), 52 deletions(-) diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h index 4e84f6bc7b..a1353f5bbd 100644 --- a/audio/aidl/vts/EffectHelper.h +++ b/audio/aidl/vts/EffectHelper.h @@ -32,12 +32,14 @@ #include #include #include +#include #include "AudioHalBinderServiceUtil.h" #include "EffectFactoryHelper.h" #include "TestUtils.h" using namespace android; +using ::android::audio::utils::toString; using aidl::android::hardware::audio::effect::CommandId; using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::IEffect; @@ -63,6 +65,13 @@ typedef ::android::AidlMessageQueue DataMQ; +static inline std::string getPrefix(Descriptor &descriptor) { + std::string prefix = "Implementor_" + descriptor.common.implementor + "_name_" + + descriptor.common.name + "_UUID_" + + toString(descriptor.common.id.uuid); + return prefix; +} + class EffectHelper { public: static void create(std::shared_ptr factory, std::shared_ptr& effect, @@ -71,7 +80,7 @@ class EffectHelper { auto& id = desc.common.id; ASSERT_STATUS(status, factory->createEffect(id.uuid, &effect)); if (status == EX_NONE) { - ASSERT_NE(effect, nullptr) << id.uuid.toString(); + ASSERT_NE(effect, nullptr) << toString(id.uuid); } } diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp index 8828c41bbe..4f658f227b 100644 --- a/audio/aidl/vts/VtsHalAECTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp @@ -162,9 +162,7 @@ INSTANTIATE_TEST_SUITE_P( auto descriptor = std::get(info.param).second; std::string echoDelay = std::to_string(std::get(info.param)); std::string mobileMode = std::get(info.param) ? "true" : "false"; - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_EchoDelay_" + echoDelay + + std::string name = getPrefix(descriptor) + "_EchoDelay_" + echoDelay + "_MobileMode_" + mobileMode; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); diff --git a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp index edfcdf6fce..cc00763399 100644 --- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp +++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp @@ -177,9 +177,7 @@ INSTANTIATE_TEST_SUITE_P( std::to_string(std::get(info.param)); std::string enableLimiter = std::to_string(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_target_peak_level_" + + std::string name = getPrefix(descriptor) + "_target_peak_level_" + targetPeakLevel + "_max_compression_gain_" + maxCompressionGain + "_enable_limiter_" + enableLimiter; std::replace_if( diff --git a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp index 8ba8e45566..46a569ef92 100644 --- a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp +++ b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp @@ -183,9 +183,7 @@ INSTANTIATE_TEST_SUITE_P( std::string margin = std::to_string(static_cast(std::get(info.param))); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_digital_gain_" + gain + + std::string name = getPrefix(descriptor) + "_digital_gain_" + gain + "_level_estimator_" + estimator + "_margin_" + margin; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp index 9cd6c22c7c..8084a594e0 100644 --- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp @@ -36,6 +36,11 @@ #include "EffectFactoryHelper.h" #include "TestUtils.h" +#include + +using namespace android; +using ::android::audio::utils::toString; + using namespace android; using aidl::android::hardware::audio::effect::Descriptor; @@ -93,7 +98,7 @@ class EffectFactoryTest : public testing::TestWithParam { std::shared_ptr effect; EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(uuid, &effect)); if (expectStatus == EX_NONE) { - EXPECT_NE(effect, nullptr) << " null effect with uuid: " << uuid.toString(); + EXPECT_NE(effect, nullptr) << " null effect with uuid: " << toString(uuid); effects.push_back(std::move(effect)); } } @@ -148,7 +153,7 @@ TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) { } std::string msg = " missing type UUID:\n"; for (const auto& uuid : typeUuidSet) { - msg += (uuid.toString() + "\n"); + msg += (toString(uuid) + "\n"); } SCOPED_TRACE(msg); EXPECT_EQ(0UL, typeUuidSet.size()); diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp index 436f2a3164..4ad9b2ddae 100644 --- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp @@ -848,10 +848,7 @@ INSTANTIATE_TEST_SUITE_P( EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))), [](const testing::TestParamInfo& info) { auto descriptor = std::get(info.param).second; - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_TYPE_" + - descriptor.common.id.type.toString() + "_UUID_" + - descriptor.common.id.uuid.toString(); + std::string name = getPrefix(descriptor); std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp index 9cfdc50a2c..afddb841ee 100644 --- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp +++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp @@ -145,9 +145,7 @@ INSTANTIATE_TEST_SUITE_P( [](const testing::TestParamInfo& info) { auto descriptor = std::get(info.param).second; std::string strength = std::to_string(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_strength_" + strength; + std::string name = getPrefix(descriptor) + "_strength_" + strength; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp index 5aeebde1a0..7a2f31bfe5 100644 --- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp +++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp @@ -126,9 +126,7 @@ INSTANTIATE_TEST_SUITE_P( [](const testing::TestParamInfo& info) { auto descriptor = std::get(info.param).second; std::string type = std::to_string(static_cast(std::get(info.param))); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_type" + type; + std::string name = getPrefix(descriptor) + "_type" + type; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp index 033e3b5f3f..5509c76eb9 100644 --- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp +++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp @@ -513,9 +513,7 @@ INSTANTIATE_TEST_SUITE_P( auto descriptor = std::get(info.param).second; DynamicsProcessing::EngineArchitecture cfg; fillEngineArchConfig(cfg, info.param); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_Cfg_" + cfg.toString(); + std::string name = getPrefix(descriptor) + "_Cfg_" + cfg.toString(); std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp index 05c2c5b5e6..f2ef185950 100644 --- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp +++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp @@ -209,9 +209,7 @@ INSTANTIATE_TEST_SUITE_P( auto descriptor = std::get<0>(info.param).second; std::string roomLevel = std::to_string(std::get<1>(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_roomLevel" + roomLevel; + std::string name = getPrefix(descriptor) + "_roomLevel" + roomLevel; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp index 716a2c67b5..37e7c0a0ff 100644 --- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp +++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp @@ -209,9 +209,7 @@ INSTANTIATE_TEST_SUITE_P( auto descriptor = std::get(info.param).second; std::string bandLevel = ::android::internal::ToString(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_preset_" + + std::string name = getPrefix(descriptor) + "_preset_" + std::to_string(std::get(info.param)) + "_bandLevel_" + bandLevel; std::replace_if( diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp index 7c79d1bfab..d417e86110 100644 --- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp +++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp @@ -195,9 +195,7 @@ INSTANTIATE_TEST_SUITE_P( std::to_string(std::get(info.param)); std::string maxAmplitude = std::to_string(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_hapticScaleId" + + std::string name = getPrefix(descriptor) + "_hapticScaleId" + hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale + "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor + "_maxAmplitude" + maxAmplitude; diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp index 96b048ed18..cbb80a9101 100644 --- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp +++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp @@ -131,9 +131,7 @@ INSTANTIATE_TEST_SUITE_P( [](const testing::TestParamInfo& info) { auto descriptor = std::get(info.param).second; std::string gainMb = std::to_string(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_gainMb_" + gainMb; + std::string name = getPrefix(descriptor) + "_gainMb_" + gainMb; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp index 5525c80894..7c8b2e58cc 100644 --- a/audio/aidl/vts/VtsHalNSTargetTest.cpp +++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp @@ -155,9 +155,7 @@ INSTANTIATE_TEST_SUITE_P( std::get(info.param)); std::string type = aidl::android::hardware::audio::effect::toString( std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_level_" + level + "_type_" + + std::string name = getPrefix(descriptor) + "_level_" + level + "_type_" + type; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp index 8fb4ebf339..3056c6c1cc 100644 --- a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp +++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp @@ -137,9 +137,7 @@ INSTANTIATE_TEST_SUITE_P( auto descriptor = std::get(info.param).second; std::string preset = std::to_string(static_cast(std::get(info.param))); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_preset" + preset; + std::string name = getPrefix(descriptor) + "_preset" + preset; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp index 6b1da6388e..07a9fa4e70 100644 --- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp +++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp @@ -141,9 +141,7 @@ INSTANTIATE_TEST_SUITE_P( [](const testing::TestParamInfo& info) { auto descriptor = std::get(info.param).second; std::string strength = std::to_string(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_strength" + strength; + std::string name = getPrefix(descriptor) + "_strength" + strength; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp index f41ba30b12..903ba696be 100644 --- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp +++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp @@ -195,9 +195,7 @@ INSTANTIATE_TEST_SUITE_P( std::get(info.param)); std::string latency = std::to_string(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_captureSize" + captureSize + + std::string name = getPrefix(descriptor) + "_captureSize" + captureSize + "_scalingMode" + scalingMode + "_measurementMode" + measurementMode + "_latency" + latency; std::replace_if( diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp index 90b7f37946..9193a360ff 100644 --- a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp +++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp @@ -149,9 +149,7 @@ INSTANTIATE_TEST_SUITE_P( auto descriptor = std::get(info.param).second; std::string level = std::to_string(std::get(info.param)); std::string mute = std::to_string(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - descriptor.common.id.uuid.toString() + "_level" + level + "_mute" + + std::string name = getPrefix(descriptor) + "_level" + level + "_mute" + mute; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); From 21cc1371a9f5aba852c3e78aff92d1050ab906fd Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Fri, 23 Jun 2023 04:34:50 +0000 Subject: [PATCH 031/152] Format VTS test code Bug: 287430121 Test: atest VtsHalAudioEffectTargetTest Change-Id: Iecc0c9388c6596cf5a25918f8f0af0495b2133a6 Merged-In: Iecc0c9388c6596cf5a25918f8f0af0495b2133a6 --- audio/aidl/vts/EffectHelper.h | 9 ++++----- audio/aidl/vts/VtsHalAECTargetTest.cpp | 4 ++-- audio/aidl/vts/VtsHalAGC1TargetTest.cpp | 6 +++--- audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp | 8 ++++---- audio/aidl/vts/VtsHalNSTargetTest.cpp | 3 +-- audio/aidl/vts/VtsHalVolumeTargetTest.cpp | 3 +-- 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h index a1353f5bbd..685d07d191 100644 --- a/audio/aidl/vts/EffectHelper.h +++ b/audio/aidl/vts/EffectHelper.h @@ -30,16 +30,15 @@ #include #include #include +#include #include #include -#include #include "AudioHalBinderServiceUtil.h" #include "EffectFactoryHelper.h" #include "TestUtils.h" using namespace android; -using ::android::audio::utils::toString; using aidl::android::hardware::audio::effect::CommandId; using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::IEffect; @@ -53,6 +52,7 @@ using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; using aidl::android::media::audio::common::AudioUuid; using aidl::android::media::audio::common::PcmType; +using ::android::audio::utils::toString; using ::android::hardware::EventFlag; const AudioFormatDescription kDefaultFormatDescription = { @@ -65,10 +65,9 @@ typedef ::android::AidlMessageQueue DataMQ; -static inline std::string getPrefix(Descriptor &descriptor) { +static inline std::string getPrefix(Descriptor& descriptor) { std::string prefix = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - toString(descriptor.common.id.uuid); + descriptor.common.name + "_UUID_" + toString(descriptor.common.id.uuid); return prefix; } diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp index 4f658f227b..1a7c3d4446 100644 --- a/audio/aidl/vts/VtsHalAECTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp @@ -162,8 +162,8 @@ INSTANTIATE_TEST_SUITE_P( auto descriptor = std::get(info.param).second; std::string echoDelay = std::to_string(std::get(info.param)); std::string mobileMode = std::get(info.param) ? "true" : "false"; - std::string name = getPrefix(descriptor) + "_EchoDelay_" + echoDelay + - "_MobileMode_" + mobileMode; + std::string name = + getPrefix(descriptor) + "_EchoDelay_" + echoDelay + "_MobileMode_" + mobileMode; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp index cc00763399..65c6a8f5fa 100644 --- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp +++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp @@ -177,9 +177,9 @@ INSTANTIATE_TEST_SUITE_P( std::to_string(std::get(info.param)); std::string enableLimiter = std::to_string(std::get(info.param)); - std::string name = getPrefix(descriptor) + "_target_peak_level_" + - targetPeakLevel + "_max_compression_gain_" + maxCompressionGain + - "_enable_limiter_" + enableLimiter; + std::string name = getPrefix(descriptor) + "_target_peak_level_" + targetPeakLevel + + "_max_compression_gain_" + maxCompressionGain + "_enable_limiter_" + + enableLimiter; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp index d417e86110..54caed920e 100644 --- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp +++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp @@ -195,10 +195,10 @@ INSTANTIATE_TEST_SUITE_P( std::to_string(std::get(info.param)); std::string maxAmplitude = std::to_string(std::get(info.param)); - std::string name = getPrefix(descriptor) + "_hapticScaleId" + - hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale + - "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor + - "_maxAmplitude" + maxAmplitude; + std::string name = getPrefix(descriptor) + "_hapticScaleId" + hapticScaleID + + "_hapticScaleVibScale" + hapticScaleVibScale + "_resonantFrequency" + + resonantFrequency + "_qFactor" + qFactor + "_maxAmplitude" + + maxAmplitude; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp index 7c8b2e58cc..bbb11fc278 100644 --- a/audio/aidl/vts/VtsHalNSTargetTest.cpp +++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp @@ -155,8 +155,7 @@ INSTANTIATE_TEST_SUITE_P( std::get(info.param)); std::string type = aidl::android::hardware::audio::effect::toString( std::get(info.param)); - std::string name = getPrefix(descriptor) + "_level_" + level + "_type_" + - type; + std::string name = getPrefix(descriptor) + "_level_" + level + "_type_" + type; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp index 9193a360ff..0b5b9fc3dc 100644 --- a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp +++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp @@ -149,8 +149,7 @@ INSTANTIATE_TEST_SUITE_P( auto descriptor = std::get(info.param).second; std::string level = std::to_string(std::get(info.param)); std::string mute = std::to_string(std::get(info.param)); - std::string name = getPrefix(descriptor) + "_level" + level + "_mute" + - mute; + std::string name = getPrefix(descriptor) + "_level" + level + "_mute" + mute; std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; From ddd7b58149a0ad3406d3ec070b2a31b8b06421e1 Mon Sep 17 00:00:00 2001 From: Yu Shan Date: Thu, 29 Jun 2023 18:33:04 -0700 Subject: [PATCH 032/152] Fix a type conversion bug. Convert int64_t to long on x86 platform loses info. Test: atest FakeVehicleHardwareTest on cf_gwear_x86. Bug: 288376096 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:76aaef448fcd9458b07b1d78ea4b79165af0cde0) Merged-In: I8826e2c0ba6c3e26af858a1d8f1388b75d537082 Change-Id: I8826e2c0ba6c3e26af858a1d8f1388b75d537082 --- .../fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h | 2 +- .../fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h index d2b701d9a5..2378676387 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h +++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/LinearFakeValueGenerator.h @@ -57,7 +57,7 @@ class LinearFakeValueGenerator : public FakeValueGenerator { 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. int64_t interval; - long lastEventTimestamp; + int64_t lastEventTimestamp; }; GeneratorCfg mGenCfg; diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp index 91331443bb..fe08dcf335 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/LinearFakeValueGenerator.cpp @@ -86,7 +86,7 @@ std::optional LinearFakeValueGenerator::nextEvent() { if (mGenCfg.lastEventTimestamp == 0) { mGenCfg.lastEventTimestamp = elapsedRealtimeNano(); } else { - long nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval; + int64_t nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval; // Prevent overflow. assert(nextEventTime > mGenCfg.lastEventTimestamp); mGenCfg.lastEventTimestamp = nextEventTime; From 588943abdc9a99299ce9da4ac6b2eb6df9653121 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Tue, 25 Apr 2023 15:26:38 +0530 Subject: [PATCH 033/152] Audio : Add remote submix stream implementation Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Merged-In: Ia477458193ade9068eaf56e953ab670fee53cc7d Change-Id: Ia477458193ade9068eaf56e953ab670fee53cc7d (cherry picked from commit 6bb696370b98eceac207c5f51ca4f98b2efb624a) --- audio/aidl/default/Android.bp | 5 + audio/aidl/default/Module.cpp | 19 +- .../include/core-impl/ModuleRemoteSubmix.h | 59 +++ audio/aidl/default/include/core-impl/Stream.h | 6 + .../include/core-impl/StreamRemoteSubmix.h | 98 +++++ .../default/r_submix/ModuleRemoteSubmix.cpp | 125 +++++++ .../default/r_submix/RemoteSubmixUtils.cpp | 47 +++ .../aidl/default/r_submix/RemoteSubmixUtils.h | 30 ++ .../default/r_submix/StreamRemoteSubmix.cpp | 354 ++++++++++++++++++ audio/aidl/default/r_submix/SubmixRoute.cpp | 230 ++++++++++++ audio/aidl/default/r_submix/SubmixRoute.h | 138 +++++++ 11 files changed, 1108 insertions(+), 3 deletions(-) create mode 100644 audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h create mode 100644 audio/aidl/default/include/core-impl/StreamRemoteSubmix.h create mode 100644 audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp create mode 100644 audio/aidl/default/r_submix/RemoteSubmixUtils.cpp create mode 100644 audio/aidl/default/r_submix/RemoteSubmixUtils.h create mode 100644 audio/aidl/default/r_submix/StreamRemoteSubmix.cpp create mode 100644 audio/aidl/default/r_submix/SubmixRoute.cpp create mode 100644 audio/aidl/default/r_submix/SubmixRoute.h diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index bda0de2b6d..e9294cf930 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -18,6 +18,7 @@ cc_defaults { "libbinder_ndk", "libcutils", "libfmq", + "libnbaio_mono", "libstagefright_foundation", "libtinyalsav2", "libutils", @@ -76,6 +77,10 @@ cc_library { "Stream.cpp", "StreamStub.cpp", "Telephony.cpp", + "r_submix/ModuleRemoteSubmix.cpp", + "r_submix/RemoteSubmixUtils.cpp", + "r_submix/SubmixRoute.cpp", + "r_submix/StreamRemoteSubmix.cpp", "usb/ModuleUsb.cpp", "usb/StreamUsb.cpp", "usb/UsbAlsaMixerControl.cpp", diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 6f89d4bc11..48d14580a7 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -27,6 +27,7 @@ #include "core-impl/Bluetooth.h" #include "core-impl/Module.h" +#include "core-impl/ModuleRemoteSubmix.h" #include "core-impl/ModuleUsb.h" #include "core-impl/SoundDose.h" #include "core-impl/StreamStub.h" @@ -111,8 +112,9 @@ std::shared_ptr Module::createInstance(Type type) { switch (type) { case Module::Type::USB: return ndk::SharedRefBase::make(type); - case Type::DEFAULT: case Type::R_SUBMIX: + return ndk::SharedRefBase::make(type); + case Type::DEFAULT: default: return ndk::SharedRefBase::make(type); } @@ -181,8 +183,8 @@ ndk::ScopedAStatus Module::createStreamContext( StreamContext temp( std::make_unique(1, true /*configureEventFlagWord*/), std::make_unique(1, true /*configureEventFlagWord*/), - portConfigIt->format.value(), portConfigIt->channelMask.value(), - portConfigIt->sampleRate.value().value, flags, + portConfigIt->portId, portConfigIt->format.value(), + portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags, portConfigIt->ext.get().handle, std::make_unique(frameSize * in_bufferSizeFrames), asyncCallback, outEventCallback, params); @@ -490,6 +492,17 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } + for (auto profile : connectedPort.profiles) { + if (profile.channelMasks.empty()) { + LOG(ERROR) << __func__ << ": the profile " << profile.name << " has no channel masks"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (profile.sampleRates.empty()) { + LOG(ERROR) << __func__ << ": the profile " << profile.name << " has no sample rates"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } + connectedPort.id = ++getConfig().nextPortId; auto [connectedPortsIt, _] = mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::vector())); diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h new file mode 100644 index 0000000000..7b1d375117 --- /dev/null +++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "core-impl/Module.h" + +namespace aidl::android::hardware::audio::core { + +class ModuleRemoteSubmix : public Module { + public: + explicit ModuleRemoteSubmix(Module::Type type) : Module(type) {} + + private: + // IModule interfaces + ndk::ScopedAStatus getTelephony(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getBluetooth(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getMicMute(bool* _aidl_return) override; + ndk::ScopedAStatus setMicMute(bool in_mute) override; + + // Module interfaces + ndk::ScopedAStatus createInputStream( + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, + std::shared_ptr* result) override; + ndk::ScopedAStatus createOutputStream( + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo, + std::shared_ptr* result) override; + ndk::ScopedAStatus populateConnectedDevicePort( + ::aidl::android::media::audio::common::AudioPort* audioPort) override; + ndk::ScopedAStatus checkAudioPatchEndpointsMatch( + const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources, + const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks) + override; + void onExternalDeviceConnectionChanged( + const ::aidl::android::media::audio::common::AudioPort& audioPort, + bool connected) override; + ndk::ScopedAStatus onMasterMuteChanged(bool mute) override; + ndk::ScopedAStatus onMasterVolumeChanged(float volume) override; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index c20a4213ed..e9f4fd4f83 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -78,6 +78,7 @@ class StreamContext { StreamContext() = default; StreamContext(std::unique_ptr commandMQ, std::unique_ptr replyMQ, + int portId, const ::aidl::android::media::audio::common::AudioFormatDescription& format, const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout, int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags, @@ -88,6 +89,7 @@ class StreamContext { : mCommandMQ(std::move(commandMQ)), mInternalCommandCookie(std::rand()), mReplyMQ(std::move(replyMQ)), + mPortId(portId), mFormat(format), mChannelLayout(channelLayout), mSampleRate(sampleRate), @@ -101,6 +103,7 @@ class StreamContext { : mCommandMQ(std::move(other.mCommandMQ)), mInternalCommandCookie(other.mInternalCommandCookie), mReplyMQ(std::move(other.mReplyMQ)), + mPortId(other.mPortId), mFormat(other.mFormat), mChannelLayout(other.mChannelLayout), mSampleRate(other.mSampleRate), @@ -114,6 +117,7 @@ class StreamContext { mCommandMQ = std::move(other.mCommandMQ); mInternalCommandCookie = other.mInternalCommandCookie; mReplyMQ = std::move(other.mReplyMQ); + mPortId = std::move(other.mPortId); mFormat = std::move(other.mFormat); mChannelLayout = std::move(other.mChannelLayout); mSampleRate = other.mSampleRate; @@ -145,6 +149,7 @@ class StreamContext { std::shared_ptr getOutEventCallback() const { return mOutEventCallback; } + int getPortId() const { return mPortId; } ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); } int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; } int getSampleRate() const { return mSampleRate; } @@ -155,6 +160,7 @@ class StreamContext { std::unique_ptr mCommandMQ; int mInternalCommandCookie; // The value used to confirm that the command was posted internally std::unique_ptr mReplyMQ; + int mPortId; ::aidl::android::media::audio::common::AudioFormatDescription mFormat; ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout; int mSampleRate; diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h new file mode 100644 index 0000000000..c1194abe95 --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "core-impl/Stream.h" +#include "r_submix/SubmixRoute.h" + +namespace aidl::android::hardware::audio::core { + +using aidl::android::hardware::audio::core::r_submix::AudioConfig; +using aidl::android::hardware::audio::core::r_submix::SubmixRoute; + +class StreamRemoteSubmix : public StreamCommonImpl { + public: + StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context); + + ::android::status_t init() override; + ::android::status_t drain(StreamDescriptor::DrainMode) override; + ::android::status_t flush() override; + ::android::status_t pause() override; + ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, + int32_t* latencyMs) override; + ::android::status_t standby() override; + void shutdown() override; + + // Overridden methods of 'StreamCommonImpl', called on a Binder thread. + ndk::ScopedAStatus prepareToClose() override; + + private: + size_t getPipeSizeInFrames(); + size_t getStreamPipeSizeInFrames(); + ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount); + ::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount); + + const int mPortId; + const bool mIsInput; + AudioConfig mStreamConfig; + std::shared_ptr mCurrentRoute = nullptr; + ::android::status_t mStatus = ::android::NO_INIT; + + // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex + // locks and none of the mutex locks should be taken together. + static std::mutex sSubmixRoutesLock; + static std::map> sSubmixRoutes + GUARDED_BY(sSubmixRoutesLock); + + // limit for number of read error log entries to avoid spamming the logs + static constexpr int kMaxReadErrorLogs = 5; + // The duration of kMaxReadFailureAttempts * READ_ATTEMPT_SLEEP_MS must be strictly inferior + // to the duration of a record buffer at the current record sample rate (of the device, not of + // the recording itself). Here we have: 3 * 5ms = 15ms < 1024 frames * 1000 / 48000 = 21.333ms + static constexpr int kMaxReadFailureAttempts = 3; + // 5ms between two read attempts when pipe is empty + static constexpr int kReadAttemptSleepUs = 5000; +}; + +class StreamInRemoteSubmix final : public StreamRemoteSubmix, public StreamIn { + public: + friend class ndk::SharedRefBase; + StreamInRemoteSubmix( + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + + private: + ndk::ScopedAStatus getActiveMicrophones( + std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) + override; +}; + +class StreamOutRemoteSubmix final : public StreamRemoteSubmix, public StreamOut { + public: + friend class ndk::SharedRefBase; + StreamOutRemoteSubmix( + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo); +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp new file mode 100644 index 0000000000..2b79f51117 --- /dev/null +++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_ModuleRemoteSubmix" + +#include + +#include + +#include "RemoteSubmixUtils.h" +#include "core-impl/ModuleRemoteSubmix.h" +#include "core-impl/StreamRemoteSubmix.h" + +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::media::audio::common::AudioOffloadInfo; +using aidl::android::media::audio::common::AudioPort; +using aidl::android::media::audio::common::AudioPortConfig; +using aidl::android::media::audio::common::MicrophoneInfo; + +namespace aidl::android::hardware::audio::core { + +ndk::ScopedAStatus ModuleRemoteSubmix::getTelephony(std::shared_ptr* _aidl_return) { + *_aidl_return = nullptr; + LOG(DEBUG) << __func__ << ": returning null"; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModuleRemoteSubmix::getBluetooth(std::shared_ptr* _aidl_return) { + *_aidl_return = nullptr; + LOG(DEBUG) << __func__ << ": returning null"; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModuleRemoteSubmix::getMicMute(bool* _aidl_return __unused) { + LOG(DEBUG) << __func__ << ": is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus ModuleRemoteSubmix::setMicMute(bool in_mute __unused) { + LOG(DEBUG) << __func__ << ": is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream( + const SinkMetadata& sinkMetadata, StreamContext&& context, + const std::vector& microphones, std::shared_ptr* result) { + return createStreamInstance(result, sinkMetadata, std::move(context), + microphones); +} + +ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream( + const SourceMetadata& sourceMetadata, StreamContext&& context, + const std::optional& offloadInfo, std::shared_ptr* result) { + return createStreamInstance(result, sourceMetadata, std::move(context), + offloadInfo); +} + +ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort) { + LOG(VERBOSE) << __func__ << ": Profiles already populated by Configuration"; + for (auto profile : audioPort->profiles) { + for (auto channelMask : profile.channelMasks) { + if (!r_submix::isChannelMaskSupported(channelMask)) { + LOG(ERROR) << __func__ << ": the profile " << profile.name + << " has unsupported channel mask : " << channelMask.toString(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } + for (auto sampleRate : profile.sampleRates) { + if (!r_submix::isSampleRateSupported(sampleRate)) { + LOG(ERROR) << __func__ << ": the profile " << profile.name + << " has unsupported sample rate : " << sampleRate; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModuleRemoteSubmix::checkAudioPatchEndpointsMatch( + const std::vector& sources, const std::vector& sinks) { + for (const auto& source : sources) { + for (const auto& sink : sinks) { + if (source->sampleRate != sink->sampleRate || + source->channelMask != sink->channelMask || source->format != sink->format) { + LOG(ERROR) << __func__ + << ": mismatch port configuration, source=" << source->toString() + << ", sink=" << sink->toString(); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + } + } + return ndk::ScopedAStatus::ok(); +} + +void ModuleRemoteSubmix::onExternalDeviceConnectionChanged( + const ::aidl::android::media::audio::common::AudioPort& audioPort __unused, + bool connected __unused) { + LOG(DEBUG) << __func__ << ": do nothing and return"; +} + +ndk::ScopedAStatus ModuleRemoteSubmix::onMasterMuteChanged(bool __unused) { + LOG(DEBUG) << __func__ << ": is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus ModuleRemoteSubmix::onMasterVolumeChanged(float __unused) { + LOG(DEBUG) << __func__ << ": is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp b/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp new file mode 100644 index 0000000000..2f5d17d44e --- /dev/null +++ b/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include "RemoteSubmixUtils.h" + +namespace aidl::android::hardware::audio::core::r_submix { + +bool isChannelMaskSupported(const AudioChannelLayout& channelMask) { + const static std::vector kSupportedChannelMask = { + AudioChannelLayout::make( + AudioChannelLayout::LAYOUT_MONO), + AudioChannelLayout::make( + AudioChannelLayout::LAYOUT_STEREO)}; + + if (std::find(kSupportedChannelMask.begin(), kSupportedChannelMask.end(), channelMask) != + kSupportedChannelMask.end()) { + return true; + } + return false; +} + +bool isSampleRateSupported(int sampleRate) { + const static std::vector kSupportedSampleRates = {8000, 11025, 12000, 16000, 22050, + 24000, 32000, 44100, 48000}; + + if (std::find(kSupportedSampleRates.begin(), kSupportedSampleRates.end(), sampleRate) != + kSupportedSampleRates.end()) { + return true; + } + return false; +} + +} // namespace aidl::android::hardware::audio::core::r_submix diff --git a/audio/aidl/default/r_submix/RemoteSubmixUtils.h b/audio/aidl/default/r_submix/RemoteSubmixUtils.h new file mode 100644 index 0000000000..952a992659 --- /dev/null +++ b/audio/aidl/default/r_submix/RemoteSubmixUtils.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +using aidl::android::media::audio::common::AudioChannelLayout; + +namespace aidl::android::hardware::audio::core::r_submix { + +bool isChannelMaskSupported(const AudioChannelLayout& channelMask); + +bool isSampleRateSupported(int sampleRate); + +} // namespace aidl::android::hardware::audio::core::r_submix diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp new file mode 100644 index 0000000000..9cc6fb8424 --- /dev/null +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_StreamRemoteSubmix" +#include + +#include + +#include "core-impl/StreamRemoteSubmix.h" + +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::media::audio::common::AudioOffloadInfo; +using aidl::android::media::audio::common::MicrophoneDynamicInfo; +using aidl::android::media::audio::common::MicrophoneInfo; + +namespace aidl::android::hardware::audio::core { + +StreamRemoteSubmix::StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context) + : StreamCommonImpl(metadata, std::move(context)), + mPortId(context.getPortId()), + mIsInput(isInput(metadata)) { + mStreamConfig.frameSize = context.getFrameSize(); + mStreamConfig.format = context.getFormat(); + mStreamConfig.channelLayout = context.getChannelLayout(); + mStreamConfig.sampleRate = context.getSampleRate(); +} + +std::mutex StreamRemoteSubmix::sSubmixRoutesLock; +std::map> StreamRemoteSubmix::sSubmixRoutes; + +::android::status_t StreamRemoteSubmix::init() { + { + std::lock_guard guard(sSubmixRoutesLock); + if (sSubmixRoutes.find(mPortId) != sSubmixRoutes.end()) { + mCurrentRoute = sSubmixRoutes[mPortId]; + } + } + // If route is not available for this port, add it. + if (mCurrentRoute == nullptr) { + // Initialize the pipe. + mCurrentRoute = std::make_shared(); + if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) { + LOG(ERROR) << __func__ << ": create pipe failed"; + return mStatus; + } + { + std::lock_guard guard(sSubmixRoutesLock); + sSubmixRoutes.emplace(mPortId, mCurrentRoute); + } + } else { + if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) { + LOG(ERROR) << __func__ << ": invalid stream config"; + return mStatus; + } + sp sink = mCurrentRoute->getSink(); + if (sink == nullptr) { + LOG(ERROR) << __func__ << ": nullptr sink when opening stream"; + return mStatus; + } + // If the sink has been shutdown or pipe recreation is forced, delete the pipe and + // recreate it. + if (sink->isShutdown()) { + LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream"; + if (::android::OK != mCurrentRoute->resetPipe()) { + LOG(ERROR) << __func__ << ": reset pipe failed"; + return mStatus; + } + } + } + + mCurrentRoute->openStream(mIsInput); + mStatus = ::android::OK; + return mStatus; +} + +::android::status_t StreamRemoteSubmix::drain(StreamDescriptor::DrainMode) { + usleep(1000); + return ::android::OK; +} + +::android::status_t StreamRemoteSubmix::flush() { + usleep(1000); + return ::android::OK; +} + +::android::status_t StreamRemoteSubmix::pause() { + usleep(1000); + return ::android::OK; +} + +ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() { + if (!mIsInput) { + std::shared_ptr route = nullptr; + { + std::lock_guard guard(sSubmixRoutesLock); + if (sSubmixRoutes.find(mPortId) != sSubmixRoutes.end()) { + route = sSubmixRoutes[mPortId]; + } + } + if (route != nullptr) { + sp sink = route->getSink(); + if (sink == nullptr) { + ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + LOG(DEBUG) << __func__ << ": shutting down MonoPipe sink"; + + sink->shutdown(true); + } else { + LOG(DEBUG) << __func__ << ": stream already closed."; + ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } + return ndk::ScopedAStatus::ok(); +} + +// Remove references to the specified input and output streams. When the device no longer +// references input and output streams destroy the associated pipe. +void StreamRemoteSubmix::shutdown() { + mCurrentRoute->closeStream(mIsInput); + // If all stream instances are closed, we can remove route information for this port. + if (!mCurrentRoute->hasAtleastOneStreamOpen()) { + mCurrentRoute->releasePipe(); + LOG(DEBUG) << __func__ << ": pipe destroyed"; + + std::lock_guard guard(sSubmixRoutesLock); + sSubmixRoutes.erase(mPortId); + mStatus = ::android::NO_INIT; + } +} + +::android::status_t StreamRemoteSubmix::transfer(void* buffer, size_t frameCount, + size_t* actualFrameCount, int32_t* latencyMs) { + if (mStatus != ::android::OK) { + LOG(ERROR) << __func__ << ": failed, not configured"; + return ::android::NO_INIT; + } + + *latencyMs = (getStreamPipeSizeInFrames() * MILLIS_PER_SECOND) / mStreamConfig.sampleRate; + LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms"; + + sp sink = mCurrentRoute->getSink(); + if (sink != nullptr) { + if (sink->isShutdown()) { + sink.clear(); + LOG(VERBOSE) << __func__ << ": pipe shutdown, ignoring the transfer."; + // the pipe has already been shutdown, this buffer will be lost but we must simulate + // timing so we don't drain the output faster than realtime + const size_t delayUs = static_cast( + std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate)); + usleep(delayUs); + + *actualFrameCount = frameCount; + return ::android::OK; + } + } else { + LOG(ERROR) << __func__ << ": transfer without a pipe!"; + return ::android::UNEXPECTED_NULL; + } + + mCurrentRoute->exitStandby(mIsInput); + return (mIsInput ? inRead(buffer, frameCount, actualFrameCount) + : outWrite(buffer, frameCount, actualFrameCount)); +} + +// Calculate the maximum size of the pipe buffer in frames for the specified stream. +size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { + auto pipeConfig = mCurrentRoute->mPipeConfig; + const size_t maxFrameSize = std::max(mStreamConfig.frameSize, pipeConfig.frameSize); + return (pipeConfig.frameCount * pipeConfig.frameSize) / maxFrameSize; +} + +::android::status_t StreamRemoteSubmix::outWrite(void* buffer, size_t frameCount, + size_t* actualFrameCount) { + sp sink = mCurrentRoute->getSink(); + if (sink != nullptr) { + if (sink->isShutdown()) { + sink.clear(); + LOG(VERBOSE) << __func__ << ": pipe shutdown, ignoring the write."; + // the pipe has already been shutdown, this buffer will be lost but we must + // simulate timing so we don't drain the output faster than realtime + const size_t delayUs = static_cast( + std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate)); + usleep(delayUs); + *actualFrameCount = frameCount; + return ::android::OK; + } + } else { + LOG(FATAL) << __func__ << ": without a pipe!"; + return ::android::UNKNOWN_ERROR; + } + + const size_t availableToWrite = sink->availableToWrite(); + // NOTE: sink has been checked above and sink and source life cycles are synchronized + sp source = mCurrentRoute->getSource(); + // If the write to the sink should be blocked, flush enough frames from the pipe to make space + // to write the most recent data. + if (!mCurrentRoute->shouldBlockWrite() && availableToWrite < frameCount) { + static uint8_t flushBuffer[64]; + const size_t flushBufferSizeFrames = sizeof(flushBuffer) / mStreamConfig.frameSize; + size_t framesToFlushFromSource = frameCount - availableToWrite; + LOG(VERBOSE) << __func__ << ": flushing " << framesToFlushFromSource + << " frames from the pipe to avoid blocking"; + while (framesToFlushFromSource) { + const size_t flushSize = std::min(framesToFlushFromSource, flushBufferSizeFrames); + framesToFlushFromSource -= flushSize; + // read does not block + source->read(flushBuffer, flushSize); + } + } + + ssize_t writtenFrames = sink->write(buffer, frameCount); + if (writtenFrames < 0) { + if (writtenFrames == (ssize_t)::android::NEGOTIATE) { + LOG(ERROR) << __func__ << ": write to pipe returned NEGOTIATE"; + sink.clear(); + *actualFrameCount = 0; + return ::android::UNKNOWN_ERROR; + } else { + // write() returned UNDERRUN or WOULD_BLOCK, retry + LOG(ERROR) << __func__ << ": write to pipe returned unexpected " << writtenFrames; + writtenFrames = sink->write(buffer, frameCount); + } + } + sink.clear(); + + if (writtenFrames < 0) { + LOG(ERROR) << __func__ << ": failed writing to pipe with " << writtenFrames; + *actualFrameCount = 0; + return ::android::UNKNOWN_ERROR; + } + LOG(VERBOSE) << __func__ << ": wrote " << writtenFrames << "frames"; + *actualFrameCount = writtenFrames; + return ::android::OK; +} + +::android::status_t StreamRemoteSubmix::inRead(void* buffer, size_t frameCount, + size_t* actualFrameCount) { + // about to read from audio source + sp source = mCurrentRoute->getSource(); + if (source == nullptr) { + int readErrorCount = mCurrentRoute->notifyReadError(); + if (readErrorCount < kMaxReadErrorLogs) { + LOG(ERROR) + << __func__ + << ": no audio pipe yet we're trying to read! (not all errors will be logged)"; + } else { + LOG(ERROR) << __func__ << ": Read errors " << readErrorCount; + } + const size_t delayUs = static_cast( + std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate)); + usleep(delayUs); + memset(buffer, 0, mStreamConfig.frameSize * frameCount); + *actualFrameCount = frameCount; + return ::android::OK; + } + + // read the data from the pipe + int attempts = 0; + const size_t delayUs = static_cast(std::roundf(kReadAttemptSleepUs)); + char* buff = (char*)buffer; + size_t remainingFrames = frameCount; + + while ((remainingFrames > 0) && (attempts < kMaxReadFailureAttempts)) { + LOG(VERBOSE) << __func__ << ": frames available to read " << source->availableToRead(); + + ssize_t framesRead = source->read(buff, remainingFrames); + + LOG(VERBOSE) << __func__ << ": frames read " << framesRead; + + if (framesRead > 0) { + remainingFrames -= framesRead; + buff += framesRead * mStreamConfig.frameSize; + LOG(VERBOSE) << __func__ << ": (attempts = " << attempts << ") got " << framesRead + << " frames, remaining=" << remainingFrames; + } else { + attempts++; + LOG(WARNING) << __func__ << ": read returned " << framesRead + << " , read failure attempts = " << attempts; + usleep(delayUs); + } + } + // done using the source + source.clear(); + + if (remainingFrames > 0) { + const size_t remainingBytes = remainingFrames * mStreamConfig.frameSize; + LOG(VERBOSE) << __func__ << ": clearing remaining_frames = " << remainingFrames; + memset(((char*)buffer) + (mStreamConfig.frameSize * frameCount) - remainingBytes, 0, + remainingBytes); + } + + long readCounterFrames = mCurrentRoute->updateReadCounterFrames(frameCount); + *actualFrameCount = frameCount; + + // compute how much we need to sleep after reading the data by comparing the wall clock with + // the projected time at which we should return. + // wall clock after reading from the pipe + auto recordDurationUs = std::chrono::steady_clock::now() - mCurrentRoute->getRecordStartTime(); + + // readCounterFrames contains the number of frames that have been read since the beginning of + // recording (including this call): it's converted to usec and compared to how long we've been + // recording for, which gives us how long we must wait to sync the projected recording time, and + // the observed recording time. + static constexpr float kScaleFactor = .8f; + const size_t projectedVsObservedOffsetUs = + kScaleFactor * (static_cast(std::roundf((readCounterFrames * MICROS_PER_SECOND / + mStreamConfig.sampleRate) - + recordDurationUs.count()))); + + LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count() + << " microseconds, will wait: " << projectedVsObservedOffsetUs << " microseconds"; + if (projectedVsObservedOffsetUs > 0) { + usleep(projectedVsObservedOffsetUs); + } + return ::android::OK; +} + +::android::status_t StreamRemoteSubmix::standby() { + mCurrentRoute->standby(mIsInput); + return ::android::OK; +} + +StreamInRemoteSubmix::StreamInRemoteSubmix(const SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector& microphones) + : StreamRemoteSubmix(sinkMetadata, std::move(context)), StreamIn(microphones) {} + +ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones( + std::vector* _aidl_return) { + LOG(DEBUG) << __func__ << ": not supported"; + *_aidl_return = std::vector(); + return ndk::ScopedAStatus::ok(); +} + +StreamOutRemoteSubmix::StreamOutRemoteSubmix(const SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional& offloadInfo) + : StreamRemoteSubmix(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp new file mode 100644 index 0000000000..8f5b8cb4e0 --- /dev/null +++ b/audio/aidl/default/r_submix/SubmixRoute.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_SubmixRoute" +#include +#include + +#include + +#include "SubmixRoute.h" + +using aidl::android::hardware::audio::common::getChannelCount; + +namespace aidl::android::hardware::audio::core::r_submix { + +// Verify a submix input or output stream can be opened. +bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig streamConfig) { + // If the stream is already open, don't open it again. + // ENABLE_LEGACY_INPUT_OPEN is default behaviour + if (!isInput && isStreamOutOpen()) { + LOG(ERROR) << __func__ << ": output stream already open."; + return false; + } + // If either stream is open, verify the existing pipe config matches the stream config. + if (hasAtleastOneStreamOpen() && !isStreamConfigCompatible(streamConfig)) { + return false; + } + return true; +} + +// Compare this stream config with existing pipe config, returning false if they do *not* +// match, true otherwise. +bool SubmixRoute::isStreamConfigCompatible(const AudioConfig streamConfig) { + if (streamConfig.channelLayout != mPipeConfig.channelLayout) { + LOG(ERROR) << __func__ << ": channel count mismatch, stream channels = " + << streamConfig.channelLayout.toString() + << " pipe config channels = " << mPipeConfig.channelLayout.toString(); + return false; + } + if (streamConfig.sampleRate != mPipeConfig.sampleRate) { + LOG(ERROR) << __func__ + << ": sample rate mismatch, stream sample rate = " << streamConfig.sampleRate + << " pipe config sample rate = " << mPipeConfig.sampleRate; + return false; + } + if (streamConfig.format != mPipeConfig.format) { + LOG(ERROR) << __func__ + << ": format mismatch, stream format = " << streamConfig.format.toString() + << " pipe config format = " << mPipeConfig.format.toString(); + return false; + } + return true; +} + +bool SubmixRoute::hasAtleastOneStreamOpen() { + std::lock_guard guard(mLock); + return (mStreamInOpen || mStreamOutOpen); +} + +// We DO NOT block if: +// - no peer input stream is present +// - the peer input is in standby AFTER having been active. +// We DO block if: +// - the input was never activated to avoid discarding first frames in the pipe in case capture +// start was delayed +bool SubmixRoute::shouldBlockWrite() { + std::lock_guard guard(mLock); + return (mStreamInOpen || (mStreamInStandby && (mReadCounterFrames != 0))); +} + +int SubmixRoute::notifyReadError() { + std::lock_guard guard(mLock); + return ++mReadErrorCount; +} + +long SubmixRoute::updateReadCounterFrames(size_t frameCount) { + std::lock_guard guard(mLock); + mReadCounterFrames += frameCount; + return mReadCounterFrames; +} + +void SubmixRoute::openStream(bool isInput) { + std::lock_guard guard(mLock); + if (isInput) { + if (mStreamInOpen) { + mInputRefCount++; + } else { + mInputRefCount = 1; + mStreamInOpen = true; + } + mStreamInStandby = true; + mReadCounterFrames = 0; + mReadErrorCount = 0; + } else { + mStreamOutOpen = true; + } +} + +void SubmixRoute::closeStream(bool isInput) { + std::lock_guard guard(mLock); + if (isInput) { + mInputRefCount--; + if (mInputRefCount == 0) { + mStreamInOpen = false; + if (mSink != nullptr) { + mSink->shutdown(true); + } + } + } else { + mStreamOutOpen = false; + } +} + +// If SubmixRoute doesn't exist for a port, create a pipe for the submix audio device of size +// buffer_size_frames and store config of the submix audio device. +::android::status_t SubmixRoute::createPipe(const AudioConfig streamConfig) { + const int channelCount = getChannelCount(streamConfig.channelLayout); + const audio_format_t audioFormat = VALUE_OR_RETURN_STATUS( + aidl2legacy_AudioFormatDescription_audio_format_t(streamConfig.format)); + const ::android::NBAIO_Format format = + ::android::Format_from_SR_C(streamConfig.sampleRate, channelCount, audioFormat); + const ::android::NBAIO_Format offers[1] = {format}; + size_t numCounterOffers = 0; + + const size_t pipeSizeInFrames = + r_submix::kDefaultPipeSizeInFrames * + ((float)streamConfig.sampleRate / r_submix::kDefaultSampleRateHz); + LOG(VERBOSE) << __func__ << ": creating pipe, rate : " << streamConfig.sampleRate + << ", pipe size : " << pipeSizeInFrames; + + // Create a MonoPipe with optional blocking set to true. + sp sink = sp::make(pipeSizeInFrames, format, true /*writeCanBlock*/); + if (sink == nullptr) { + LOG(FATAL) << __func__ << ": sink is null"; + return ::android::UNEXPECTED_NULL; + } + + // Negotiation between the source and sink cannot fail as the device open operation + // creates both ends of the pipe using the same audio format. + ssize_t index = sink->negotiate(offers, 1, nullptr, numCounterOffers); + if (index != 0) { + LOG(FATAL) << __func__ << ": Negotiation for the sink failed, index = " << index; + return ::android::BAD_INDEX; + } + sp source = sp::make(sink.get()); + if (source == nullptr) { + LOG(FATAL) << __func__ << ": source is null"; + return ::android::UNEXPECTED_NULL; + } + numCounterOffers = 0; + index = source->negotiate(offers, 1, nullptr, numCounterOffers); + if (index != 0) { + LOG(FATAL) << __func__ << ": Negotiation for the source failed, index = " << index; + return ::android::BAD_INDEX; + } + LOG(VERBOSE) << __func__ << ": created pipe"; + + mPipeConfig = streamConfig; + mPipeConfig.frameCount = sink->maxFrames(); + + LOG(VERBOSE) << __func__ << ": Pipe frame size : " << mPipeConfig.frameSize + << ", pipe frames : " << mPipeConfig.frameCount; + + // Save references to the source and sink. + { + std::lock_guard guard(mLock); + mSink = std::move(sink); + mSource = std::move(source); + } + + return ::android::OK; +} + +// Release references to the sink and source. +void SubmixRoute::releasePipe() { + std::lock_guard guard(mLock); + mSink.clear(); + mSource.clear(); +} + +::android::status_t SubmixRoute::resetPipe() { + releasePipe(); + return createPipe(mPipeConfig); +} + +void SubmixRoute::standby(bool isInput) { + std::lock_guard guard(mLock); + + if (isInput) { + mStreamInStandby = true; + } else { + mStreamOutStandby = true; + mStreamOutStandbyTransition = !mStreamOutStandbyTransition; + } +} + +void SubmixRoute::exitStandby(bool isInput) { + std::lock_guard guard(mLock); + + if (isInput) { + if (mStreamInStandby || mStreamOutStandbyTransition) { + mStreamInStandby = false; + mStreamOutStandbyTransition = false; + // keep track of when we exit input standby (== first read == start "real recording") + // or when we start recording silence, and reset projected time + mRecordStartTime = std::chrono::steady_clock::now(); + mReadCounterFrames = 0; + } + } else { + if (mStreamOutStandby) { + mStreamOutStandby = false; + mStreamOutStandbyTransition = true; + } + } +} + +} // namespace aidl::android::hardware::audio::core::r_submix diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h new file mode 100644 index 0000000000..5f7ea75934 --- /dev/null +++ b/audio/aidl/default/r_submix/SubmixRoute.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include +#include + +#include + +#include "core-impl/Stream.h" + +using aidl::android::media::audio::common::AudioChannelLayout; +using aidl::android::media::audio::common::AudioFormatDescription; +using aidl::android::media::audio::common::AudioFormatType; +using aidl::android::media::audio::common::PcmType; +using ::android::MonoPipe; +using ::android::MonoPipeReader; +using ::android::sp; + +namespace aidl::android::hardware::audio::core::r_submix { + +static constexpr int kDefaultSampleRateHz = 48000; +// Size at default sample rate +// NOTE: This value will be rounded up to the nearest power of 2 by MonoPipe(). +static constexpr int kDefaultPipeSizeInFrames = (1024 * 4); + +// Configuration of the audio stream. +struct AudioConfig { + int sampleRate = kDefaultSampleRateHz; + AudioFormatDescription format = + AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT}; + AudioChannelLayout channelLayout = + AudioChannelLayout::make( + AudioChannelLayout::LAYOUT_STEREO); + size_t frameSize; + size_t frameCount; +}; + +class SubmixRoute { + public: + AudioConfig mPipeConfig; + + bool isStreamInOpen() { + std::lock_guard guard(mLock); + return mStreamInOpen; + } + bool getStreamInStandby() { + std::lock_guard guard(mLock); + return mStreamInStandby; + } + bool isStreamOutOpen() { + std::lock_guard guard(mLock); + return mStreamOutOpen; + } + bool getStreamOutStandby() { + std::lock_guard guard(mLock); + return mStreamOutStandby; + } + long getReadCounterFrames() { + std::lock_guard guard(mLock); + return mReadCounterFrames; + } + int getReadErrorCount() { + std::lock_guard guard(mLock); + return mReadErrorCount; + } + std::chrono::time_point getRecordStartTime() { + std::lock_guard guard(mLock); + return mRecordStartTime; + } + sp getSink() { + std::lock_guard guard(mLock); + return mSink; + } + sp getSource() { + std::lock_guard guard(mLock); + return mSource; + } + + bool isStreamConfigValid(bool isInput, const AudioConfig streamConfig); + void closeStream(bool isInput); + ::android::status_t createPipe(const AudioConfig streamConfig); + void exitStandby(bool isInput); + bool hasAtleastOneStreamOpen(); + int notifyReadError(); + void openStream(bool isInput); + void releasePipe(); + ::android::status_t resetPipe(); + bool shouldBlockWrite(); + void standby(bool isInput); + long updateReadCounterFrames(size_t frameCount); + + private: + bool isStreamConfigCompatible(const AudioConfig streamConfig); + + std::mutex mLock; + + bool mStreamInOpen GUARDED_BY(mLock) = false; + int mInputRefCount GUARDED_BY(mLock) = 0; + bool mStreamInStandby GUARDED_BY(mLock) = true; + bool mStreamOutStandbyTransition GUARDED_BY(mLock) = false; + bool mStreamOutOpen GUARDED_BY(mLock) = false; + bool mStreamOutStandby GUARDED_BY(mLock) = true; + // how many frames have been requested to be read since standby + long mReadCounterFrames GUARDED_BY(mLock) = 0; + int mReadErrorCount GUARDED_BY(mLock) = 0; + // wall clock when recording starts + std::chrono::time_point mRecordStartTime GUARDED_BY(mLock); + + // Pipe variables: they handle the ring buffer that "pipes" audio: + // - from the submix virtual audio output == what needs to be played + // remotely, seen as an output for the client + // - to the virtual audio source == what is captured by the component + // which "records" the submix / virtual audio source, and handles it as needed. + // A usecase example is one where the component capturing the audio is then sending it over + // Wifi for presentation on a remote Wifi Display device (e.g. a dongle attached to a TV, or a + // TV with Wifi Display capabilities), or to a wireless audio player. + sp mSink GUARDED_BY(mLock); + sp mSource GUARDED_BY(mLock); +}; + +} // namespace aidl::android::hardware::audio::core::r_submix From 19d08c00aec2fff1e62c76326f6ca6acf37ac373 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 27 Jun 2023 16:39:33 -0700 Subject: [PATCH 034/152] audio: Add DriverInterface::start method This method is used to bring out the hardware from standby. It replaces the ad hoc 'exitStandby' method in StreamUsb. Streamlined StreamUsb code to avoid locking during transfers. Updated StreamRemoteSubmix to use 'start'. Added extra checks to StreamStub to ensure that 'init/shutdown' and 'standby/start' methods are called as expected. This allows removing extra checks from non-stub stream implementations. Bug: 205884982 Test: atest VtsHalAudioCoreTargetTest Merged-In: I3615a7ca99cb4f1e149dcbfbc912f2ed58fb033f Change-Id: I3615a7ca99cb4f1e149dcbfbc912f2ed58fb033f (cherry picked from commit 49712b56d8967d7302f8e48d4826c102e1327620) --- audio/aidl/default/Stream.cpp | 39 +++++--- audio/aidl/default/StreamStub.cpp | 47 +++++++-- audio/aidl/default/include/core-impl/Stream.h | 3 +- .../include/core-impl/StreamRemoteSubmix.h | 4 +- .../default/include/core-impl/StreamStub.h | 5 +- .../default/include/core-impl/StreamUsb.h | 19 +++- .../default/r_submix/StreamRemoteSubmix.cpp | 34 ++++--- audio/aidl/default/usb/StreamUsb.cpp | 95 +++++++++---------- 8 files changed, 150 insertions(+), 96 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 73f1293007..251dea09e5 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -166,10 +166,15 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { case Tag::start: if (mState == StreamDescriptor::State::STANDBY || mState == StreamDescriptor::State::DRAINING) { - populateReply(&reply, mIsConnected); - mState = mState == StreamDescriptor::State::STANDBY - ? StreamDescriptor::State::IDLE - : StreamDescriptor::State::ACTIVE; + if (::android::status_t status = mDriver->start(); status == ::android::OK) { + populateReply(&reply, mIsConnected); + mState = mState == StreamDescriptor::State::STANDBY + ? StreamDescriptor::State::IDLE + : StreamDescriptor::State::ACTIVE; + } else { + LOG(ERROR) << __func__ << ": start failed: " << status; + mState = StreamDescriptor::State::ERROR; + } } else { populateReplyWrongState(&reply, command); } @@ -377,26 +382,36 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { populateReply(&reply, mIsConnected); break; case Tag::start: { - bool commandAccepted = true; + std::optional nextState; switch (mState) { case StreamDescriptor::State::STANDBY: - mState = StreamDescriptor::State::IDLE; + nextState = StreamDescriptor::State::IDLE; break; case StreamDescriptor::State::PAUSED: - mState = StreamDescriptor::State::ACTIVE; + nextState = StreamDescriptor::State::ACTIVE; break; case StreamDescriptor::State::DRAIN_PAUSED: - switchToTransientState(StreamDescriptor::State::DRAINING); + nextState = StreamDescriptor::State::DRAINING; break; case StreamDescriptor::State::TRANSFER_PAUSED: - switchToTransientState(StreamDescriptor::State::TRANSFERRING); + nextState = StreamDescriptor::State::TRANSFERRING; break; default: populateReplyWrongState(&reply, command); - commandAccepted = false; } - if (commandAccepted) { - populateReply(&reply, mIsConnected); + if (nextState.has_value()) { + if (::android::status_t status = mDriver->start(); status == ::android::OK) { + populateReply(&reply, mIsConnected); + if (*nextState == StreamDescriptor::State::IDLE || + *nextState == StreamDescriptor::State::ACTIVE) { + mState = *nextState; + } else { + switchToTransientState(*nextState); + } + } else { + LOG(ERROR) << __func__ << ": start failed: " << status; + mState = StreamDescriptor::State::ERROR; + } } } break; case Tag::burst: diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/StreamStub.cpp index d88dfbc3c2..2dcf4d4d42 100644 --- a/audio/aidl/default/StreamStub.cpp +++ b/audio/aidl/default/StreamStub.cpp @@ -33,33 +33,67 @@ namespace aidl::android::hardware::audio::core { StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context) : StreamCommonImpl(metadata, std::move(context)), - mFrameSizeBytes(context.getFrameSize()), - mSampleRate(context.getSampleRate()), - mIsAsynchronous(!!context.getAsyncCallback()), + mFrameSizeBytes(getContext().getFrameSize()), + mSampleRate(getContext().getSampleRate()), + mIsAsynchronous(!!getContext().getAsyncCallback()), mIsInput(isInput(metadata)) {} ::android::status_t StreamStub::init() { + mIsInitialized = true; usleep(500); return ::android::OK; } ::android::status_t StreamStub::drain(StreamDescriptor::DrainMode) { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } usleep(500); return ::android::OK; } ::android::status_t StreamStub::flush() { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } usleep(500); return ::android::OK; } ::android::status_t StreamStub::pause() { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } usleep(500); return ::android::OK; } +::android::status_t StreamStub::standby() { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + usleep(500); + mIsStandby = true; + return ::android::OK; +} + +::android::status_t StreamStub::start() { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + usleep(500); + mIsStandby = false; + return ::android::OK; +} + ::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { + if (!mIsInitialized) { + LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; + } + if (mIsStandby) { + LOG(FATAL) << __func__ << ": must not happen while in standby"; + } static constexpr float kMicrosPerSecond = MICROS_PER_SECOND; static constexpr float kScaleFactor = .8f; if (mIsAsynchronous) { @@ -80,13 +114,10 @@ StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context) return ::android::OK; } -::android::status_t StreamStub::standby() { - usleep(500); - return ::android::OK; +void StreamStub::shutdown() { + mIsInitialized = false; } -void StreamStub::shutdown() {} - StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector& microphones) : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {} diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index e9f4fd4f83..aaf58601b5 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -180,9 +180,10 @@ struct DriverInterface { virtual ::android::status_t drain(StreamDescriptor::DrainMode mode) = 0; virtual ::android::status_t flush() = 0; virtual ::android::status_t pause() = 0; + virtual ::android::status_t standby() = 0; + virtual ::android::status_t start() = 0; virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) = 0; - virtual ::android::status_t standby() = 0; virtual void shutdown() = 0; // This function is only called once. }; diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h index c1194abe95..2253ec76cd 100644 --- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -35,9 +35,10 @@ class StreamRemoteSubmix : public StreamCommonImpl { ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; + ::android::status_t standby() override; + ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; - ::android::status_t standby() override; void shutdown() override; // Overridden methods of 'StreamCommonImpl', called on a Binder thread. @@ -53,7 +54,6 @@ class StreamRemoteSubmix : public StreamCommonImpl { const bool mIsInput; AudioConfig mStreamConfig; std::shared_ptr mCurrentRoute = nullptr; - ::android::status_t mStatus = ::android::NO_INIT; // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex // locks and none of the mutex locks should be taken together. diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index c8900f3223..6b1b2ddc89 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -28,9 +28,10 @@ class StreamStub : public StreamCommonImpl { ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; + ::android::status_t standby() override; + ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; - ::android::status_t standby() override; void shutdown() override; private: @@ -38,6 +39,8 @@ class StreamStub : public StreamCommonImpl { const int mSampleRate; const bool mIsAsynchronous; const bool mIsInput; + bool mIsInitialized = false; // Used for validating the state machine logic. + bool mIsStandby = true; // Used for validating the state machine logic. }; class StreamInStub final : public StreamStub, public StreamIn { diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 5e55cd8cb8..8c40782db1 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -16,7 +16,10 @@ #pragma once +#include +#include #include +#include #include #include @@ -38,9 +41,10 @@ class StreamUsb : public StreamCommonImpl { ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; + ::android::status_t standby() override; + ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; - ::android::status_t standby() override; void shutdown() override; // Overridden methods of 'StreamCommonImpl', called on a Binder thread. @@ -48,15 +52,20 @@ class StreamUsb : public StreamCommonImpl { ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override; private: - ::android::status_t exitStandby(); + using AlsaDeviceProxyDeleter = std::function; + using AlsaDeviceProxy = std::unique_ptr; + + static std::optional maybePopulateConfig(const StreamContext& context, + bool isInput); mutable std::mutex mLock; const size_t mFrameSizeBytes; - std::optional mConfig; const bool mIsInput; - std::vector> mAlsaDeviceProxies GUARDED_BY(mLock); - bool mIsStandby = true; + const std::optional mConfig; + std::atomic mConnectedDevicesUpdated = false; + // All fields below are only used on the worker thread. + std::vector mAlsaDeviceProxies; }; class StreamInUsb final : public StreamUsb, public StreamIn { diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 9cc6fb8424..5af0d914b8 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -55,7 +55,7 @@ std::map> StreamRemoteSubmix::sSubmixRoute mCurrentRoute = std::make_shared(); if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) { LOG(ERROR) << __func__ << ": create pipe failed"; - return mStatus; + return ::android::NO_INIT; } { std::lock_guard guard(sSubmixRoutesLock); @@ -64,12 +64,12 @@ std::map> StreamRemoteSubmix::sSubmixRoute } else { if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) { LOG(ERROR) << __func__ << ": invalid stream config"; - return mStatus; + return ::android::NO_INIT; } sp sink = mCurrentRoute->getSink(); if (sink == nullptr) { LOG(ERROR) << __func__ << ": nullptr sink when opening stream"; - return mStatus; + return ::android::NO_INIT; } // If the sink has been shutdown or pipe recreation is forced, delete the pipe and // recreate it. @@ -77,14 +77,13 @@ std::map> StreamRemoteSubmix::sSubmixRoute LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream"; if (::android::OK != mCurrentRoute->resetPipe()) { LOG(ERROR) << __func__ << ": reset pipe failed"; - return mStatus; + return ::android::NO_INIT; } } } mCurrentRoute->openStream(mIsInput); - mStatus = ::android::OK; - return mStatus; + return ::android::OK; } ::android::status_t StreamRemoteSubmix::drain(StreamDescriptor::DrainMode) { @@ -102,6 +101,16 @@ std::map> StreamRemoteSubmix::sSubmixRoute return ::android::OK; } +::android::status_t StreamRemoteSubmix::standby() { + mCurrentRoute->standby(mIsInput); + return ::android::OK; +} + +::android::status_t StreamRemoteSubmix::start() { + mCurrentRoute->exitStandby(mIsInput); + return ::android::OK; +} + ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() { if (!mIsInput) { std::shared_ptr route = nullptr; @@ -138,17 +147,12 @@ void StreamRemoteSubmix::shutdown() { std::lock_guard guard(sSubmixRoutesLock); sSubmixRoutes.erase(mPortId); - mStatus = ::android::NO_INIT; } + mCurrentRoute.reset(); } ::android::status_t StreamRemoteSubmix::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { - if (mStatus != ::android::OK) { - LOG(ERROR) << __func__ << ": failed, not configured"; - return ::android::NO_INIT; - } - *latencyMs = (getStreamPipeSizeInFrames() * MILLIS_PER_SECOND) / mStreamConfig.sampleRate; LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms"; @@ -171,7 +175,6 @@ void StreamRemoteSubmix::shutdown() { return ::android::UNEXPECTED_NULL; } - mCurrentRoute->exitStandby(mIsInput); return (mIsInput ? inRead(buffer, frameCount, actualFrameCount) : outWrite(buffer, frameCount, actualFrameCount)); } @@ -329,11 +332,6 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { return ::android::OK; } -::android::status_t StreamRemoteSubmix::standby() { - mCurrentRoute->standby(mIsInput); - return ::android::OK; -} - StreamInRemoteSubmix::StreamInRemoteSubmix(const SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector& microphones) diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index 49bc1d67a0..17e1ab42f1 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #define LOG_TAG "AHAL_StreamUsb" #include @@ -45,25 +47,30 @@ namespace aidl::android::hardware::audio::core { StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context) : StreamCommonImpl(metadata, std::move(context)), - mFrameSizeBytes(context.getFrameSize()), - mIsInput(isInput(metadata)) { + mFrameSizeBytes(getContext().getFrameSize()), + mIsInput(isInput(metadata)), + mConfig(maybePopulateConfig(getContext(), mIsInput)) {} + +// static +std::optional StreamUsb::maybePopulateConfig(const StreamContext& context, + bool isInput) { struct pcm_config config; - config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), mIsInput); + config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput); if (config.channels == 0) { LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString(); - return; + return std::nullopt; } config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat()); if (config.format == PCM_FORMAT_INVALID) { LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString(); - return; + return std::nullopt; } config.rate = context.getSampleRate(); if (config.rate == 0) { LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate; - return; + return std::nullopt; } - mConfig = config; + return config; } ::android::status_t StreamUsb::init() { @@ -89,8 +96,8 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( } } std::lock_guard guard(mLock); - mAlsaDeviceProxies.clear(); RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices)); + mConnectedDevicesUpdated.store(true, std::memory_order_release); return ndk::ScopedAStatus::ok(); } @@ -111,59 +118,53 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( ::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { - { - std::lock_guard guard(mLock); - if (!mConfig.has_value() || mConnectedDevices.empty()) { - LOG(ERROR) << __func__ << ": failed, has config: " << mConfig.has_value() - << ", has connected devices: " << mConnectedDevices.empty(); - return ::android::NO_INIT; - } - } - if (mIsStandby) { - if (::android::status_t status = exitStandby(); status != ::android::OK) { - LOG(ERROR) << __func__ << ": failed to exit standby, status=" << status; - return status; - } - } - std::vector> alsaDeviceProxies; - { - std::lock_guard guard(mLock); - alsaDeviceProxies = mAlsaDeviceProxies; + if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) { + // 'setConnectedDevices' has been called. I/O will be restarted. + *actualFrameCount = 0; + *latencyMs = StreamDescriptor::LATENCY_UNKNOWN; + return ::android::OK; } const size_t bytesToTransfer = frameCount * mFrameSizeBytes; + unsigned maxLatency = 0; if (mIsInput) { + if (mAlsaDeviceProxies.empty()) { + LOG(FATAL) << __func__ << ": no input devices"; + return ::android::NO_INIT; + } // For input case, only support single device. - proxy_read(alsaDeviceProxies[0].get(), buffer, bytesToTransfer); + proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer); + maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get()); } else { - for (auto& proxy : alsaDeviceProxies) { + for (auto& proxy : mAlsaDeviceProxies) { proxy_write(proxy.get(), buffer, bytesToTransfer); + maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get())); } } *actualFrameCount = frameCount; - *latencyMs = Module::kLatencyMs; + maxLatency = std::min(maxLatency, static_cast(std::numeric_limits::max())); + *latencyMs = maxLatency; return ::android::OK; } ::android::status_t StreamUsb::standby() { - if (!mIsStandby) { - std::lock_guard guard(mLock); - mAlsaDeviceProxies.clear(); - mIsStandby = true; - } + mAlsaDeviceProxies.clear(); return ::android::OK; } -void StreamUsb::shutdown() {} +void StreamUsb::shutdown() { + mAlsaDeviceProxies.clear(); +} -::android::status_t StreamUsb::exitStandby() { +::android::status_t StreamUsb::start() { std::vector connectedDevices; { std::lock_guard guard(mLock); std::transform(mConnectedDevices.begin(), mConnectedDevices.end(), std::back_inserter(connectedDevices), [](const auto& device) { return device.address; }); + mConnectedDevicesUpdated.store(false, std::memory_order_release); } - std::vector> alsaDeviceProxies; + decltype(mAlsaDeviceProxies) alsaDeviceProxies; for (const auto& device : connectedDevices) { alsa_device_profile profile; profile_init(&profile, mIsInput ? PCM_IN : PCM_OUT); @@ -175,16 +176,16 @@ void StreamUsb::shutdown() {} return ::android::UNKNOWN_ERROR; } - auto proxy = std::shared_ptr(new alsa_device_proxy(), - [](alsa_device_proxy* proxy) { - proxy_close(proxy); - free(proxy); - }); + AlsaDeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) { + proxy_close(proxy); + free(proxy); + }); // Always ask for alsa configure as required since the configuration should be supported // by the connected device. That is guaranteed by `setAudioPortConfig` and // `setAudioPatch`. - if (int err = - proxy_prepare(proxy.get(), &profile, &mConfig.value(), true /*is_bit_perfect*/); + if (int err = proxy_prepare(proxy.get(), &profile, + const_cast(&mConfig.value()), + true /*is_bit_perfect*/); err != 0) { LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device.toString() << " error=" << err; @@ -197,11 +198,7 @@ void StreamUsb::shutdown() {} } alsaDeviceProxies.push_back(std::move(proxy)); } - { - std::lock_guard guard(mLock); - mAlsaDeviceProxies = alsaDeviceProxies; - } - mIsStandby = false; + mAlsaDeviceProxies = std::move(alsaDeviceProxies); return ::android::OK; } From feb37e509e5f0a3ce435a3fd6e6229ae6db0f3b5 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Thu, 29 Jun 2023 18:18:20 +0000 Subject: [PATCH 035/152] Support passing entire effect_param_t as vendor extension Replace the UUID toString with hex version Bug: 271500140 Test: Enable AIDL Test: atest libAudioHalEffectParamTest Change-Id: I79a5db25dc45774821a9a9a6bcda77c04e9da90d Merged-In: I79a5db25dc45774821a9a9a6bcda77c04e9da90d --- audio/aidl/default/EffectConfig.cpp | 4 +++- audio/aidl/default/EffectFactory.cpp | 18 +++++++++++------- .../aidl/default/extension/ExtensionEffect.cpp | 12 ++++++------ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp index 71d111bd06..f3f674f6ef 100644 --- a/audio/aidl/default/EffectConfig.cpp +++ b/audio/aidl/default/EffectConfig.cpp @@ -18,6 +18,7 @@ #include #define LOG_TAG "AHAL_EffectConfig" #include +#include #include #include @@ -162,7 +163,7 @@ bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml, RETURN_VALUE_IF((libraryUuid.uuid == getEffectUuidZero()), false, "invalidUuidAttribute"); LOG(DEBUG) << __func__ << (isProxy ? " proxy " : libraryUuid.name) << " : " - << libraryUuid.uuid.toString(); + << ::android::audio::utils::toString(libraryUuid.uuid); return true; } @@ -250,6 +251,7 @@ bool EffectConfig::findUuid(const std::string& xmlEffectName, AudioUuid* uuid) { V("downmix", Downmix) \ V("dynamics_processing", DynamicsProcessing) \ V("equalizer", Equalizer) \ + V("extensioneffect", Extension) \ V("haptic_generator", HapticGenerator) \ V("loudness_enhancer", LoudnessEnhancer) \ V("env_reverb", EnvReverb) \ diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp index 7073a10c96..8ed62c9c7a 100644 --- a/audio/aidl/default/EffectFactory.cpp +++ b/audio/aidl/default/EffectFactory.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -47,7 +48,7 @@ Factory::~Factory() { for (const auto& it : mEffectMap) { if (auto spEffect = it.first.lock()) { LOG(ERROR) << __func__ << " erase remaining instance UUID " - << it.second.first.toString(); + << ::android::audio::utils::toString(it.second.first); destroyEffectImpl(spEffect); } } @@ -123,7 +124,7 @@ ndk::ScopedAStatus Factory::queryProcessing(const std::optional* _aidl_return) { - LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString(); + LOG(DEBUG) << __func__ << ": UUID " << ::android::audio::utils::toString(in_impl_uuid); if (mEffectLibMap.count(in_impl_uuid)) { auto& entry = mEffectLibMap[in_impl_uuid]; getDlSyms(entry); @@ -163,7 +164,8 @@ ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr& in "dlNulldestroyEffectFunc"); RETURN_IF_BINDER_EXCEPTION(interface->destroyEffectFunc(in_handle)); } else { - LOG(ERROR) << __func__ << ": UUID " << uuid.toString() << " does not exist in libMap!"; + LOG(ERROR) << __func__ << ": UUID " << ::android::audio::utils::toString(uuid) + << " does not exist in libMap!"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } mEffectMap.erase(effectIt); @@ -207,8 +209,8 @@ bool Factory::openEffectLibrary(const AudioUuid& impl, const std::string& path) return false; } - LOG(INFO) << __func__ << " dlopen lib:" << path << "\nimpl:" << impl.toString() - << "\nhandle:" << libHandle; + LOG(INFO) << __func__ << " dlopen lib:" << path + << "\nimpl:" << ::android::audio::utils::toString(impl) << "\nhandle:" << libHandle; auto interface = new effect_dl_interface_s{nullptr, nullptr, nullptr}; mEffectLibMap.insert( {impl, @@ -228,8 +230,10 @@ void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLi id.uuid = configLib.uuid; id.proxy = proxyUuid; LOG(DEBUG) << __func__ << " loading lib " << path->second << ": typeUuid " - << id.type.toString() << "\nimplUuid " << id.uuid.toString() << " proxyUuid " - << (proxyUuid.has_value() ? proxyUuid->toString() : "null"); + << ::android::audio::utils::toString(id.type) << "\nimplUuid " + << ::android::audio::utils::toString(id.uuid) << " proxyUuid " + << (proxyUuid.has_value() ? ::android::audio::utils::toString(proxyUuid.value()) + : "null"); if (openEffectLibrary(id.uuid, path->second)) { mIdentitySet.insert(std::move(id)); } diff --git a/audio/aidl/default/extension/ExtensionEffect.cpp b/audio/aidl/default/extension/ExtensionEffect.cpp index c4eebc005f..4a4d71b687 100644 --- a/audio/aidl/default/extension/ExtensionEffect.cpp +++ b/audio/aidl/default/extension/ExtensionEffect.cpp @@ -30,8 +30,8 @@ using aidl::android::hardware::audio::effect::DefaultExtension; using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::ExtensionEffect; -using aidl::android::hardware::audio::effect::getEffectUuidExtensionImpl; -using aidl::android::hardware::audio::effect::getEffectUuidExtensionType; +using aidl::android::hardware::audio::effect::getEffectImplUuidExtension; +using aidl::android::hardware::audio::effect::getEffectTypeUuidExtension; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::Range; using aidl::android::hardware::audio::effect::VendorExtension; @@ -39,7 +39,7 @@ using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != getEffectUuidExtensionImpl()) { + if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidExtension()) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } @@ -54,7 +54,7 @@ extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, } extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) { - if (!in_impl_uuid || *in_impl_uuid != getEffectUuidExtensionImpl()) { + if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidExtension()) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } @@ -67,8 +67,8 @@ namespace aidl::android::hardware::audio::effect { const std::string ExtensionEffect::kEffectName = "ExtensionEffectExample"; const Descriptor ExtensionEffect::kDescriptor = { - .common = {.id = {.type = getEffectUuidExtensionType(), - .uuid = getEffectUuidExtensionImpl(), + .common = {.id = {.type = getEffectTypeUuidExtension(), + .uuid = getEffectImplUuidExtension(), .proxy = std::nullopt}, .name = ExtensionEffect::kEffectName, .implementor = "The Android Open Source Project"}}; From 558dbedf51dda8ed8b70aacda3a8f11138e66833 Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Fri, 28 Apr 2023 23:37:02 +0000 Subject: [PATCH 036/152] Strongbox may not support 1024 bit key size for RSA. Strongbox may not support 1024 bit key size for RSA. So in NoUserConfirmation test updated the key size to 2048 so that the test works for both TEE and Strongbox. Bug: 280117495 Test: run VtsAidlKeyMintTarget (cherry picked from https://android-review.googlesource.com/q/commit:ce2bebdd79cf7536b06c2d67cdee8867475a3b10) Merged-In: I32bb28001aca9b69eedb1bd3d0bcff43052d06e4 Change-Id: I32bb28001aca9b69eedb1bd3d0bcff43052d06e4 --- security/keymint/aidl/vts/functional/KeyMintTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp index e99149bf17..bdec4d3fb4 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -3119,7 +3119,7 @@ TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) { */ TEST_P(SigningOperationsTest, NoUserConfirmation) { ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(1024, 65537) + .RsaSigningKey(2048, 65537) .Digest(Digest::NONE) .Padding(PaddingMode::NONE) .Authorization(TAG_NO_AUTH_REQUIRED) From 997efaa19115ef3b5a655323b35118d1be1736fd Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Tue, 9 May 2023 08:10:36 +0100 Subject: [PATCH 037/152] Skip ATTEST_KEY using variant on waivered devices Bug: 281452355 Bug: 289451966 Test: VtsAidlKeyMintTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:c3de1caf4327dc367a95f7416cba19827428bd1b) Merged-In: Id448edae88569518deb2db4ab7bf50d16f33709a Change-Id: Id448edae88569518deb2db4ab7bf50d16f33709a --- .../vts/functional/KeyBlobUpgradeTest.cpp | 25 +++++++++++- .../vts/functional/KeyMintAidlTestBase.cpp | 40 ++++++++++++++----- .../aidl/vts/functional/KeyMintAidlTestBase.h | 1 + 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp index 68924422d1..fb014cfe0b 100644 --- a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp @@ -71,6 +71,9 @@ namespace aidl::android::hardware::security::keymint::test { namespace { +// Names for individual key types to create and use. Note that some the names +// induce specific behaviour, as indicated by the functions below. + std::vector keyblob_names_tee = { "aes-key", "aes-key-rr", "des-key", "hmac-key", "rsa-key", "p256-key", "ed25519-key", "x25519-key", @@ -84,6 +87,11 @@ std::vector keyblob_names_sb = {"aes-key", "aes-key-rr", "hmac-key", "rsa-key", "p256-key", "rsa-attest-key", "p256-attest-key"}; +// Helper functions to detect particular key types based on the name. +bool requires_attest_key(const std::string& name) { + return name.find("-attest-key") != std::string::npos; +} + bool requires_rr(const std::string& name) { return name.find("-rr") != std::string::npos; } @@ -207,6 +215,11 @@ class KeyBlobUpgradeTest : public KeyMintAidlTestBase { } for (std::string name : keyblob_names()) { + if (requires_attest_key(name) && shouldSkipAttestKeyTest()) { + std::cerr << "Skipping variant '" << name + << "' which requires ATTEST_KEY support that has been waivered\n"; + continue; + } for (bool with_hidden : {false, true}) { std::string app_id; std::string app_data; @@ -355,6 +368,11 @@ TEST_P(KeyBlobUpgradeTest, CreateKeyBlobsBefore) { }}; for (std::string name : keyblob_names()) { + if (requires_attest_key(name) && shouldSkipAttestKeyTest()) { + std::cerr << "Skipping variant '" << name + << "' which requires ATTEST_KEY support that has been waivered\n"; + continue; + } auto entry = keys_info.find(name); ASSERT_NE(entry, keys_info.end()) << "no builder for " << name; auto builder = entry->second; @@ -432,6 +450,11 @@ TEST_P(KeyBlobUpgradeTest, UseKeyBlobsBeforeOrAfter) { } for (std::string name : keyblob_names()) { + if (requires_attest_key(name) && shouldSkipAttestKeyTest()) { + std::cerr << "Skipping variant '" << name + << "' which requires ATTEST_KEY support that has been waivered\n"; + continue; + } for (bool with_hidden : {false, true}) { auto builder = AuthorizationSetBuilder(); if (with_hidden) { @@ -531,7 +554,7 @@ TEST_P(KeyBlobUpgradeTest, UseKeyBlobsBeforeOrAfter) { // Both ways round should agree. EXPECT_EQ(keymint_data, local_data); - } else if (name.find("-attest-key") != std::string::npos) { + } else if (requires_attest_key(name)) { // Covers rsa-attest-key, p256-attest-key, ed25519-attest-key. // Use attestation key to sign RSA signing key diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index a8ea407e44..ec7256e23f 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -1617,17 +1617,39 @@ bool KeyMintAidlTestBase::is_chipset_allowed_km4_strongbox(void) const { return false; } -// Skip the test if all the following conditions hold: -// 1. ATTEST_KEY feature is disabled -// 2. STRONGBOX is enabled -// 3. The device is running one of the chipsets that have received a waiver -// allowing it to be launched with Android S (or later) with Keymaster 4.0 +// Indicate whether a test that involves use of the ATTEST_KEY feature should be +// skipped. +// +// In general, every KeyMint implementation should support ATTEST_KEY; +// however, there is a waiver for some specific devices that ship with a +// combination of Keymaster/StrongBox and KeyMint/TEE. On these devices, the +// ATTEST_KEY feature is disabled in the KeyMint/TEE implementation so that +// the device has consistent ATTEST_KEY behavior (ie. UNIMPLEMENTED) across both +// HAL implementations. +// +// This means that a test involving ATTEST_KEY test should be skipped if all of +// the following conditions hold: +// 1. The device is running one of the chipsets that have received a waiver +// allowing it to be launched with Android S or T with Keymaster 4.0 // in StrongBox -void KeyMintAidlTestBase::skipAttestKeyTest(void) const { +// 2. The device has a STRONGBOX implementation present. +// 3. ATTEST_KEY feature is advertised as disabled. +// +// Note that in this scenario, ATTEST_KEY tests should be skipped for both +// the StrongBox implementation (which is Keymaster, therefore not tested here) +// and for the TEE implementation (which is adjusted to return UNIMPLEMENTED +// specifically for this waiver). +bool KeyMintAidlTestBase::shouldSkipAttestKeyTest(void) const { // Check the chipset first as that doesn't require a round-trip to Package Manager. - if (is_chipset_allowed_km4_strongbox() && is_strongbox_enabled() && - is_attest_key_feature_disabled()) { - GTEST_SKIP() << "Test is not applicable"; + return (is_chipset_allowed_km4_strongbox() && is_strongbox_enabled() && + is_attest_key_feature_disabled()); +} + +// Skip a test that involves use of the ATTEST_KEY feature in specific configurations +// where ATTEST_KEY is not supported (for either StrongBox or TEE). +void KeyMintAidlTestBase::skipAttestKeyTest(void) const { + if (shouldSkipAttestKeyTest()) { + GTEST_SKIP() << "Test using ATTEST_KEY is not applicable on waivered device"; } } diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h index 30ac452bab..1763e943a7 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h @@ -359,6 +359,7 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam { bool is_attest_key_feature_disabled(void) const; bool is_strongbox_enabled(void) const; bool is_chipset_allowed_km4_strongbox(void) const; + bool shouldSkipAttestKeyTest(void) const; void skipAttestKeyTest(void) const; protected: From 94042a987c692b97c500abd7eaa9d932362367a1 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Thu, 15 Jun 2023 09:41:05 +0100 Subject: [PATCH 038/152] Allow extra error code in device ID attestation Generalize the existing helper function to allow more variants. Remove a couple of pointless invocations of the existing helper. Bug: 286733800 Test: VtsAidlKeyMintTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:f42238c99ffe0df2e51cec84a96ed859a878b2b0) Merged-In: Ic01c53cbe79f55c2d403a66acbfd04029395c287 Change-Id: Ic01c53cbe79f55c2d403a66acbfd04029395c287 --- .../aidl/vts/functional/AttestKeyTest.cpp | 9 +------ .../DeviceUniqueAttestationTest.cpp | 4 ++-- .../vts/functional/KeyMintAidlTestBase.cpp | 24 ++++++++++++++++--- .../aidl/vts/functional/KeyMintAidlTestBase.h | 2 +- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp index a868c966e6..6d289ecda8 100644 --- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp +++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp @@ -961,10 +961,7 @@ TEST_P(AttestKeyTest, EcdsaAttestationMismatchID) { vector attested_key_cert_chain; auto result = GenerateKey(builder, attest_key, &attested_key_blob, &attested_key_characteristics, &attested_key_cert_chain); - - ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG) - << "result = " << result; - device_id_attestation_vsr_check(result); + device_id_attestation_check_acceptable_error(invalid_tag.tag, result); } CheckedDeleteKey(&attest_key.keyBlob); } @@ -1026,8 +1023,6 @@ TEST_P(AttestKeyTest, SecondIMEIAttestationIDSuccess) { ASSERT_EQ(result, ErrorCode::OK); - device_id_attestation_vsr_check(result); - CheckedDeleteKey(&attested_key_blob); AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics); @@ -1107,8 +1102,6 @@ TEST_P(AttestKeyTest, MultipleIMEIAttestationIDSuccess) { ASSERT_EQ(result, ErrorCode::OK); - device_id_attestation_vsr_check(result); - CheckedDeleteKey(&attested_key_blob); AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics); diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp index 55bb5b4fab..8e9adedf5c 100644 --- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp +++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp @@ -374,8 +374,8 @@ TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) { // Add the tag that doesn't match the local device's real ID. builder.push_back(invalid_tag); auto result = GenerateKey(builder, &key_blob, &key_characteristics); - ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG); - device_id_attestation_vsr_check(result); + + device_id_attestation_check_acceptable_error(invalid_tag.tag, result); } } diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index a8ea407e44..a8b1d06f47 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -2153,14 +2153,32 @@ void p256_pub_key(const vector& coseKeyData, EVP_PKEY_Ptr* signingKey) *signingKey = std::move(pubKey); } -void device_id_attestation_vsr_check(const ErrorCode& result) { - if (get_vsr_api_level() > __ANDROID_API_T__) { - ASSERT_FALSE(result == ErrorCode::INVALID_TAG) +// Check the error code from an attempt to perform device ID attestation with an invalid value. +void device_id_attestation_check_acceptable_error(Tag tag, const ErrorCode& result) { + // Standard/default error code for ID mismatch. + if (result == ErrorCode::CANNOT_ATTEST_IDS) { + return; + } + + // Depending on the situation, other error codes may be acceptable. First, allow older + // implementations to use INVALID_TAG. + if (result == ErrorCode::INVALID_TAG) { + ASSERT_FALSE(get_vsr_api_level() > __ANDROID_API_T__) << "It is a specification violation for INVALID_TAG to be returned due to ID " << "mismatch in a Device ID Attestation call. INVALID_TAG is only intended to " << "be used for a case where updateAad() is called after update(). As of " << "VSR-14, this is now enforced as an error."; } + + // If the device is not a phone, it will not have IMEI/MEID values available. Allow + // ATTESTATION_IDS_NOT_PROVISIONED in this case. + if (result == ErrorCode::ATTESTATION_IDS_NOT_PROVISIONED) { + ASSERT_TRUE((tag == TAG_ATTESTATION_ID_IMEI || tag == TAG_ATTESTATION_ID_MEID || + tag == TAG_ATTESTATION_ID_SECOND_IMEI)) + << "incorrect error code on attestation ID mismatch"; + } + ADD_FAILURE() << "Error code " << result + << " returned on attestation ID mismatch, should be CANNOT_ATTEST_IDS"; } // Check whether the given named feature is available. diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h index 30ac452bab..6318514d6b 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h @@ -421,7 +421,7 @@ vector make_name_from_str(const string& name); void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode, vector* payload_value); void p256_pub_key(const vector& coseKeyData, EVP_PKEY_Ptr* signingKey); -void device_id_attestation_vsr_check(const ErrorCode& result); +void device_id_attestation_check_acceptable_error(Tag tag, const ErrorCode& result); bool check_feature(const std::string& name); AuthorizationSet HwEnforcedAuthorizations(const vector& key_characteristics); From 35621098def02699788da6775ba56066d650a3f2 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Tue, 4 Jul 2023 13:08:30 +0100 Subject: [PATCH 039/152] Fix attestation error checks Avoid the ADD_FAILURE at the end if attestion ID failure uses an allowed return code. Test: VtsAidlKeyMintTargetTest Bug: 286733800 (cherry picked from https://android-review.googlesource.com/q/commit:810fbcffed8e86a3b53e8212ce4fdb64971d812f) Change-Id: I0dcac312ac4516a078b2742721e3a19074da52b1 Merged-In: I0dcac312ac4516a078b2742721e3a19074da52b1 --- .../vts/functional/KeyMintAidlTestBase.cpp | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index a8b1d06f47..284af941b1 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -2155,30 +2155,26 @@ void p256_pub_key(const vector& coseKeyData, EVP_PKEY_Ptr* signingKey) // Check the error code from an attempt to perform device ID attestation with an invalid value. void device_id_attestation_check_acceptable_error(Tag tag, const ErrorCode& result) { - // Standard/default error code for ID mismatch. if (result == ErrorCode::CANNOT_ATTEST_IDS) { - return; - } - - // Depending on the situation, other error codes may be acceptable. First, allow older - // implementations to use INVALID_TAG. - if (result == ErrorCode::INVALID_TAG) { + // Standard/default error code for ID mismatch. + } else if (result == ErrorCode::INVALID_TAG) { + // Depending on the situation, other error codes may be acceptable. First, allow older + // implementations to use INVALID_TAG. ASSERT_FALSE(get_vsr_api_level() > __ANDROID_API_T__) << "It is a specification violation for INVALID_TAG to be returned due to ID " << "mismatch in a Device ID Attestation call. INVALID_TAG is only intended to " << "be used for a case where updateAad() is called after update(). As of " << "VSR-14, this is now enforced as an error."; - } - - // If the device is not a phone, it will not have IMEI/MEID values available. Allow - // ATTESTATION_IDS_NOT_PROVISIONED in this case. - if (result == ErrorCode::ATTESTATION_IDS_NOT_PROVISIONED) { + } else if (result == ErrorCode::ATTESTATION_IDS_NOT_PROVISIONED) { + // If the device is not a phone, it will not have IMEI/MEID values available. Allow + // ATTESTATION_IDS_NOT_PROVISIONED in this case. ASSERT_TRUE((tag == TAG_ATTESTATION_ID_IMEI || tag == TAG_ATTESTATION_ID_MEID || tag == TAG_ATTESTATION_ID_SECOND_IMEI)) << "incorrect error code on attestation ID mismatch"; + } else { + ADD_FAILURE() << "Error code " << result + << " returned on attestation ID mismatch, should be CANNOT_ATTEST_IDS"; } - ADD_FAILURE() << "Error code " << result - << " returned on attestation ID mismatch, should be CANNOT_ATTEST_IDS"; } // Check whether the given named feature is available. From fda1197d79cabfd98d70850bf374f32e4aebcd16 Mon Sep 17 00:00:00 2001 From: Yu Shan Date: Fri, 23 Jun 2023 17:43:17 -0700 Subject: [PATCH 040/152] Pass property set error to subscribed clients. Pass the async property set error generated by VehicleHardware layer to subscribed clients Test: atest DefaultVehicleHalTest Bug: 286384730 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7b1448edcfd3f88365932e2d94659952444aae2b) Merged-In: Iadd92e1c0c741ad6450a0508fe9e6301bdfe66c5 Change-Id: Iadd92e1c0c741ad6450a0508fe9e6301bdfe66c5 --- .../hardware/src/FakeVehicleHardware.cpp | 1 + .../aidl/impl/vhal/include/ConnectedClient.h | 8 ++- .../impl/vhal/include/DefaultVehicleHal.h | 6 +- .../impl/vhal/include/SubscriptionManager.h | 6 ++ .../aidl/impl/vhal/src/ConnectedClient.cpp | 31 +++++++++- .../aidl/impl/vhal/src/DefaultVehicleHal.cpp | 37 +++++++++--- .../impl/vhal/src/SubscriptionManager.cpp | 27 +++++++++ .../impl/vhal/test/DefaultVehicleHalTest.cpp | 58 +++++++++++++++++++ .../impl/vhal/test/MockVehicleCallback.cpp | 20 ++++++- .../aidl/impl/vhal/test/MockVehicleCallback.h | 5 ++ .../impl/vhal/test/MockVehicleHardware.cpp | 11 +++- .../aidl/impl/vhal/test/MockVehicleHardware.h | 2 + 12 files changed, 198 insertions(+), 14 deletions(-) diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp index 3f5e4c4273..46c67a517a 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp @@ -1808,6 +1808,7 @@ void FakeVehicleHardware::registerOnPropertyChangeEvent( void FakeVehicleHardware::registerOnPropertySetErrorEvent( std::unique_ptr callback) { + // In FakeVehicleHardware, we will never use mOnPropertySetErrorCallback. if (mOnPropertySetErrorCallback != nullptr) { ALOGE("registerOnPropertySetErrorEvent must only be called once"); return; diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h index 2e7298ff0b..b3f4a0f722 100644 --- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h +++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h @@ -107,12 +107,18 @@ class SubscriptionClient final : public ConnectedClient { // Gets the callback to be called when the request for this client has finished. std::shared_ptr getResultCallback(); - // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent} + // Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent} // callback. static void sendUpdatedValues( CallbackType callback, std::vector&& updatedValues); + // Marshals the set property error events into largeParcelable and sends it through + // {@code onPropertySetError} callback. + static void sendPropertySetErrors( + CallbackType callback, + std::vector&& + vehiclePropErrors); protected: // Gets the callback to be called when the request for this client has timeout. diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h index 2c2cf1a5bd..74ad7eaf3e 100644 --- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h +++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h @@ -249,10 +249,14 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi const CallbackType& callback, std::shared_ptr pendingRequestPool); static void onPropertyChangeEvent( - std::weak_ptr subscriptionManager, + const std::weak_ptr& subscriptionManager, const std::vector& updatedValues); + static void onPropertySetErrorEvent( + const std::weak_ptr& subscriptionManager, + const std::vector& errorEvents); + static void checkHealth(IVehicleHardware* hardware, std::weak_ptr subscriptionManager); diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h index 14799d9f84..301d56c270 100644 --- a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h +++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h @@ -99,6 +99,12 @@ class SubscriptionManager final { const std::vector& updatedValues); + // For a list of set property error events, returns a map that maps clients subscribing to the + // properties to a list of errors for each client. + std::unordered_map> + getSubscribedClientsForErrorEvents(const std::vector& errorEvents); + // Checks whether the sample rate is valid. static bool checkSampleRateHz(float sampleRateHz); diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp index 81d231c87f..fb23a25047 100644 --- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp +++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp @@ -38,6 +38,8 @@ using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback; using ::aidl::android::hardware::automotive::vehicle::SetValueResult; using ::aidl::android::hardware::automotive::vehicle::SetValueResults; using ::aidl::android::hardware::automotive::vehicle::StatusCode; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropError; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues; using ::android::base::Result; @@ -300,7 +302,34 @@ void SubscriptionClient::sendUpdatedValues(std::shared_ptr cal if (ScopedAStatus callbackStatus = callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount); !callbackStatus.isOk()) { - ALOGE("subscribe: failed to call UpdateValues callback, client ID: %p, error: %s, " + ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, " + "exception: %d, service specific error: %d", + callback->asBinder().get(), callbackStatus.getMessage(), + callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError()); + } +} + +void SubscriptionClient::sendPropertySetErrors(std::shared_ptr callback, + std::vector&& vehiclePropErrors) { + if (vehiclePropErrors.empty()) { + return; + } + + VehiclePropErrors vehiclePropErrorsLargeParcelable; + ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors), + &vehiclePropErrorsLargeParcelable); + if (!status.isOk()) { + int statusCode = status.getServiceSpecificError(); + ALOGE("subscribe: failed to marshal result into large parcelable, error: " + "%s, code: %d", + status.getMessage(), statusCode); + return; + } + + if (ScopedAStatus callbackStatus = + callback->onPropertySetError(vehiclePropErrorsLargeParcelable); + !callbackStatus.isOk()) { + ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, " "exception: %d, service specific error: %d", callback->asBinder().get(), callbackStatus.getMessage(), callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError()); diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp index 98cfc398af..0d5c070c54 100644 --- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp +++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp @@ -144,6 +144,11 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr vehicleHa [subscriptionManagerCopy](std::vector updatedValues) { onPropertyChangeEvent(subscriptionManagerCopy, updatedValues); })); + mVehicleHardware->registerOnPropertySetErrorEvent( + std::make_unique( + [subscriptionManagerCopy](std::vector errorEvents) { + onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents); + })); // Register heartbeat event. mRecurrentAction = std::make_shared>( @@ -177,7 +182,7 @@ DefaultVehicleHal::~DefaultVehicleHal() { } void DefaultVehicleHal::onPropertyChangeEvent( - std::weak_ptr subscriptionManager, + const std::weak_ptr& subscriptionManager, const std::vector& updatedValues) { auto manager = subscriptionManager.lock(); if (manager == nullptr) { @@ -194,6 +199,20 @@ void DefaultVehicleHal::onPropertyChangeEvent( } } +void DefaultVehicleHal::onPropertySetErrorEvent( + const std::weak_ptr& subscriptionManager, + const std::vector& errorEvents) { + auto manager = subscriptionManager.lock(); + if (manager == nullptr) { + ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending"); + return; + } + auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents); + for (auto& [callback, vehiclePropErrors] : vehiclePropErrorsByClient) { + SubscriptionClient::sendPropertySetErrors(callback, std::move(vehiclePropErrors)); + } +} + template std::shared_ptr DefaultVehicleHal::getOrCreateClient( std::unordered_map>* clients, @@ -692,15 +711,19 @@ ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback, // Create a new SubscriptionClient if there isn't an existing one. mSubscriptionClients->maybeAddClient(callback); - // Since we have already check the sample rates, the following functions must succeed. if (!onChangeSubscriptions.empty()) { - return toScopedAStatus(mSubscriptionManager->subscribe(callback, onChangeSubscriptions, - /*isContinuousProperty=*/false)); + auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions, + /*isContinuousProperty=*/false); + if (!result.ok()) { + return toScopedAStatus(result); + } } if (!continuousSubscriptions.empty()) { - return toScopedAStatus(mSubscriptionManager->subscribe(callback, - continuousSubscriptions, - /*isContinuousProperty=*/true)); + auto result = mSubscriptionManager->subscribe(callback, continuousSubscriptions, + /*isContinuousProperty=*/true); + if (!result.ok()) { + return toScopedAStatus(result); + } } } return ScopedAStatus::ok(); diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp index bba730f6f4..1f2690e340 100644 --- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp +++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp @@ -36,6 +36,7 @@ constexpr float ONE_SECOND_IN_NANO = 1'000'000'000.; using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback; using ::aidl::android::hardware::automotive::vehicle::StatusCode; using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropError; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; using ::android::base::Error; using ::android::base::Result; @@ -269,6 +270,32 @@ SubscriptionManager::getSubscribedClients(const std::vector& u return clients; } +std::unordered_map, std::vector> +SubscriptionManager::getSubscribedClientsForErrorEvents( + const std::vector& errorEvents) { + std::scoped_lock lockGuard(mLock); + std::unordered_map, std::vector> clients; + + for (const auto& errorEvent : errorEvents) { + PropIdAreaId propIdAreaId{ + .propId = errorEvent.propId, + .areaId = errorEvent.areaId, + }; + if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) { + continue; + } + + for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) { + clients[client].push_back({ + .propId = errorEvent.propId, + .areaId = errorEvent.areaId, + .errorCode = errorEvent.errorCode, + }); + } + } + return clients; +} + bool SubscriptionManager::isEmpty() { std::scoped_lock lockGuard(mLock); return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty(); diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp index 05e569ab8a..96b71f0af0 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp +++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp @@ -62,6 +62,7 @@ using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions; using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow; using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig; using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropError; using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors; using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess; @@ -1653,6 +1654,63 @@ TEST_F(DefaultVehicleHalTest, testDumpCallerShouldNotDump) { ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos); } +TEST_F(DefaultVehicleHalTest, testOnPropertySetErrorEvent) { + std::vector options = { + { + .propId = GLOBAL_ON_CHANGE_PROP, + .areaIds = {0}, + }, + { + .propId = GLOBAL_CONTINUOUS_PROP, + .areaIds = {0}, + .sampleRate = 1, + }, + }; + auto status = getClient()->subscribe(getCallbackClient(), options, 0); + ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage(); + std::vector errorEvents = { + { + .propId = GLOBAL_ON_CHANGE_PROP, + .areaId = 0, + .errorCode = StatusCode::INTERNAL_ERROR, + }, + { + .propId = GLOBAL_ON_CHANGE_PROP, + .areaId = 0, + .errorCode = StatusCode::ACCESS_DENIED, + }, + { + .propId = GLOBAL_CONTINUOUS_PROP, + .areaId = 0, + .errorCode = StatusCode::INVALID_ARG, + }, + }; + std::vector expectedResults = { + { + .propId = GLOBAL_ON_CHANGE_PROP, + .areaId = 0, + .errorCode = StatusCode::INTERNAL_ERROR, + }, + { + .propId = GLOBAL_ON_CHANGE_PROP, + .areaId = 0, + .errorCode = StatusCode::ACCESS_DENIED, + }, + { + .propId = GLOBAL_CONTINUOUS_PROP, + .areaId = 0, + .errorCode = StatusCode::INVALID_ARG, + }, + }; + getHardware()->sendOnPropertySetErrorEvent(errorEvents); + + ASSERT_EQ(getCallback()->countOnPropertySetErrorResults(), 1u); + auto maybeVehiclePropErrors = getCallback()->nextOnPropertySetErrorResults(); + ASSERT_TRUE(maybeVehiclePropErrors.has_value()); + const auto& vehiclePropErrors = maybeVehiclePropErrors.value(); + ASSERT_THAT(vehiclePropErrors.payloads, UnorderedElementsAreArray(expectedResults)); +} + } // namespace vehicle } // namespace automotive } // namespace hardware diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp index f51ce5cb39..54fede1f3d 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp @@ -81,8 +81,14 @@ ScopedAStatus MockVehicleCallback::onPropertyEvent(const VehiclePropValues& resu return result; } -ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) { - return ScopedAStatus::ok(); +ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors& results) { + ScopedAStatus result; + { + std::scoped_lock lockGuard(mLock); + result = storeResults(results, &mOnPropertySetErrorResults); + } + mCond.notify_all(); + return result; } std::optional MockVehicleCallback::nextGetValueResults() { @@ -105,6 +111,16 @@ size_t MockVehicleCallback::countOnPropertyEventResults() { return mOnPropertyEventResults.size(); } +std::optional MockVehicleCallback::nextOnPropertySetErrorResults() { + std::scoped_lock lockGuard(mLock); + return pop(mOnPropertySetErrorResults); +} + +size_t MockVehicleCallback::countOnPropertySetErrorResults() { + std::scoped_lock lockGuard(mLock); + return mOnPropertySetErrorResults.size(); +} + bool MockVehicleCallback::waitForSetValueResults(size_t size, size_t timeoutInNano) { std::unique_lock lk(mLock); return mCond.wait_for(lk, std::chrono::nanoseconds(timeoutInNano), [this, size] { diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h index f17b273b18..1545eae08f 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h @@ -63,6 +63,9 @@ class MockVehicleCallback final nextSetValueResults(); std::optional nextOnPropertyEventResults(); + size_t countOnPropertySetErrorResults(); + std::optional + nextOnPropertySetErrorResults(); size_t countOnPropertyEventResults(); bool waitForSetValueResults(size_t size, size_t timeoutInNano); bool waitForGetValueResults(size_t size, size_t timeoutInNano); @@ -77,6 +80,8 @@ class MockVehicleCallback final std::list mOnPropertyEventResults GUARDED_BY(mLock); int32_t mSharedMemoryFileCount GUARDED_BY(mLock); + std::list + mOnPropertySetErrorResults GUARDED_BY(mLock); }; } // namespace vehicle diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp index 4df4e1aea5..ba0d33dfde 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp @@ -131,8 +131,9 @@ void MockVehicleHardware::registerOnPropertyChangeEvent( } void MockVehicleHardware::registerOnPropertySetErrorEvent( - std::unique_ptr) { - // TODO(b/200737967): mock this. + std::unique_ptr callback) { + std::scoped_lock lockGuard(mLock); + mPropertySetErrorCallback = std::move(callback); } void MockVehicleHardware::setPropertyConfigs(const std::vector& configs) { @@ -254,6 +255,12 @@ template StatusCode MockVehicleHardware::handleRequestsLocked>* storedRequests, std::list>* storedResponses) const; +void MockVehicleHardware::sendOnPropertySetErrorEvent( + const std::vector& errorEvents) { + std::scoped_lock lockGuard(mLock); + (*mPropertySetErrorCallback)(errorEvents); +} + } // namespace vehicle } // namespace automotive } // namespace hardware diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h index 743841c216..46b30b9405 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h @@ -85,6 +85,7 @@ class MockVehicleHardware final : public IVehicleHardware { aidl::android::hardware::automotive::vehicle::StatusCode status); void setSleepTime(int64_t timeInNano); void setDumpResult(DumpResult result); + void sendOnPropertySetErrorEvent(const std::vector& errorEvents); private: mutable std::mutex mLock; @@ -104,6 +105,7 @@ class MockVehicleHardware final : public IVehicleHardware { mStatusByFunctions GUARDED_BY(mLock); int64_t mSleepTime GUARDED_BY(mLock) = 0; std::unique_ptr mPropertyChangeCallback GUARDED_BY(mLock); + std::unique_ptr mPropertySetErrorCallback GUARDED_BY(mLock); std::function, const std::vector&)> From 3a34c72b61cd3aef999e4dae84eaedcad91dc86e Mon Sep 17 00:00:00 2001 From: Gabriel Biren Date: Tue, 11 Jul 2023 19:59:22 +0000 Subject: [PATCH 041/152] Represent NAN callback events as a bitmap to better handle overlapping events. Reimplementation of aosp/2473685 for the AIDL VTS tests. Bug: 290318208 Test: atest VtsHalWifiNanIfaceTargetTest Change-Id: I1a0e6ab8dd529c10fcec8f26424a7181e7d91568 --- .../functional/wifi_nan_iface_aidl_test.cpp | 171 +++++++----------- 1 file changed, 65 insertions(+), 106 deletions(-) diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp index bebad7ca08..95bcec7029 100644 --- a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp +++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp @@ -76,18 +76,10 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { void TearDown() override { stopWifiService(getInstanceName()); } - // Used as a mechanism to inform the test about data/event callbacks. - inline void notify() { - std::unique_lock lock(mtx_); - count_++; - cv_.notify_one(); - } - enum CallbackType { - INVALID = -2, - ANY_CALLBACK = -1, + INVALID = 0, - NOTIFY_CAPABILITIES_RESPONSE = 0, + NOTIFY_CAPABILITIES_RESPONSE = 1, NOTIFY_ENABLE_RESPONSE, NOTIFY_CONFIG_RESPONSE, NOTIFY_DISABLE_RESPONSE, @@ -128,310 +120,278 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { EVENT_SUSPENSION_MODE_CHANGE, }; + // Used as a mechanism to inform the test about data/event callbacks. + inline void notify(CallbackType callbackType) { + std::unique_lock lock(mtx_); + callback_event_bitmap_ |= (0x1 << callbackType); + cv_.notify_one(); + } + // Test code calls this function to wait for data/event callback. - // Must set callbackType = INVALID before calling this function. + // Must set callback_event_bitmap_ to 0 before calling this function. inline std::cv_status wait(CallbackType waitForCallbackType) { std::unique_lock lock(mtx_); EXPECT_NE(INVALID, waitForCallbackType); std::cv_status status = std::cv_status::no_timeout; auto now = std::chrono::system_clock::now(); - while (count_ == 0) { + while (!(receivedCallback(waitForCallbackType))) { status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); if (status == std::cv_status::timeout) return status; - if (waitForCallbackType != ANY_CALLBACK && callback_type_ != INVALID && - callback_type_ != waitForCallbackType) { - count_--; - } } - count_--; return status; } + inline bool receivedCallback(CallbackType waitForCallbackType) { + return callback_event_bitmap_ & (0x1 << waitForCallbackType); + } + class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback { public: WifiNanIfaceEventCallback(WifiNanIfaceAidlTest& parent) : parent_(parent){}; ::ndk::ScopedAStatus eventClusterEvent(const NanClusterEventInd& event) override { - parent_.callback_type_ = EVENT_CLUSTER_EVENT; parent_.nan_cluster_event_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_CLUSTER_EVENT); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDataPathConfirm(const NanDataPathConfirmInd& event) override { - parent_.callback_type_ = EVENT_DATA_PATH_CONFIRM; parent_.nan_data_path_confirm_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_DATA_PATH_CONFIRM); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDataPathRequest(const NanDataPathRequestInd& event) override { - parent_.callback_type_ = EVENT_DATA_PATH_REQUEST; parent_.nan_data_path_request_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_DATA_PATH_REQUEST); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDataPathScheduleUpdate( const NanDataPathScheduleUpdateInd& event) override { - parent_.callback_type_ = EVENT_DATA_PATH_SCHEDULE_UPDATE; parent_.nan_data_path_schedule_update_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_DATA_PATH_SCHEDULE_UPDATE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDataPathTerminated(int32_t ndpInstanceId) override { - parent_.callback_type_ = EVENT_DATA_PATH_TERMINATED; parent_.ndp_instance_id_ = ndpInstanceId; - parent_.notify(); + parent_.notify(EVENT_DATA_PATH_TERMINATED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDisabled(const NanStatus& status) override { - parent_.callback_type_ = EVENT_DISABLED; parent_.status_ = status; - parent_.notify(); + parent_.notify(EVENT_DISABLED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventFollowupReceived(const NanFollowupReceivedInd& event) override { - parent_.callback_type_ = EVENT_FOLLOWUP_RECEIVED; parent_.nan_followup_received_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_FOLLOWUP_RECEIVED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventMatch(const NanMatchInd& event) override { - parent_.callback_type_ = EVENT_MATCH; parent_.nan_match_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_MATCH); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventMatchExpired(int8_t discoverySessionId, int32_t peerId) override { - parent_.callback_type_ = EVENT_MATCH_EXPIRED; parent_.session_id_ = discoverySessionId; parent_.peer_id_ = peerId; - parent_.notify(); + parent_.notify(EVENT_MATCH_EXPIRED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventPublishTerminated(int8_t sessionId, const NanStatus& status) override { - parent_.callback_type_ = EVENT_PUBLISH_TERMINATED; parent_.session_id_ = sessionId; parent_.status_ = status; - parent_.notify(); + parent_.notify(EVENT_PUBLISH_TERMINATED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventSubscribeTerminated(int8_t sessionId, const NanStatus& status) override { - parent_.callback_type_ = EVENT_SUBSCRIBE_TERMINATED; parent_.session_id_ = sessionId; parent_.status_ = status; - parent_.notify(); + parent_.notify(EVENT_SUBSCRIBE_TERMINATED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventTransmitFollowup(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = EVENT_TRANSMIT_FOLLOWUP; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(EVENT_TRANSMIT_FOLLOWUP); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventPairingConfirm(const NanPairingConfirmInd& event) override { - parent_.callback_type_ = EVENT_PAIRING_CONFIRM; parent_.nan_pairing_confirm_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_PAIRING_CONFIRM); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventPairingRequest(const NanPairingRequestInd& event) override { - parent_.callback_type_ = EVENT_PAIRING_REQUEST; parent_.nan_pairing_request_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_PAIRING_REQUEST); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventBootstrappingConfirm( const NanBootstrappingConfirmInd& event) override { - parent_.callback_type_ = EVENT_BOOTSTRAPPING_CONFIRM; parent_.nan_bootstrapping_confirm_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_BOOTSTRAPPING_CONFIRM); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventBootstrappingRequest( const NanBootstrappingRequestInd& event) override { - parent_.callback_type_ = EVENT_BOOTSTRAPPING_REQUEST; parent_.nan_bootstrapping_request_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_BOOTSTRAPPING_REQUEST); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventSuspensionModeChanged( const NanSuspensionModeChangeInd& event) override { - parent_.callback_type_ = EVENT_SUSPENSION_MODE_CHANGE; parent_.nan_suspension_mode_change_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_SUSPENSION_MODE_CHANGE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyCapabilitiesResponse( char16_t id, const NanStatus& status, const NanCapabilities& capabilities) override { - parent_.callback_type_ = NOTIFY_CAPABILITIES_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.capabilities_ = capabilities; - parent_.notify(); + parent_.notify(NOTIFY_CAPABILITIES_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyConfigResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_CONFIG_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_CONFIG_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyCreateDataInterfaceResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_CREATE_DATA_INTERFACE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyDeleteDataInterfaceResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_DELETE_DATA_INTERFACE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyDisableResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_DISABLE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_DISABLE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyEnableResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_ENABLE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_ENABLE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyInitiateDataPathResponse(char16_t id, const NanStatus& status, int32_t ndpInstanceId) override { - parent_.callback_type_ = NOTIFY_INITIATE_DATA_PATH_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.ndp_instance_id_ = ndpInstanceId; - parent_.notify(); + parent_.notify(NOTIFY_INITIATE_DATA_PATH_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyRespondToDataPathIndicationResponse( char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyStartPublishResponse(char16_t id, const NanStatus& status, int8_t sessionId) override { - parent_.callback_type_ = NOTIFY_START_PUBLISH_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.session_id_ = sessionId; - parent_.notify(); + parent_.notify(NOTIFY_START_PUBLISH_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyStartSubscribeResponse(char16_t id, const NanStatus& status, int8_t sessionId) override { - parent_.callback_type_ = NOTIFY_START_SUBSCRIBE_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.session_id_ = sessionId; - parent_.notify(); + parent_.notify(NOTIFY_START_SUBSCRIBE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyStopPublishResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_STOP_PUBLISH_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_STOP_PUBLISH_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyStopSubscribeResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_STOP_SUBSCRIBE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_STOP_SUBSCRIBE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyTerminateDataPathResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_TERMINATE_DATA_PATH_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_TERMINATE_DATA_PATH_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifySuspendResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_SUSPEND_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_SUSPEND_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyResumeResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_RESUME_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_RESUME_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyTransmitFollowupResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyInitiatePairingResponse(char16_t id, const NanStatus& status, int32_t pairingInstanceId) override { - parent_.callback_type_ = NOTIFY_INITIATE_PAIRING_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.pairing_instance_id_ = pairingInstanceId; - parent_.notify(); + parent_.notify(NOTIFY_INITIATE_PAIRING_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyRespondToPairingIndicationResponse( char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyInitiateBootstrappingResponse( char16_t id, const NanStatus& status, int32_t bootstrapppingInstanceId) override { - parent_.callback_type_ = NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.bootstrappping_instance_id_ = bootstrapppingInstanceId; - parent_.notify(); + parent_.notify(NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyRespondToBootstrappingIndicationResponse( char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyTerminatePairingResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_TERMINATE_PAIRING_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_TERMINATE_PAIRING_RESPONSE); return ndk::ScopedAStatus::ok(); } @@ -441,7 +401,7 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { protected: std::shared_ptr wifi_nan_iface_; - CallbackType callback_type_; + uint64_t callback_event_bitmap_; uint16_t id_; uint8_t session_id_; uint32_t ndp_instance_id_; @@ -468,7 +428,6 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { // synchronization objects std::mutex mtx_; std::condition_variable cv_; - int count_ = 0; }; /* @@ -488,7 +447,7 @@ TEST_P(WifiNanIfaceAidlTest, FailOnIfaceInvalid) { */ TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; NanEnableRequest nanEnableRequest = {}; NanConfigRequestSupplemental nanConfigRequestSupp = {}; auto status = @@ -498,7 +457,7 @@ TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) { // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); - ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE)); ASSERT_EQ(id_, inputCmdId); ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS); } @@ -509,7 +468,7 @@ TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) { */ TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; NanConfigRequest nanConfigRequest = {}; NanConfigRequestSupplemental nanConfigRequestSupp = {}; auto status = @@ -520,7 +479,7 @@ TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) { // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE)); - ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_CONFIG_RESPONSE)); ASSERT_EQ(id_, inputCmdId); ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS); } @@ -561,12 +520,12 @@ TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidShimArgs) { */ TEST_P(WifiNanIfaceAidlTest, NotifyCapabilitiesResponse) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; EXPECT_TRUE(wifi_nan_iface_->getCapabilitiesRequest(inputCmdId).isOk()); // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE)); - ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_CAPABILITIES_RESPONSE)); ASSERT_EQ(id_, inputCmdId); ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); @@ -654,14 +613,14 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) { nanConfigRequestSupp.numberOfSpatialStreamsInDiscovery = 0; nanConfigRequestSupp.enableDiscoveryWindowEarlyTermination = false; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; auto status = wifi_nan_iface_->enableRequest(inputCmdId, req, nanConfigRequestSupp); if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { ASSERT_TRUE(status.isOk()); // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); - ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE)); ASSERT_EQ(id_, inputCmdId); ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); } @@ -688,7 +647,7 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) { // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE)); - ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_START_PUBLISH_RESPONSE)); ASSERT_EQ(id_, inputCmdId + 1); ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); } @@ -699,7 +658,7 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) { */ TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; NanRespondToDataPathIndicationRequest nanRespondToDataPathIndicationRequest = {}; nanRespondToDataPathIndicationRequest.ifaceName = "AwareInterfaceNameTooLong"; auto status = wifi_nan_iface_->respondToDataPathIndicationRequest( @@ -716,7 +675,7 @@ TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) { */ TEST_P(WifiNanIfaceAidlTest, InitiateDataPathRequest_InvalidArgs) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; NanInitiateDataPathRequest nanInitiateDataPathRequest = {}; nanInitiateDataPathRequest.ifaceName = "AwareInterfaceNameTooLong"; auto status = wifi_nan_iface_->initiateDataPathRequest(inputCmdId, nanInitiateDataPathRequest); From 3f7bfd2dc5a079548a98f217ef7b76396531b96e Mon Sep 17 00:00:00 2001 From: Gabriel Biren Date: Tue, 11 Jul 2023 19:59:22 +0000 Subject: [PATCH 042/152] Represent NAN callback events as a bitmap to better handle overlapping events. Reimplementation of aosp/2473685 for the AIDL VTS tests. Bug: 290318208 Test: atest VtsHalWifiNanIfaceTargetTest Change-Id: I1a0e6ab8dd529c10fcec8f26424a7181e7d91568 --- .../functional/wifi_nan_iface_aidl_test.cpp | 171 +++++++----------- 1 file changed, 65 insertions(+), 106 deletions(-) diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp index bebad7ca08..95bcec7029 100644 --- a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp +++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp @@ -76,18 +76,10 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { void TearDown() override { stopWifiService(getInstanceName()); } - // Used as a mechanism to inform the test about data/event callbacks. - inline void notify() { - std::unique_lock lock(mtx_); - count_++; - cv_.notify_one(); - } - enum CallbackType { - INVALID = -2, - ANY_CALLBACK = -1, + INVALID = 0, - NOTIFY_CAPABILITIES_RESPONSE = 0, + NOTIFY_CAPABILITIES_RESPONSE = 1, NOTIFY_ENABLE_RESPONSE, NOTIFY_CONFIG_RESPONSE, NOTIFY_DISABLE_RESPONSE, @@ -128,310 +120,278 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { EVENT_SUSPENSION_MODE_CHANGE, }; + // Used as a mechanism to inform the test about data/event callbacks. + inline void notify(CallbackType callbackType) { + std::unique_lock lock(mtx_); + callback_event_bitmap_ |= (0x1 << callbackType); + cv_.notify_one(); + } + // Test code calls this function to wait for data/event callback. - // Must set callbackType = INVALID before calling this function. + // Must set callback_event_bitmap_ to 0 before calling this function. inline std::cv_status wait(CallbackType waitForCallbackType) { std::unique_lock lock(mtx_); EXPECT_NE(INVALID, waitForCallbackType); std::cv_status status = std::cv_status::no_timeout; auto now = std::chrono::system_clock::now(); - while (count_ == 0) { + while (!(receivedCallback(waitForCallbackType))) { status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); if (status == std::cv_status::timeout) return status; - if (waitForCallbackType != ANY_CALLBACK && callback_type_ != INVALID && - callback_type_ != waitForCallbackType) { - count_--; - } } - count_--; return status; } + inline bool receivedCallback(CallbackType waitForCallbackType) { + return callback_event_bitmap_ & (0x1 << waitForCallbackType); + } + class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback { public: WifiNanIfaceEventCallback(WifiNanIfaceAidlTest& parent) : parent_(parent){}; ::ndk::ScopedAStatus eventClusterEvent(const NanClusterEventInd& event) override { - parent_.callback_type_ = EVENT_CLUSTER_EVENT; parent_.nan_cluster_event_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_CLUSTER_EVENT); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDataPathConfirm(const NanDataPathConfirmInd& event) override { - parent_.callback_type_ = EVENT_DATA_PATH_CONFIRM; parent_.nan_data_path_confirm_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_DATA_PATH_CONFIRM); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDataPathRequest(const NanDataPathRequestInd& event) override { - parent_.callback_type_ = EVENT_DATA_PATH_REQUEST; parent_.nan_data_path_request_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_DATA_PATH_REQUEST); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDataPathScheduleUpdate( const NanDataPathScheduleUpdateInd& event) override { - parent_.callback_type_ = EVENT_DATA_PATH_SCHEDULE_UPDATE; parent_.nan_data_path_schedule_update_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_DATA_PATH_SCHEDULE_UPDATE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDataPathTerminated(int32_t ndpInstanceId) override { - parent_.callback_type_ = EVENT_DATA_PATH_TERMINATED; parent_.ndp_instance_id_ = ndpInstanceId; - parent_.notify(); + parent_.notify(EVENT_DATA_PATH_TERMINATED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventDisabled(const NanStatus& status) override { - parent_.callback_type_ = EVENT_DISABLED; parent_.status_ = status; - parent_.notify(); + parent_.notify(EVENT_DISABLED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventFollowupReceived(const NanFollowupReceivedInd& event) override { - parent_.callback_type_ = EVENT_FOLLOWUP_RECEIVED; parent_.nan_followup_received_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_FOLLOWUP_RECEIVED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventMatch(const NanMatchInd& event) override { - parent_.callback_type_ = EVENT_MATCH; parent_.nan_match_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_MATCH); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventMatchExpired(int8_t discoverySessionId, int32_t peerId) override { - parent_.callback_type_ = EVENT_MATCH_EXPIRED; parent_.session_id_ = discoverySessionId; parent_.peer_id_ = peerId; - parent_.notify(); + parent_.notify(EVENT_MATCH_EXPIRED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventPublishTerminated(int8_t sessionId, const NanStatus& status) override { - parent_.callback_type_ = EVENT_PUBLISH_TERMINATED; parent_.session_id_ = sessionId; parent_.status_ = status; - parent_.notify(); + parent_.notify(EVENT_PUBLISH_TERMINATED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventSubscribeTerminated(int8_t sessionId, const NanStatus& status) override { - parent_.callback_type_ = EVENT_SUBSCRIBE_TERMINATED; parent_.session_id_ = sessionId; parent_.status_ = status; - parent_.notify(); + parent_.notify(EVENT_SUBSCRIBE_TERMINATED); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventTransmitFollowup(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = EVENT_TRANSMIT_FOLLOWUP; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(EVENT_TRANSMIT_FOLLOWUP); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventPairingConfirm(const NanPairingConfirmInd& event) override { - parent_.callback_type_ = EVENT_PAIRING_CONFIRM; parent_.nan_pairing_confirm_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_PAIRING_CONFIRM); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventPairingRequest(const NanPairingRequestInd& event) override { - parent_.callback_type_ = EVENT_PAIRING_REQUEST; parent_.nan_pairing_request_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_PAIRING_REQUEST); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventBootstrappingConfirm( const NanBootstrappingConfirmInd& event) override { - parent_.callback_type_ = EVENT_BOOTSTRAPPING_CONFIRM; parent_.nan_bootstrapping_confirm_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_BOOTSTRAPPING_CONFIRM); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventBootstrappingRequest( const NanBootstrappingRequestInd& event) override { - parent_.callback_type_ = EVENT_BOOTSTRAPPING_REQUEST; parent_.nan_bootstrapping_request_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_BOOTSTRAPPING_REQUEST); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus eventSuspensionModeChanged( const NanSuspensionModeChangeInd& event) override { - parent_.callback_type_ = EVENT_SUSPENSION_MODE_CHANGE; parent_.nan_suspension_mode_change_ind_ = event; - parent_.notify(); + parent_.notify(EVENT_SUSPENSION_MODE_CHANGE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyCapabilitiesResponse( char16_t id, const NanStatus& status, const NanCapabilities& capabilities) override { - parent_.callback_type_ = NOTIFY_CAPABILITIES_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.capabilities_ = capabilities; - parent_.notify(); + parent_.notify(NOTIFY_CAPABILITIES_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyConfigResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_CONFIG_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_CONFIG_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyCreateDataInterfaceResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_CREATE_DATA_INTERFACE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyDeleteDataInterfaceResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_DELETE_DATA_INTERFACE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyDisableResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_DISABLE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_DISABLE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyEnableResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_ENABLE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_ENABLE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyInitiateDataPathResponse(char16_t id, const NanStatus& status, int32_t ndpInstanceId) override { - parent_.callback_type_ = NOTIFY_INITIATE_DATA_PATH_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.ndp_instance_id_ = ndpInstanceId; - parent_.notify(); + parent_.notify(NOTIFY_INITIATE_DATA_PATH_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyRespondToDataPathIndicationResponse( char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyStartPublishResponse(char16_t id, const NanStatus& status, int8_t sessionId) override { - parent_.callback_type_ = NOTIFY_START_PUBLISH_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.session_id_ = sessionId; - parent_.notify(); + parent_.notify(NOTIFY_START_PUBLISH_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyStartSubscribeResponse(char16_t id, const NanStatus& status, int8_t sessionId) override { - parent_.callback_type_ = NOTIFY_START_SUBSCRIBE_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.session_id_ = sessionId; - parent_.notify(); + parent_.notify(NOTIFY_START_SUBSCRIBE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyStopPublishResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_STOP_PUBLISH_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_STOP_PUBLISH_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyStopSubscribeResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_STOP_SUBSCRIBE_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_STOP_SUBSCRIBE_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyTerminateDataPathResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_TERMINATE_DATA_PATH_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_TERMINATE_DATA_PATH_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifySuspendResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_SUSPEND_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_SUSPEND_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyResumeResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_RESUME_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_RESUME_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyTransmitFollowupResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyInitiatePairingResponse(char16_t id, const NanStatus& status, int32_t pairingInstanceId) override { - parent_.callback_type_ = NOTIFY_INITIATE_PAIRING_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.pairing_instance_id_ = pairingInstanceId; - parent_.notify(); + parent_.notify(NOTIFY_INITIATE_PAIRING_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyRespondToPairingIndicationResponse( char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyInitiateBootstrappingResponse( char16_t id, const NanStatus& status, int32_t bootstrapppingInstanceId) override { - parent_.callback_type_ = NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE; parent_.id_ = id; parent_.status_ = status; parent_.bootstrappping_instance_id_ = bootstrapppingInstanceId; - parent_.notify(); + parent_.notify(NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyRespondToBootstrappingIndicationResponse( char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE); return ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus notifyTerminatePairingResponse(char16_t id, const NanStatus& status) override { - parent_.callback_type_ = NOTIFY_TERMINATE_PAIRING_RESPONSE; parent_.id_ = id; parent_.status_ = status; - parent_.notify(); + parent_.notify(NOTIFY_TERMINATE_PAIRING_RESPONSE); return ndk::ScopedAStatus::ok(); } @@ -441,7 +401,7 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { protected: std::shared_ptr wifi_nan_iface_; - CallbackType callback_type_; + uint64_t callback_event_bitmap_; uint16_t id_; uint8_t session_id_; uint32_t ndp_instance_id_; @@ -468,7 +428,6 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { // synchronization objects std::mutex mtx_; std::condition_variable cv_; - int count_ = 0; }; /* @@ -488,7 +447,7 @@ TEST_P(WifiNanIfaceAidlTest, FailOnIfaceInvalid) { */ TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; NanEnableRequest nanEnableRequest = {}; NanConfigRequestSupplemental nanConfigRequestSupp = {}; auto status = @@ -498,7 +457,7 @@ TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) { // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); - ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE)); ASSERT_EQ(id_, inputCmdId); ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS); } @@ -509,7 +468,7 @@ TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) { */ TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; NanConfigRequest nanConfigRequest = {}; NanConfigRequestSupplemental nanConfigRequestSupp = {}; auto status = @@ -520,7 +479,7 @@ TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) { // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE)); - ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_CONFIG_RESPONSE)); ASSERT_EQ(id_, inputCmdId); ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS); } @@ -561,12 +520,12 @@ TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidShimArgs) { */ TEST_P(WifiNanIfaceAidlTest, NotifyCapabilitiesResponse) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; EXPECT_TRUE(wifi_nan_iface_->getCapabilitiesRequest(inputCmdId).isOk()); // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE)); - ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_CAPABILITIES_RESPONSE)); ASSERT_EQ(id_, inputCmdId); ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); @@ -654,14 +613,14 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) { nanConfigRequestSupp.numberOfSpatialStreamsInDiscovery = 0; nanConfigRequestSupp.enableDiscoveryWindowEarlyTermination = false; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; auto status = wifi_nan_iface_->enableRequest(inputCmdId, req, nanConfigRequestSupp); if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { ASSERT_TRUE(status.isOk()); // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); - ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE)); ASSERT_EQ(id_, inputCmdId); ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); } @@ -688,7 +647,7 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) { // Wait for a callback. ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE)); - ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callback_type_); + ASSERT_TRUE(receivedCallback(NOTIFY_START_PUBLISH_RESPONSE)); ASSERT_EQ(id_, inputCmdId + 1); ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); } @@ -699,7 +658,7 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) { */ TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; NanRespondToDataPathIndicationRequest nanRespondToDataPathIndicationRequest = {}; nanRespondToDataPathIndicationRequest.ifaceName = "AwareInterfaceNameTooLong"; auto status = wifi_nan_iface_->respondToDataPathIndicationRequest( @@ -716,7 +675,7 @@ TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) { */ TEST_P(WifiNanIfaceAidlTest, InitiateDataPathRequest_InvalidArgs) { uint16_t inputCmdId = 10; - callback_type_ = INVALID; + callback_event_bitmap_ = 0; NanInitiateDataPathRequest nanInitiateDataPathRequest = {}; nanInitiateDataPathRequest.ifaceName = "AwareInterfaceNameTooLong"; auto status = wifi_nan_iface_->initiateDataPathRequest(inputCmdId, nanInitiateDataPathRequest); From 5aadf9ad17c356fd1b0a90905684869482261e4a Mon Sep 17 00:00:00 2001 From: Myles Watson Date: Tue, 11 Jul 2023 16:08:27 -0700 Subject: [PATCH 043/152] BluetoothAudio: Statically link HAL dependencies Bug: 290666670 Bug: 289857524 Bug: 284091286 Bug: 289489060 Test: mma -j32 (cherry picked from https://android-review.googlesource.com/q/commit:44628f38d2f60a8e9c283315485d2d62605f677d) Merged-In: I2b3c32b133e208ec2cfb1b244ccb24ad249f22df Change-Id: I2b3c32b133e208ec2cfb1b244ccb24ad249f22df The 32-bit libraries may not be present on the device. This makes the test more self-contained. --- bluetooth/audio/aidl/vts/Android.bp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp index e03fb5873d..5a604a1960 100644 --- a/bluetooth/audio/aidl/vts/Android.bp +++ b/bluetooth/audio/aidl/vts/Android.bp @@ -15,11 +15,14 @@ cc_test { ], tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"], srcs: ["VtsHalBluetoothAudioTargetTest.cpp"], - shared_libs: [ + static_libs: [ "android.hardware.audio.common-V1-ndk", "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", + "android.media.audio.common.types-V2-ndk", + ], + shared_libs: [ "libbase", "libbinder_ndk", "libcutils", From 719f6465307b4c0a763936125220e1de359ec054 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 12 Jul 2023 22:44:25 +0000 Subject: [PATCH 044/152] compat matrix: add ISap slot2 The framework supports this, but devices copied its support into each of their compat matrices instead of adding it once here. Bug: 290408770 Test: build Change-Id: I2de4f1365a6981a0a2ef7165c916fba91a340799 --- compatibility_matrices/compatibility_matrix.4.xml | 1 + compatibility_matrices/compatibility_matrix.5.xml | 1 + compatibility_matrices/compatibility_matrix.6.xml | 1 + compatibility_matrices/compatibility_matrix.7.xml | 1 + 4 files changed, 4 insertions(+) diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml index b9fb3f407f..204b83b96f 100644 --- a/compatibility_matrices/compatibility_matrix.4.xml +++ b/compatibility_matrices/compatibility_matrix.4.xml @@ -361,6 +361,7 @@ ISap slot1 + slot2 diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml index b374c8cfa3..bbf70558c2 100644 --- a/compatibility_matrices/compatibility_matrix.5.xml +++ b/compatibility_matrices/compatibility_matrix.5.xml @@ -399,6 +399,7 @@ ISap slot1 + slot2 diff --git a/compatibility_matrices/compatibility_matrix.6.xml b/compatibility_matrices/compatibility_matrix.6.xml index 40ae6558e8..1b812eded1 100644 --- a/compatibility_matrices/compatibility_matrix.6.xml +++ b/compatibility_matrices/compatibility_matrix.6.xml @@ -454,6 +454,7 @@ ISap slot1 + slot2 diff --git a/compatibility_matrices/compatibility_matrix.7.xml b/compatibility_matrices/compatibility_matrix.7.xml index e5ef954255..441979626c 100644 --- a/compatibility_matrices/compatibility_matrix.7.xml +++ b/compatibility_matrices/compatibility_matrix.7.xml @@ -582,6 +582,7 @@ ISap slot1 + slot2 From 1f06b4bf7613fadf1835fa2bba8e6bdf34b470f2 Mon Sep 17 00:00:00 2001 From: Gabriel Biren Date: Thu, 13 Jul 2023 18:24:14 +0000 Subject: [PATCH 045/152] Use a 64-bit instance of 0x1 when creating the event bitmask. Comments on ag/24025770 suggest that the bit shift will lead to undefined behavior for event codes greater than 31. Bug: 290318208 Test: atest VtsHalWifiNanIfaceTargetTest # manually set some of the expected # events codes to > 31 to verify that # the bit shift works as expected Change-Id: I09e11dac8acf90baf047e24cebe1d01970b1dc8a --- wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp index 95bcec7029..738e72cf00 100644 --- a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp +++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp @@ -123,7 +123,7 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { // Used as a mechanism to inform the test about data/event callbacks. inline void notify(CallbackType callbackType) { std::unique_lock lock(mtx_); - callback_event_bitmap_ |= (0x1 << callbackType); + callback_event_bitmap_ |= (UINT64_C(0x1) << callbackType); cv_.notify_one(); } @@ -143,7 +143,7 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { } inline bool receivedCallback(CallbackType waitForCallbackType) { - return callback_event_bitmap_ & (0x1 << waitForCallbackType); + return callback_event_bitmap_ & (UINT64_C(0x1) << waitForCallbackType); } class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback { From 4c3eeb417ee28249061be9d00ff9522f59cedddb Mon Sep 17 00:00:00 2001 From: Gabriel Biren Date: Thu, 13 Jul 2023 18:24:14 +0000 Subject: [PATCH 046/152] Use a 64-bit instance of 0x1 when creating the event bitmask. Comments on ag/24025770 suggest that the bit shift will lead to undefined behavior for event codes greater than 31. Bug: 290318208 Test: atest VtsHalWifiNanIfaceTargetTest # manually set some of the expected # events codes to > 31 to verify that # the bit shift works as expected Change-Id: I09e11dac8acf90baf047e24cebe1d01970b1dc8a --- wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp index 95bcec7029..738e72cf00 100644 --- a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp +++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp @@ -123,7 +123,7 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { // Used as a mechanism to inform the test about data/event callbacks. inline void notify(CallbackType callbackType) { std::unique_lock lock(mtx_); - callback_event_bitmap_ |= (0x1 << callbackType); + callback_event_bitmap_ |= (UINT64_C(0x1) << callbackType); cv_.notify_one(); } @@ -143,7 +143,7 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam { } inline bool receivedCallback(CallbackType waitForCallbackType) { - return callback_event_bitmap_ & (0x1 << waitForCallbackType); + return callback_event_bitmap_ & (UINT64_C(0x1) << waitForCallbackType); } class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback { From 3729b0bd6074edccb00976690f22a3c7572d652d Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Wed, 21 Jun 2023 22:49:04 +0000 Subject: [PATCH 047/152] Fix wrong timeout and mock method in radio VTS Fixed wrong time unit convension for timeout values used in broadcast radio HAL VTS. Also replaced tuner callback mock method which caused segmentation fault when unimplemented callback methods are called. In addition, antenna connection state was checked at the end of the each test instead of at the beginning. Bug: 277531858 Test: atest VtsHalBroadcastradioAidlTargetTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4420c1dbbf28cc80ac47cdbafb9cc81034f8fc8f) Merged-In: Ied70fcfd2742ae5d253aec984e2161afa6f65162 Change-Id: Ied70fcfd2742ae5d253aec984e2161afa6f65162 --- .../VtsHalBroadcastradioAidlTargetTest.cpp | 219 +++++++++++++----- 1 file changed, 156 insertions(+), 63 deletions(-) diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp index 356673f715..8bee1b2d1f 100644 --- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp +++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp @@ -32,11 +32,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -61,11 +61,6 @@ using ::testing::SaveArg; namespace bcutils = ::aidl::android::hardware::broadcastradio::utils; -inline constexpr std::chrono::seconds kTuneTimeoutSec = - std::chrono::seconds(IBroadcastRadio::TUNER_TIMEOUT_MS * 1000); -inline constexpr std::chrono::seconds kProgramListScanTimeoutSec = - std::chrono::seconds(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS * 1000); - const ConfigFlag kConfigFlagValues[] = { ConfigFlag::FORCE_MONO, ConfigFlag::FORCE_ANALOG, @@ -108,20 +103,68 @@ bool supportsFM(const AmFmRegionConfig& config) { } // namespace -class TunerCallbackMock : public BnTunerCallback { +class CallbackFlag final { public: - TunerCallbackMock(); + CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; } + /** + * Notify that the callback is called. + */ + void notify() { + std::unique_lock lock(mMutex); + mCalled = true; + lock.unlock(); + mCv.notify_all(); + }; + + /** + * Wait for the timeout passed into the constructor. + */ + bool wait() { + std::unique_lock lock(mMutex); + return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs), + [this] { return mCalled; }); + }; + + /** + * Reset the callback to not called. + */ + void reset() { + std::unique_lock lock(mMutex); + mCalled = false; + } + + private: + std::mutex mMutex; + bool mCalled GUARDED_BY(mMutex) = false; + std::condition_variable mCv; + int mTimeoutMs; +}; + +class TunerCallbackImpl final : public BnTunerCallback { + public: + TunerCallbackImpl(); ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override; - MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChangedMock, ScopedAStatus(const ProgramInfo&)); ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override; ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override; - MOCK_METHOD1(onAntennaStateChange, ScopedAStatus(bool connected)); - MOCK_METHOD1(onParametersUpdated, ScopedAStatus(const vector& parameters)); - MOCK_METHOD2(onConfigFlagUpdated, ScopedAStatus(ConfigFlag in_flag, bool in_value)); - MOCK_TIMEOUT_METHOD0(onProgramListReady, void()); + ScopedAStatus onParametersUpdated(const vector& parameters) override; + ScopedAStatus onAntennaStateChange(bool connected) override; + ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override; + bool waitOnCurrentProgramInfoChangedCallback(); + bool waitProgramReady(); + void reset(); + + bool getAntennaConnectionState(); + ProgramInfo getCurrentProgramInfo(); + bcutils::ProgramInfoSet getProgramList(); + + private: std::mutex mLock; + bool mAntennaConnectionState GUARDED_BY(mLock); + ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock); bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock); + CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS); + CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS); }; struct AnnouncementListenerMock : public BnAnnouncementListener { @@ -139,7 +182,7 @@ class BroadcastRadioHalTest : public testing::TestWithParam { std::shared_ptr mModule; Properties mProperties; - std::shared_ptr mCallback = SharedRefBase::make(); + std::shared_ptr mCallback; }; MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) { @@ -147,20 +190,18 @@ MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " return ids.end() != find(ids.begin(), ids.end(), id.value); } -TunerCallbackMock::TunerCallbackMock() { - EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); - - // we expect the antenna is connected through the whole test - EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0); +TunerCallbackImpl::TunerCallbackImpl() { + mAntennaConnectionState = true; } -ScopedAStatus TunerCallbackMock::onTuneFailed(Result result, const ProgramSelector& selector) { +ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) { LOG(DEBUG) << "Tune failed for selector" << selector.toString(); EXPECT_TRUE(result == Result::CANCELED); return ndk::ScopedAStatus::ok(); } -ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) { +ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) { + LOG(DEBUG) << "onCurrentProgramInfoChanged called"; for (const auto& id : info.selector) { EXPECT_NE(id.type, IdentifierType::INVALID); } @@ -196,21 +237,75 @@ ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& } } - return onCurrentProgramInfoChangedMock(info); + { + std::lock_guard lk(mLock); + mCurrentProgramInfo = info; + } + + mOnCurrentProgramInfoChangedFlag.notify(); + return ndk::ScopedAStatus::ok(); } -ScopedAStatus TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) { - std::lock_guard lk(mLock); - - updateProgramList(chunk, &mProgramList); +ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) { + LOG(DEBUG) << "onProgramListUpdated called"; + { + std::lock_guard lk(mLock); + updateProgramList(chunk, &mProgramList); + } if (chunk.complete) { - onProgramListReady(); + mOnProgramListReadyFlag.notify(); } return ndk::ScopedAStatus::ok(); } +ScopedAStatus TunerCallbackImpl::onParametersUpdated( + [[maybe_unused]] const vector& parameters) { + return ndk::ScopedAStatus::ok(); +} + +ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) { + if (!connected) { + std::lock_guard lk(mLock); + mAntennaConnectionState = false; + } + return ndk::ScopedAStatus::ok(); +} + +ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag, + [[maybe_unused]] bool in_value) { + return ndk::ScopedAStatus::ok(); +} + +bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() { + return mOnCurrentProgramInfoChangedFlag.wait(); +} + +bool TunerCallbackImpl::waitProgramReady() { + return mOnProgramListReadyFlag.wait(); +} + +void TunerCallbackImpl::reset() { + mOnCurrentProgramInfoChangedFlag.reset(); + mOnProgramListReadyFlag.reset(); +} + +bool TunerCallbackImpl::getAntennaConnectionState() { + std::lock_guard lk(mLock); + return mAntennaConnectionState; +} + +ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() { + std::lock_guard lk(mLock); + return mCurrentProgramInfo; +} + +bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() { + std::lock_guard lk(mLock); + return mProgramList; +} + void BroadcastRadioHalTest::SetUp() { EXPECT_EQ(mModule.get(), nullptr) << "Module is already open"; @@ -228,6 +323,8 @@ void BroadcastRadioHalTest::SetUp() { EXPECT_FALSE(mProperties.product.empty()); EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u); + mCallback = SharedRefBase::make(); + // set callback EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk()); } @@ -236,6 +333,11 @@ void BroadcastRadioHalTest::TearDown() { if (mModule) { ASSERT_TRUE(mModule->unsetTunerCallback().isOk()); } + if (mCallback) { + // we expect the antenna is connected through the whole test + EXPECT_TRUE(mCallback->getAntennaConnectionState()); + mCallback = nullptr; + } } bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) { @@ -256,7 +358,7 @@ std::optional BroadcastRadioHalTest::getProgramList() { std::optional BroadcastRadioHalTest::getProgramList( const ProgramFilter& filter) { - EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber()); + mCallback->reset(); auto startResult = mModule->startProgramListUpdates(filter); @@ -268,13 +370,13 @@ std::optional BroadcastRadioHalTest::getProgramList( if (!startResult.isOk()) { return std::nullopt; } - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, kProgramListScanTimeoutSec); + EXPECT_TRUE(mCallback->waitProgramReady()); auto stopResult = mModule->stopProgramListUpdates(); EXPECT_TRUE(stopResult.isOk()); - return mCallback->mProgramList; + return mCallback->getProgramList(); } /** @@ -456,7 +558,7 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithoutTunerCallback) { * - if it is supported, the test is ignored; */ TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) { - LOG(DEBUG) << "TuneFailsWithInvalid Test"; + LOG(DEBUG) << "TuneFailsWithNotSupported Test"; vector supportTestId = { makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0), // invalid @@ -477,9 +579,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) { for (const auto& id : supportTestId) { ProgramSelector sel{id, {}}; - auto result = mModule->tune(sel); - if (!bcutils::isSupported(mProperties, sel)) { + auto result = mModule->tune(sel); + EXPECT_EQ(result.getServiceSpecificError(), notSupportedError); } } @@ -508,9 +610,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) { for (const auto& id : invalidId) { ProgramSelector sel{id, {}}; - auto result = mModule->tune(sel); - if (bcutils::isSupported(mProperties, sel)) { + auto result = mModule->tune(sel); + EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError); } } @@ -549,13 +651,7 @@ TEST_P(BroadcastRadioHalTest, FmTune) { int64_t freq = 90900; // 90.9 FM ProgramSelector sel = makeSelectorAmfm(freq); // try tuning - ProgramInfo infoCb = {}; - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, - InfoHasId(makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq))) - .Times(AnyNumber()) - .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok())))) - .WillRepeatedly(testing::InvokeWithoutArgs([] { return ndk::ScopedAStatus::ok(); })); - + mCallback->reset(); auto result = mModule->tune(sel); // expect a failure if it's not supported @@ -566,7 +662,8 @@ TEST_P(BroadcastRadioHalTest, FmTune) { // expect a callback if it succeeds EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); + ProgramInfo infoCb = mCallback->getCurrentProgramInfo(); LOG(DEBUG) << "Current program info: " << infoCb.toString(); @@ -638,12 +735,6 @@ TEST_P(BroadcastRadioHalTest, DabTune) { } // try tuning - ProgramInfo infoCb = {}; - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, - InfoHasId(makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq))) - .Times(AnyNumber()) - .WillOnce( - DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok())))); auto result = mModule->tune(sel); @@ -655,7 +746,9 @@ TEST_P(BroadcastRadioHalTest, DabTune) { // expect a callback if it succeeds EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); + ProgramInfo infoCb = mCallback->getCurrentProgramInfo(); + LOG(DEBUG) << "Current program info: " << infoCb.toString(); // it should tune exactly to what was requested @@ -669,13 +762,13 @@ TEST_P(BroadcastRadioHalTest, DabTune) { * * Verifies that: * - the method succeeds; - * - the program info is changed within kTuneTimeoutSec; + * - the program info is changed within kTuneTimeoutMs; * - works both directions and with or without skipping sub-channel. */ TEST_P(BroadcastRadioHalTest, Seek) { LOG(DEBUG) << "Seek Test"; - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); + mCallback->reset(); auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true); @@ -685,14 +778,14 @@ TEST_P(BroadcastRadioHalTest, Seek) { } EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); + mCallback->reset(); result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false); EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); } /** @@ -720,13 +813,13 @@ TEST_P(BroadcastRadioHalTest, SeekFailsWithoutTunerCallback) { * * Verifies that: * - the method succeeds or returns NOT_SUPPORTED; - * - the program info is changed within kTuneTimeoutSec if the method succeeded; + * - the program info is changed within kTuneTimeoutMs if the method succeeded; * - works both directions. */ TEST_P(BroadcastRadioHalTest, Step) { LOG(DEBUG) << "Step Test"; - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); + mCallback->reset(); auto result = mModule->step(/* in_directionUp= */ true); @@ -735,14 +828,14 @@ TEST_P(BroadcastRadioHalTest, Step) { return; } EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); - EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber()); + mCallback->reset(); result = mModule->step(/* in_directionUp= */ false); EXPECT_TRUE(result.isOk()); - EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec); + EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback()); } /** @@ -955,7 +1048,7 @@ TEST_P(BroadcastRadioHalTest, SetConfigFlags) { * * Verifies that: * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED; - * - the complete list is fetched within kProgramListScanTimeoutSec; + * - the complete list is fetched within kProgramListScanTimeoutMs; * - stopProgramListUpdates does not crash. */ TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) { @@ -969,7 +1062,7 @@ TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) { * * Verifies that: * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED; - * - the complete list is fetched within kProgramListScanTimeoutSec; + * - the complete list is fetched within kProgramListScanTimeoutMs; * - stopProgramListUpdates does not crash; * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first * AMFM program matches the expected result. @@ -1017,7 +1110,7 @@ TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) { * * Verifies that: * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED; - * - the complete list is fetched within kProgramListScanTimeoutSec; + * - the complete list is fetched within kProgramListScanTimeoutMs; * - stopProgramListUpdates does not crash; * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB * program matches the expected result. From 073af1802eaccf2ddd440ef561971914bf1496a2 Mon Sep 17 00:00:00 2001 From: Jeff Pu Date: Wed, 12 Jul 2023 18:53:52 +0000 Subject: [PATCH 048/152] Update fingerprint VHAL operation lifecycle Bug: 289410175 Test: atest FakeFingerprintEngineTest Change-Id: I6da68047be9bf5357c1b4c75ba28fc66c2e3bcc0 --- .../aidl/default/FakeFingerprintEngine.cpp | 55 ++++++++++++------- .../default/include/FakeFingerprintEngine.h | 6 +- .../tests/FakeFingerprintEngineTest.cpp | 14 ++++- 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp index 5f5455af61..975728764b 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp @@ -89,24 +89,29 @@ void FakeFingerprintEngine::updateContext(WorkMode mode, ISessionCallback* cb, } void FakeFingerprintEngine::fingerDownAction() { + bool isTerminal = false; LOG(INFO) << __func__; switch (mWorkMode) { case WorkMode::kAuthenticate: - onAuthenticateFingerDown(mCb, mOperationId, mCancel); + isTerminal = onAuthenticateFingerDown(mCb, mOperationId, mCancel); break; case WorkMode::kEnroll: - onEnrollFingerDown(mCb, mHat, mCancel); + isTerminal = onEnrollFingerDown(mCb, mHat, mCancel); break; case WorkMode::kDetectInteract: - onDetectInteractFingerDown(mCb, mCancel); + isTerminal = onDetectInteractFingerDown(mCb, mCancel); break; default: LOG(WARNING) << "unexpected mode: on fingerDownAction(), " << (int)mWorkMode; break; } + + if (isTerminal) { + mWorkMode = WorkMode::kIdle; + } } -void FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, +bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat, const std::future& cancel) { BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency())); @@ -115,7 +120,7 @@ void FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, if (hat.mac.empty()) { LOG(ERROR) << "Fail: hat"; cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); - return; + return true; } // Force error-out @@ -124,7 +129,7 @@ void FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, LOG(ERROR) << "Fail: operation_enroll_error"; auto ec = convertError(err); cb->onError(ec.first, ec.second); - return; + return true; } // Format is ":,...: @@ -133,7 +138,7 @@ void FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, if (parts.size() != 3) { LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll; cb->onError(Error::VENDOR, 0 /* vendorError */); - return; + return true; } auto enrollmentId = std::stoi(parts[0]); auto progress = parseEnrollmentCapture(parts[1]); @@ -149,7 +154,7 @@ void FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, if (shouldCancel(cancel)) { LOG(ERROR) << "Fail: cancel"; cb->onError(Error::CANCELED, 0 /* vendorCode */); - return; + return true; } auto ac = convertAcquiredInfo(acquired[j]); cb->onAcquired(ac.first, ac.second); @@ -175,9 +180,11 @@ void FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, cb->onEnrollmentProgress(enrollmentId, left); } } + + return true; } -void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, +bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, int64_t /* operationId */, const std::future& cancel) { BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency())); @@ -191,11 +198,13 @@ void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, if (N == 0) { LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired; cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); - return; + return true; } // got lockout? - if (checkSensorLockout(cb)) return; + if (checkSensorLockout(cb)) { + return FakeLockoutTracker::LockoutMode::kPermanent == mLockoutTracker.getMode(); + } int i = 0; do { @@ -203,7 +212,7 @@ void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, LOG(ERROR) << "Fail: operation_authenticate_fails"; mLockoutTracker.addFailedAttempt(); cb->onAuthenticationFailed(); - return; + return false; } auto err = FingerprintHalProperties::operation_authenticate_error().value_or(0); @@ -211,20 +220,21 @@ void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, LOG(ERROR) << "Fail: operation_authenticate_error"; auto ec = convertError(err); cb->onError(ec.first, ec.second); - return; + return true; /* simply terminating current operation for any user inserted error, + revisit if tests need*/ } if (FingerprintHalProperties::lockout().value_or(false)) { LOG(ERROR) << "Fail: lockout"; cb->onLockoutPermanent(); cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */); - return; + return true; } if (shouldCancel(cancel)) { LOG(ERROR) << "Fail: cancel"; cb->onError(Error::CANCELED, 0 /* vendorCode */); - return; + return true; } if (i < N) { @@ -242,16 +252,17 @@ void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, if (id > 0 && isEnrolled) { cb->onAuthenticationSucceeded(id, {} /* hat */); mLockoutTracker.reset(); - return; + return true; } else { LOG(ERROR) << "Fail: fingerprint not enrolled"; cb->onAuthenticationFailed(); mLockoutTracker.addFailedAttempt(); checkSensorLockout(cb); + return true; } } -void FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb, +bool FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb, const std::future& cancel) { BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency())); @@ -266,7 +277,7 @@ void FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb, if (N == 0) { LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired; cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); - return; + return true; } int i = 0; @@ -276,13 +287,13 @@ void FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb, LOG(ERROR) << "Fail: operation_detect_interaction_error"; auto ec = convertError(err); cb->onError(ec.first, ec.second); - return; + return true; } if (shouldCancel(cancel)) { LOG(ERROR) << "Fail: cancel"; cb->onError(Error::CANCELED, 0 /* vendorCode */); - return; + return true; } if (i < N) { @@ -299,10 +310,12 @@ void FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb, if (id <= 0 || !isEnrolled) { LOG(ERROR) << "Fail: not enrolled"; cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); - return; + return true; } cb->onInteractionDetected(); + + return true; } void FakeFingerprintEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) { diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h index 8ac7a955e4..a06b786acd 100644 --- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h +++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h @@ -94,10 +94,10 @@ class FakeFingerprintEngine { virtual void updateContext(WorkMode mode, ISessionCallback* cb, std::future& cancel, int64_t operationId, const keymaster::HardwareAuthToken& hat); - void onEnrollFingerDown(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat, + bool onEnrollFingerDown(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat, const std::future& cancel); - void onAuthenticateFingerDown(ISessionCallback* cb, int64_t, const std::future& cancel); - void onDetectInteractFingerDown(ISessionCallback* cb, const std::future& cancel); + bool onAuthenticateFingerDown(ISessionCallback* cb, int64_t, const std::future& cancel); + bool onDetectInteractFingerDown(ISessionCallback* cb, const std::future& cancel); WorkMode mWorkMode; ISessionCallback* mCb; diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp index 86207a5c7d..e7e8a476eb 100644 --- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp +++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp @@ -132,6 +132,8 @@ class FakeFingerprintEngineTest : public ::testing::Test { FingerprintHalProperties::operation_enroll_latency({}); FingerprintHalProperties::operation_authenticate_latency({}); FingerprintHalProperties::operation_detect_interaction_latency({}); + FingerprintHalProperties::operation_authenticate_fails(false); + FingerprintHalProperties::operation_detect_interaction_latency({}); } FakeFingerprintEngine mEngine; @@ -185,6 +187,7 @@ TEST_F(FakeFingerprintEngineTest, Enroll) { ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value()); ASSERT_EQ(4, mCallback->mLastEnrolled); ASSERT_EQ(1, mCallback->mLastAcquiredInfo); + ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle); } TEST_F(FakeFingerprintEngineTest, EnrollCancel) { @@ -239,6 +242,7 @@ TEST_F(FakeFingerprintEngineTest, Authenticate) { ASSERT_FALSE(mCallback->mAuthenticateFailed); ASSERT_EQ(2, mCallback->mLastAuthenticated); ASSERT_EQ(1, mCallback->mLastAcquiredInfo); + ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle); } TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) { @@ -293,6 +297,14 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateError9) { ASSERT_EQ(mCallback->mErrorVendorCode, 9); } +TEST_F(FakeFingerprintEngineTest, AuthenticateFails) { + FingerprintHalProperties::operation_authenticate_fails(true); + mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); + mEngine.fingerDownAction(); + ASSERT_TRUE(mCallback->mAuthenticateFailed); + ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate); +} + TEST_F(FakeFingerprintEngineTest, AuthenticateAcquired) { FingerprintHalProperties::lockout(false); FingerprintHalProperties::enrollments({1, 2}); @@ -318,6 +330,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetect) { mEngine.fingerDownAction(); ASSERT_EQ(1, mCallback->mInteractionDetectedCount); ASSERT_EQ(1, mCallback->mLastAcquiredInfo); + ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle); } TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) { @@ -483,7 +496,6 @@ TEST_F(FakeFingerprintEngineTest, randomLatency) { FingerprintHalProperties::operation_detect_interaction_latency())); } ASSERT_TRUE(latencySet.size() > 95); - FingerprintHalProperties::operation_detect_interaction_latency({}); } } // namespace aidl::android::hardware::biometrics::fingerprint From dfd1d0632e2b8ed2ca700bec88662ec43cfe5bfc Mon Sep 17 00:00:00 2001 From: Jaideep Sharma Date: Fri, 7 Jul 2023 14:35:48 +0530 Subject: [PATCH 049/152] vts: getParameters only if parameters are supported 1) Validate specific parameters before open call, send only if parameters are supported. 2) GetParameters only if parameters are in range. Bug: 288510312 Test: run vts VtsHalNSTargetTest, VtsHalAECTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:b985903e16929a7378c6c8ff6281e6748164ce51) Merged-In: Idb20d819b3eb8a4ba56b4d50311c1aa7659f3616 Change-Id: Idb20d819b3eb8a4ba56b4d50311c1aa7659f3616 --- audio/aidl/vts/VtsHalAECTargetTest.cpp | 11 ++++++++--- audio/aidl/vts/VtsHalNSTargetTest.cpp | 12 +++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp index 8828c41bbe..b1cedcaf9d 100644 --- a/audio/aidl/vts/VtsHalAECTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp @@ -51,7 +51,7 @@ class AECParamTest : public ::testing::TestWithParam, public ASSERT_NE(nullptr, mFactory); ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); - Parameter::Specific specific = getDefaultParamSpecific(); + auto specific = getDefaultParamSpecific(); Parameter::Common common = EffectHelper::createParamCommon( 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); @@ -65,8 +65,13 @@ class AECParamTest : public ::testing::TestWithParam, public ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect)); } - Parameter::Specific getDefaultParamSpecific() { - AcousticEchoCanceler aec = AcousticEchoCanceler::make(0); + std::optional getDefaultParamSpecific() { + auto aec = AcousticEchoCanceler::make(0); + if (!isParameterValid(aec, + mDescriptor)) { + return std::nullopt; + } + Parameter::Specific specific = Parameter::Specific::make(aec); return specific; diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp index 5525c80894..13b4c43115 100644 --- a/audio/aidl/vts/VtsHalNSTargetTest.cpp +++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp @@ -48,7 +48,7 @@ class NSParamTest : public ::testing::TestWithParam, public Ef ASSERT_NE(nullptr, mFactory); ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); - Parameter::Specific specific = getDefaultParamSpecific(); + std::optional specific = getDefaultParamSpecific(); Parameter::Common common = EffectHelper::createParamCommon( 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); @@ -62,9 +62,13 @@ class NSParamTest : public ::testing::TestWithParam, public Ef ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect)); } - Parameter::Specific getDefaultParamSpecific() { + std::optional getDefaultParamSpecific() { NoiseSuppression ns = NoiseSuppression::make(NoiseSuppression::Level::MEDIUM); + if (!isParameterValid(ns, mDescriptor)) { + return std::nullopt; + } + Parameter::Specific specific = Parameter::Specific::make(ns); return specific; @@ -85,7 +89,9 @@ class NSParamTest : public ::testing::TestWithParam, public Ef // validate parameter Descriptor desc; ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc)); - const binder_exception_t expected = EX_NONE; + const bool valid = + isParameterValid(ns, desc); + const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT; // set parameter Parameter expectParam; From 00d87fdae7ef2c837d35569c11413eff4283465a Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Fri, 14 Jul 2023 22:10:46 +0000 Subject: [PATCH 050/152] Support custom effect type UUID in audio effect AIDL example service Parse custom effect type uuid in audio_effects_config.xml, so OEM can add effect types without changing code Bug: 271500140 Test: atest --test-mapping hardware/interfaces/audio/aidl/vts:presubmit (cherry picked from https://android-review.googlesource.com/q/commit:80e5850d82f1b311a89367a77bab2c801ac16b37) Merged-In: I558958cc42c6c4a304e0ab1239ddefec9575a5af Change-Id: I558958cc42c6c4a304e0ab1239ddefec9575a5af --- audio/aidl/default/EffectConfig.cpp | 52 ++++++++++++------- audio/aidl/default/EffectFactory.cpp | 9 ++-- audio/aidl/default/audio_effects_config.xml | 9 ++-- .../include/effectFactory-impl/EffectConfig.h | 15 +++--- .../effectFactory-impl/EffectFactory.h | 2 +- 5 files changed, 52 insertions(+), 35 deletions(-) diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp index f3f674f6ef..730c0bf758 100644 --- a/audio/aidl/default/EffectConfig.cpp +++ b/audio/aidl/default/EffectConfig.cpp @@ -117,53 +117,59 @@ bool EffectConfig::parseLibrary(const tinyxml2::XMLElement& xml) { bool EffectConfig::parseEffect(const tinyxml2::XMLElement& xml) { struct EffectLibraries effectLibraries; - std::vector libraryUuids; + std::vector libraries; std::string name = xml.Attribute("name"); RETURN_VALUE_IF(name == "", false, "effectsNoName"); LOG(DEBUG) << __func__ << dump(xml); - struct LibraryUuid libraryUuid; + struct Library library; if (std::strcmp(xml.Name(), "effectProxy") == 0) { // proxy lib and uuid - RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid, true), false, "parseProxyLibFailed"); - effectLibraries.proxyLibrary = libraryUuid; + RETURN_VALUE_IF(!parseLibrary(xml, library, true), false, "parseProxyLibFailed"); + effectLibraries.proxyLibrary = library; // proxy effect libs and UUID auto xmlProxyLib = xml.FirstChildElement(); RETURN_VALUE_IF(!xmlProxyLib, false, "noLibForProxy"); while (xmlProxyLib) { - struct LibraryUuid tempLibraryUuid; - RETURN_VALUE_IF(!parseLibraryUuid(*xmlProxyLib, tempLibraryUuid), false, + struct Library tempLibrary; + RETURN_VALUE_IF(!parseLibrary(*xmlProxyLib, tempLibrary), false, "parseEffectLibFailed"); - libraryUuids.push_back(std::move(tempLibraryUuid)); + libraries.push_back(std::move(tempLibrary)); xmlProxyLib = xmlProxyLib->NextSiblingElement(); } } else { // expect only one library if not proxy - RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid), false, "parseEffectLibFailed"); - libraryUuids.push_back(std::move(libraryUuid)); + RETURN_VALUE_IF(!parseLibrary(xml, library), false, "parseEffectLibFailed"); + libraries.push_back(std::move(library)); } - effectLibraries.libraries = std::move(libraryUuids); + effectLibraries.libraries = std::move(libraries); mEffectsMap[name] = std::move(effectLibraries); return true; } -bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml, - struct LibraryUuid& libraryUuid, bool isProxy) { +bool EffectConfig::parseLibrary(const tinyxml2::XMLElement& xml, struct Library& library, + bool isProxy) { // Retrieve library name only if not effectProxy element if (!isProxy) { const char* name = xml.Attribute("library"); RETURN_VALUE_IF(!name, false, "noLibraryAttribute"); - libraryUuid.name = name; + library.name = name; } const char* uuidStr = xml.Attribute("uuid"); RETURN_VALUE_IF(!uuidStr, false, "noUuidAttribute"); - libraryUuid.uuid = stringToUuid(uuidStr); - RETURN_VALUE_IF((libraryUuid.uuid == getEffectUuidZero()), false, "invalidUuidAttribute"); + library.uuid = stringToUuid(uuidStr); + if (const char* typeUuidStr = xml.Attribute("type")) { + library.type = stringToUuid(typeUuidStr); + } + RETURN_VALUE_IF((library.uuid == getEffectUuidZero()), false, "invalidUuidAttribute"); - LOG(DEBUG) << __func__ << (isProxy ? " proxy " : libraryUuid.name) << " : " - << ::android::audio::utils::toString(libraryUuid.uuid); + LOG(DEBUG) << __func__ << (isProxy ? " proxy " : library.name) << " : uuid " + << ::android::audio::utils::toString(library.uuid) + << (library.type.has_value() + ? ::android::audio::utils::toString(library.type.value()) + : ""); return true; } @@ -241,7 +247,8 @@ EffectConfig::getProcessingMap() const { return mProcessingMap; } -bool EffectConfig::findUuid(const std::string& xmlEffectName, AudioUuid* uuid) { +bool EffectConfig::findUuid(const std::pair& effectElem, + AudioUuid* uuid) { // Difference from EFFECT_TYPE_LIST_DEF, there could be multiple name mapping to same Effect Type #define EFFECT_XML_TYPE_LIST_DEF(V) \ V("acoustic_echo_canceler", AcousticEchoCanceler) \ @@ -268,6 +275,7 @@ bool EffectConfig::findUuid(const std::string& xmlEffectName, AudioUuid* uuid) { #define GENERATE_MAP_ENTRY_V(s, symbol) {s, &getEffectTypeUuid##symbol}, + const std::string xmlEffectName = effectElem.first; typedef const AudioUuid& (*UuidGetter)(void); static const std::map uuidMap{ // std::make_pair("s", &getEffectTypeUuidExtension)}; @@ -276,6 +284,14 @@ bool EffectConfig::findUuid(const std::string& xmlEffectName, AudioUuid* uuid) { *uuid = (*it->second)(); return true; } + + const auto& libs = effectElem.second.libraries; + for (const auto& lib : libs) { + if (lib.type.has_value()) { + *uuid = lib.type.value(); + return true; + } + } return false; } diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp index 8ed62c9c7a..62f3c7ee47 100644 --- a/audio/aidl/default/EffectFactory.cpp +++ b/audio/aidl/default/EffectFactory.cpp @@ -105,7 +105,7 @@ ndk::ScopedAStatus Factory::queryProcessing(const std::optional */) { - for (const auto& lib : libs.libraries /* std::vector */) { + for (const auto& lib : libs.libraries /* std::vector */) { Descriptor desc; if (libs.proxyLibrary.has_value()) { desc.common.id.proxy = libs.proxyLibrary.value().uuid; @@ -219,7 +219,7 @@ bool Factory::openEffectLibrary(const AudioUuid& impl, const std::string& path) return true; } -void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib, +void Factory::createIdentityWithConfig(const EffectConfig::Library& configLib, const AudioUuid& typeUuid, const std::optional proxyUuid) { static const auto& libMap = mConfig.getLibraryMap(); @@ -246,8 +246,7 @@ void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLi void Factory::loadEffectLibs() { const auto& configEffectsMap = mConfig.getEffectsMap(); for (const auto& configEffects : configEffectsMap) { - if (AudioUuid uuid; - EffectConfig::findUuid(configEffects.first /* xml effect name */, &uuid)) { + if (AudioUuid type; EffectConfig::findUuid(configEffects /* xml effect */, &type)) { const auto& configLibs = configEffects.second; std::optional proxyUuid; if (configLibs.proxyLibrary.has_value()) { @@ -255,7 +254,7 @@ void Factory::loadEffectLibs() { proxyUuid = proxyLib.uuid; } for (const auto& configLib : configLibs.libraries) { - createIdentityWithConfig(configLib, uuid, proxyUuid); + createIdentityWithConfig(configLib, type, proxyUuid); } } else { LOG(ERROR) << __func__ << ": can not find type UUID for effect " << configEffects.first diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml index 6627ae7533..00de797764 100644 --- a/audio/aidl/default/audio_effects_config.xml +++ b/audio/aidl/default/audio_effects_config.xml @@ -50,7 +50,8 @@ @@ -94,7 +95,7 @@ - + diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h index f8a86e1515..344846a4ca 100644 --- a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h +++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h @@ -40,14 +40,15 @@ class EffectConfig { public: explicit EffectConfig(const std::string& file); - struct LibraryUuid { + struct Library { std::string name; // library name - ::aidl::android::media::audio::common::AudioUuid uuid; + ::aidl::android::media::audio::common::AudioUuid uuid; // implementation UUID + std::optional<::aidl::android::media::audio::common::AudioUuid> type; // optional type UUID }; // struct EffectLibraries { - std::optional proxyLibrary; - std::vector libraries; + std::optional proxyLibrary; + std::vector libraries; }; int getSkippedElements() const { return mSkippedElements; } @@ -56,7 +57,7 @@ class EffectConfig { return mEffectsMap; } - static bool findUuid(const std::string& xmlEffectName, + static bool findUuid(const std::pair& effectElem, ::aidl::android::media::audio::common::AudioUuid* uuid); using ProcessingLibrariesMap = std::map>; @@ -96,8 +97,8 @@ class EffectConfig { bool parseProcessing(Processing::Type::Tag typeTag, const tinyxml2::XMLElement& xml); // Function to parse effect.library name and effect.uuid from xml - bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid, - bool isProxy = false); + bool parseLibrary(const tinyxml2::XMLElement& xml, struct Library& library, + bool isProxy = false); const char* dump(const tinyxml2::XMLElement& element, tinyxml2::XMLPrinter&& printer = {}) const; diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h index ad59ca799c..1401db03e5 100644 --- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h +++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h @@ -104,7 +104,7 @@ class Factory : public BnFactory { bool openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl, const std::string& path); void createIdentityWithConfig( - const EffectConfig::LibraryUuid& configLib, + const EffectConfig::Library& configLib, const ::aidl::android::media::audio::common::AudioUuid& typeUuidStr, const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid); From 5091d1c6cf2f245321b3249fba9efd780d41d1f3 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Fri, 14 Jul 2023 21:08:31 +0000 Subject: [PATCH 051/152] Make EffectFactory implementation thread-safe Also adjust some log level as verbos Bug: 271500140 Test: atest --test-mapping hardware/interfaces/audio/aidl/vts:presubmit Change-Id: I04560c62bdbcfb85dbe223bec0149b112205a323 Merged-In: I04560c62bdbcfb85dbe223bec0149b112205a323 --- audio/aidl/default/EffectFactory.cpp | 36 +++++++++++-------- audio/aidl/default/EffectImpl.cpp | 7 ++-- audio/aidl/default/EffectThread.cpp | 4 +-- .../include/effect-impl/EffectContext.h | 4 +-- .../include/effect-impl/EffectWorker.h | 8 ++--- .../effectFactory-impl/EffectFactory.h | 24 ++++++++----- 6 files changed, 47 insertions(+), 36 deletions(-) diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp index 62f3c7ee47..96f13ba058 100644 --- a/audio/aidl/default/EffectFactory.cpp +++ b/audio/aidl/default/EffectFactory.cpp @@ -49,18 +49,18 @@ Factory::~Factory() { if (auto spEffect = it.first.lock()) { LOG(ERROR) << __func__ << " erase remaining instance UUID " << ::android::audio::utils::toString(it.second.first); - destroyEffectImpl(spEffect); + destroyEffectImpl_l(spEffect); } } } } -ndk::ScopedAStatus Factory::getDescriptorWithUuid(const AudioUuid& uuid, Descriptor* desc) { +ndk::ScopedAStatus Factory::getDescriptorWithUuid_l(const AudioUuid& uuid, Descriptor* desc) { RETURN_IF(!desc, EX_NULL_POINTER, "nullDescriptor"); if (mEffectLibMap.count(uuid)) { auto& entry = mEffectLibMap[uuid]; - getDlSyms(entry); + getDlSyms_l(entry); auto& libInterface = std::get(entry); RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER, "dlNullQueryEffectFunc"); @@ -75,6 +75,7 @@ ndk::ScopedAStatus Factory::queryEffects(const std::optional& in_type const std::optional& in_impl_uuid, const std::optional& in_proxy_uuid, std::vector* _aidl_return) { + std::lock_guard lg(mMutex); // get the matching list std::vector idList; std::copy_if(mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(idList), @@ -88,7 +89,8 @@ ndk::ScopedAStatus Factory::queryEffects(const std::optional& in_type for (const auto& id : idList) { if (mEffectLibMap.count(id.uuid)) { Descriptor desc; - RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(id.uuid, &desc), "getDescriptorFailed"); + RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid_l(id.uuid, &desc), + "getDescriptorFailed"); // update proxy UUID with information from config xml desc.common.id.proxy = id.proxy; _aidl_return->emplace_back(std::move(desc)); @@ -99,6 +101,7 @@ ndk::ScopedAStatus Factory::queryEffects(const std::optional& in_type ndk::ScopedAStatus Factory::queryProcessing(const std::optional& in_type, std::vector* _aidl_return) { + std::lock_guard lg(mMutex); const auto& processings = mConfig.getProcessingMap(); // Processing stream type for (const auto& procIter : processings) { @@ -110,7 +113,7 @@ ndk::ScopedAStatus Factory::queryProcessing(const std::optional* _aidl_return) { LOG(DEBUG) << __func__ << ": UUID " << ::android::audio::utils::toString(in_impl_uuid); + std::lock_guard lg(mMutex); if (mEffectLibMap.count(in_impl_uuid)) { auto& entry = mEffectLibMap[in_impl_uuid]; - getDlSyms(entry); + getDlSyms_l(entry); auto& libInterface = std::get(entry); RETURN_IF(!libInterface || !libInterface->createEffectFunc, EX_NULL_POINTER, @@ -152,7 +156,7 @@ ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid, return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr& in_handle) { +ndk::ScopedAStatus Factory::destroyEffectImpl_l(const std::shared_ptr& in_handle) { std::weak_ptr wpHandle(in_handle); // find the effect entry with key (std::weak_ptr) if (auto effectIt = mEffectMap.find(wpHandle); effectIt != mEffectMap.end()) { @@ -177,7 +181,7 @@ ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr& in } // go over the map and cleanup all expired weak_ptrs. -void Factory::cleanupEffectMap() { +void Factory::cleanupEffectMap_l() { for (auto it = mEffectMap.begin(); it != mEffectMap.end();) { if (nullptr == it->first.lock()) { it = mEffectMap.erase(it); @@ -189,13 +193,15 @@ void Factory::cleanupEffectMap() { ndk::ScopedAStatus Factory::destroyEffect(const std::shared_ptr& in_handle) { LOG(DEBUG) << __func__ << ": instance " << in_handle.get(); - ndk::ScopedAStatus status = destroyEffectImpl(in_handle); + std::lock_guard lg(mMutex); + ndk::ScopedAStatus status = destroyEffectImpl_l(in_handle); // always do the cleanup - cleanupEffectMap(); + cleanupEffectMap_l(); return status; } -bool Factory::openEffectLibrary(const AudioUuid& impl, const std::string& path) { +bool Factory::openEffectLibrary(const AudioUuid& impl, + const std::string& path) NO_THREAD_SAFETY_ANALYSIS { std::function dlClose = [](void* handle) -> void { if (handle && dlclose(handle)) { LOG(ERROR) << "dlclose failed " << dlerror(); @@ -219,9 +225,9 @@ bool Factory::openEffectLibrary(const AudioUuid& impl, const std::string& path) return true; } -void Factory::createIdentityWithConfig(const EffectConfig::Library& configLib, - const AudioUuid& typeUuid, - const std::optional proxyUuid) { +void Factory::createIdentityWithConfig( + const EffectConfig::Library& configLib, const AudioUuid& typeUuid, + const std::optional proxyUuid) NO_THREAD_SAFETY_ANALYSIS { static const auto& libMap = mConfig.getLibraryMap(); const std::string& libName = configLib.name; if (auto path = libMap.find(libName); path != libMap.end()) { @@ -263,7 +269,7 @@ void Factory::loadEffectLibs() { } } -void Factory::getDlSyms(DlEntry& entry) { +void Factory::getDlSyms_l(DlEntry& entry) { auto& dlHandle = std::get(entry); RETURN_VALUE_IF(!dlHandle, void(), "dlNullHandle"); // Get the reference of the DL interfaces in library map tuple. diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp index da1ad111db..c81c731c43 100644 --- a/audio/aidl/default/EffectImpl.cpp +++ b/audio/aidl/default/EffectImpl.cpp @@ -76,7 +76,7 @@ ndk::ScopedAStatus EffectImpl::close() { } ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) { - LOG(DEBUG) << getEffectName() << __func__ << " with: " << param.toString(); + LOG(VERBOSE) << getEffectName() << __func__ << " with: " << param.toString(); const auto tag = param.getTag(); switch (tag) { @@ -100,7 +100,6 @@ ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) { } ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) { - LOG(DEBUG) << getEffectName() << __func__ << id.toString(); auto tag = id.getTag(); switch (tag) { case Parameter::Id::commonTag: { @@ -117,7 +116,7 @@ ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* break; } } - LOG(DEBUG) << getEffectName() << __func__ << param->toString(); + LOG(VERBOSE) << getEffectName() << __func__ << id.toString() << param->toString(); return ndk::ScopedAStatus::ok(); } @@ -254,7 +253,7 @@ IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int samples for (int i = 0; i < samples; i++) { *out++ = *in++; } - LOG(DEBUG) << getEffectName() << __func__ << " done processing " << samples << " samples"; + LOG(VERBOSE) << getEffectName() << __func__ << " done processing " << samples << " samples"; return {STATUS_OK, samples, samples}; } diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp index 574dc69e48..cd2ba5375b 100644 --- a/audio/aidl/default/EffectThread.cpp +++ b/audio/aidl/default/EffectThread.cpp @@ -149,8 +149,8 @@ void EffectThread::process_l() { IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples); outputMQ->write(buffer, status.fmqProduced); statusMQ->writeBlocking(&status, 1); - LOG(DEBUG) << mName << __func__ << ": done processing, effect consumed " - << status.fmqConsumed << " produced " << status.fmqProduced; + LOG(VERBOSE) << mName << __func__ << ": done processing, effect consumed " + << status.fmqConsumed << " produced " << status.fmqProduced; } } diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h index 22cdb6be83..698e7a50ce 100644 --- a/audio/aidl/default/include/effect-impl/EffectContext.h +++ b/audio/aidl/default/include/effect-impl/EffectContext.h @@ -124,11 +124,11 @@ class EffectContext { virtual RetCode setCommon(const Parameter::Common& common) { mCommon = common; - LOG(INFO) << __func__ << mCommon.toString(); + LOG(VERBOSE) << __func__ << mCommon.toString(); return RetCode::SUCCESS; } virtual Parameter::Common getCommon() { - LOG(DEBUG) << __func__ << mCommon.toString(); + LOG(VERBOSE) << __func__ << mCommon.toString(); return mCommon; } diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h index b456817b45..421429acaf 100644 --- a/audio/aidl/default/include/effect-impl/EffectWorker.h +++ b/audio/aidl/default/include/effect-impl/EffectWorker.h @@ -45,8 +45,8 @@ class EffectWorker : public EffectThread { auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite(); if (readSamples && writeSamples) { auto processSamples = std::min(readSamples, writeSamples); - LOG(DEBUG) << __func__ << " available to read " << readSamples << " available to write " - << writeSamples << " process " << processSamples; + LOG(VERBOSE) << __func__ << " available to read " << readSamples + << " available to write " << writeSamples << " process " << processSamples; auto buffer = mContext->getWorkBuffer(); inputMQ->read(buffer, processSamples); @@ -54,8 +54,8 @@ class EffectWorker : public EffectThread { IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples); outputMQ->write(buffer, status.fmqProduced); statusMQ->writeBlocking(&status, 1); - LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed - << " produced " << status.fmqProduced; + LOG(VERBOSE) << __func__ << " done processing, effect consumed " << status.fmqConsumed + << " produced " << status.fmqProduced; } else { // TODO: maybe add some sleep here to avoid busy waiting } diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h index 1401db03e5..d0b820434a 100644 --- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h +++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h @@ -24,6 +24,7 @@ #include #include +#include #include "EffectConfig.h" namespace aidl::android::hardware::audio::effect { @@ -82,9 +83,11 @@ class Factory : public BnFactory { private: const EffectConfig mConfig; ~Factory(); + + std::mutex mMutex; // Set of effect descriptors supported by the devices. - std::set mDescSet; - std::set mIdentitySet; + std::set mDescSet GUARDED_BY(mMutex); + std::set mIdentitySet GUARDED_BY(mMutex); static constexpr int kMapEntryHandleIndex = 0; static constexpr int kMapEntryInterfaceIndex = 1; @@ -94,13 +97,15 @@ class Factory : public BnFactory { std::string /* library name */> DlEntry; - std::map mEffectLibMap; + std::map mEffectLibMap + GUARDED_BY(mMutex); typedef std::pair EffectEntry; - std::map, EffectEntry, std::owner_less<>> mEffectMap; + std::map, EffectEntry, std::owner_less<>> mEffectMap GUARDED_BY(mMutex); - ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr& in_handle); - void cleanupEffectMap(); + ndk::ScopedAStatus destroyEffectImpl_l(const std::shared_ptr& in_handle) + REQUIRES(mMutex); + void cleanupEffectMap_l() REQUIRES(mMutex); bool openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl, const std::string& path); void createIdentityWithConfig( @@ -108,12 +113,13 @@ class Factory : public BnFactory { const ::aidl::android::media::audio::common::AudioUuid& typeUuidStr, const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid); - ndk::ScopedAStatus getDescriptorWithUuid( - const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc); + ndk::ScopedAStatus getDescriptorWithUuid_l( + const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc) + REQUIRES(mMutex); void loadEffectLibs(); /* Get effect_dl_interface_s from library handle */ - void getDlSyms(DlEntry& entry); + void getDlSyms_l(DlEntry& entry) REQUIRES(mMutex); }; } // namespace aidl::android::hardware::audio::effect From 360c71ddabcfb4ee978f3dfa48af94a432e6b4d1 Mon Sep 17 00:00:00 2001 From: "xiaoshun.xu" Date: Tue, 11 Jul 2023 17:30:04 +0800 Subject: [PATCH 052/152] Fix vts sco test fail for usb interface [Description] If bt controller device is usb interface, sco loopback single pkt and bandwidth test can not pass because pkt size is limited accroding to core spec [Root Cause] USB sco packet size is limited in spec [Solution] If is bt usb chip, continuous receive sco packets from controller until size is enough [Test Report] Test Pass Bug: 286355871 (cherry picked from https://android-review.googlesource.com/q/commit:4e85c099593a7d337bb277afc178eda3f7e7a818) Merged-In: Idb150d8a72149f7e1dfaccfd7bc82a91710da59c Change-Id: Idb150d8a72149f7e1dfaccfd7bc82a91710da59c --- .../aidl/vts/VtsHalBluetoothTargetTest.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp index e5222a764d..24eb4d0871 100644 --- a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp +++ b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp @@ -222,6 +222,8 @@ class BluetoothAidlTest : public ::testing::TestWithParam { int wait_for_completed_packets_event(uint16_t handle); void send_and_wait_for_cmd_complete(std::unique_ptr cmd, std::vector& cmd_complete); + void reassemble_sco_loopback_pkt(std::vector& scoPackets, + size_t size); // A simple test implementation of BluetoothHciCallbacks. class BluetoothHciCallbacks @@ -569,6 +571,11 @@ void BluetoothAidlTest::sendAndCheckSco(int num_packets, size_t size, ASSERT_TRUE( sco_queue.tryPopWithTimeout(sco_loopback, kWaitForScoDataTimeout)); + if (sco_loopback.size() < size) { + // The packets may have been split for USB. Reassemble before checking. + reassemble_sco_loopback_pkt(sco_loopback, size); + } + ASSERT_EQ(sco_packet, sco_loopback); } logger.setTotalBytes(num_packets * size * 2); @@ -703,6 +710,22 @@ void BluetoothAidlTest::send_and_wait_for_cmd_complete( wait_for_command_complete_event(view.GetOpCode(), cmd_complete)); } +// Handle the loopback packet. +void BluetoothAidlTest::reassemble_sco_loopback_pkt(std::vector& scoPackets, + size_t size) { + std::vector sco_packet_whole; + sco_packet_whole.assign(scoPackets.begin(), scoPackets.end()); + while (size + 3 > sco_packet_whole.size()) { + std::vector sco_packets; + ASSERT_TRUE( + sco_queue.tryPopWithTimeout(sco_packets, kWaitForScoDataTimeout)); + sco_packet_whole.insert(sco_packet_whole.end(), sco_packets.begin() + 3, + sco_packets.end()); + } + scoPackets.assign(sco_packet_whole.begin(), sco_packet_whole.end()); + scoPackets[2] = size; +} + // Empty test: Initialize()/Close() are called in SetUp()/TearDown(). TEST_P(BluetoothAidlTest, InitializeAndClose) {} From cf892db1ef4845b9b2e85ab0481981724037509f Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Wed, 19 Jul 2023 17:20:19 +0000 Subject: [PATCH 053/152] Fix null pointer crash in AIDL radio HAL VTS Bug: 277531858 Test: atest VtsHalBroadcastradioAidlTargetTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:978de0a8a4968774e81e10e716a46bd9e1369479) Merged-In: Icb67c27b9a747411a9bfbd48647e6e6046cf5e8d Change-Id: Icb67c27b9a747411a9bfbd48647e6e6046cf5e8d --- .../aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp index 8bee1b2d1f..790d60b252 100644 --- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp +++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp @@ -997,13 +997,12 @@ TEST_P(BroadcastRadioHalTest, SetConfigFlags) { LOG(DEBUG) << "SetConfigFlags Test"; auto get = [&](ConfigFlag flag) -> bool { - bool* gotValue = nullptr; + bool gotValue; - auto halResult = mModule->isConfigFlagSet(flag, gotValue); + auto halResult = mModule->isConfigFlagSet(flag, &gotValue); - EXPECT_FALSE(gotValue == nullptr); EXPECT_TRUE(halResult.isOk()); - return *gotValue; + return gotValue; }; auto notSupportedError = resultToInt(Result::NOT_SUPPORTED); From 8fec556d253f5b3b4bd9b38f3a10f08677425164 Mon Sep 17 00:00:00 2001 From: Jeff Pu Date: Thu, 20 Jul 2023 13:07:04 +0000 Subject: [PATCH 054/152] Authentication state stays on enrollment mismatch Bug: 291778822 Test: atest FakeFingerprintEngineTest Change-Id: I4566303af982855aa0ebc52652464fb116a23858 --- biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp | 2 +- .../aidl/default/tests/FakeFingerprintEngineTest.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp index 975728764b..9f9ca96cd6 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp @@ -258,7 +258,7 @@ bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb, cb->onAuthenticationFailed(); mLockoutTracker.addFailedAttempt(); checkSensorLockout(cb); - return true; + return false; } } diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp index e7e8a476eb..bc235a6c65 100644 --- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp +++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp @@ -269,6 +269,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateNotEnrolled) { mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future()); mEngine.fingerDownAction(); ASSERT_TRUE(mCallback->mAuthenticateFailed); + ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate); } TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) { From 0ddd5410e3d4dd7323d0b1b4651c8a7b085806c4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 18 Jul 2023 02:33:58 +0000 Subject: [PATCH 055/152] Update OWNERS for Weaver Weaver does not have a clear owner, but list the people who seem to be most involved with it currently. Bug: 291284381 Test: N/A Change-Id: I69de46f8154bf91272a7197ce71c13c745a7208e (cherry picked from commit f4483a2ce98b8d863c84b4148f788ccd85db7086) Merged-In: I69de46f8154bf91272a7197ce71c13c745a7208e --- weaver/1.0/vts/functional/OWNERS | 3 --- weaver/OWNERS | 6 ++++++ weaver/aidl/vts/OWNERS | 2 -- 3 files changed, 6 insertions(+), 5 deletions(-) delete mode 100644 weaver/1.0/vts/functional/OWNERS create mode 100644 weaver/OWNERS delete mode 100644 weaver/aidl/vts/OWNERS diff --git a/weaver/1.0/vts/functional/OWNERS b/weaver/1.0/vts/functional/OWNERS deleted file mode 100644 index ec8c304b67..0000000000 --- a/weaver/1.0/vts/functional/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Bug component: 186411 -chengyouho@google.com -frankwoo@google.com diff --git a/weaver/OWNERS b/weaver/OWNERS new file mode 100644 index 0000000000..7e579f63cd --- /dev/null +++ b/weaver/OWNERS @@ -0,0 +1,6 @@ +# Bug component: 1081729 +ebiggers@google.com +paulcrowley@google.com +swillden@google.com +wfrichar@google.com +chengyouho@google.com diff --git a/weaver/aidl/vts/OWNERS b/weaver/aidl/vts/OWNERS deleted file mode 100644 index 40d95e4bf0..0000000000 --- a/weaver/aidl/vts/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -chengyouho@google.com -frankwoo@google.com From 1cd59722b67b7b745a74ea30288d4bd6f754491d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 18 Jul 2023 02:33:59 +0000 Subject: [PATCH 056/152] Make VtsHalWeaverTargetTest test both HIDL and AIDL services VtsHalWeaverTargetTest and VtsHalWeaverV1_0TargetTest are identical except for whether they use AIDL or HIDL. Unfortunately, the HIDL test is needed for several more years. For now, we have to make some substantial fixes to both tests. To make continued maintenance of this test easier, update VtsHalWeaverTargetTest to handle both AIDL and HIDL. The test cases are still written in terms of the AIDL API, so it should still be straightforward to remove HIDL support when the time comes. Bug: 291284381 Test: 'atest VtsHalWeaverTargetTest' on bramble Change-Id: I6b760930146ad1b08f17ef810a86c0058601c3bf (cherry picked from commit b59654f239745583f53fda7d62bb06f1144a347d) Merged-In: I6b760930146ad1b08f17ef810a86c0058601c3bf --- weaver/aidl/vts/Android.bp | 5 +- weaver/aidl/vts/VtsHalWeaverTargetTest.cpp | 200 ++++++++++++++++++--- 2 files changed, 181 insertions(+), 24 deletions(-) diff --git a/weaver/aidl/vts/Android.bp b/weaver/aidl/vts/Android.bp index 557fe47aa7..ee03b28136 100644 --- a/weaver/aidl/vts/Android.bp +++ b/weaver/aidl/vts/Android.bp @@ -34,7 +34,10 @@ cc_test { "libbinder_ndk", "libbase", ], - static_libs: ["android.hardware.weaver-V2-ndk"], + static_libs: [ + "android.hardware.weaver-V2-ndk", + "android.hardware.weaver@1.0", + ], test_suites: [ "general-tests", "vts", diff --git a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp index f016515a6a..b75a56f039 100644 --- a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp +++ b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include @@ -27,29 +30,162 @@ using ::aidl::android::hardware::weaver::WeaverConfig; using ::aidl::android::hardware::weaver::WeaverReadResponse; using ::aidl::android::hardware::weaver::WeaverReadStatus; -using ::ndk::SpAIBinder; +using HidlIWeaver = ::android::hardware::weaver::V1_0::IWeaver; +using HidlWeaverConfig = ::android::hardware::weaver::V1_0::WeaverConfig; +using HidlWeaverReadStatus = ::android::hardware::weaver::V1_0::WeaverReadStatus; +using HidlWeaverReadResponse = ::android::hardware::weaver::V1_0::WeaverReadResponse; +using HidlWeaverStatus = ::android::hardware::weaver::V1_0::WeaverStatus; const std::vector KEY{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; const std::vector WRONG_KEY{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const std::vector VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; const std::vector OTHER_VALUE{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 255, 255}; -struct WeaverAidlTest : public ::testing::TestWithParam { - virtual void SetUp() override { - weaver = IWeaver::fromBinder( - SpAIBinder(AServiceManager_waitForService(GetParam().c_str()))); - ASSERT_NE(weaver, nullptr); +class WeaverAdapter { + public: + virtual ~WeaverAdapter() {} + virtual bool isReady() = 0; + virtual ::ndk::ScopedAStatus getConfig(WeaverConfig* _aidl_return) = 0; + virtual ::ndk::ScopedAStatus read(int32_t in_slotId, const std::vector& in_key, + WeaverReadResponse* _aidl_return) = 0; + virtual ::ndk::ScopedAStatus write(int32_t in_slotId, const std::vector& in_key, + const std::vector& in_value) = 0; +}; + +class WeaverAidlAdapter : public WeaverAdapter { + public: + WeaverAidlAdapter(const std::string& param) + : aidl_weaver_(IWeaver::fromBinder( + ::ndk::SpAIBinder(AServiceManager_waitForService(param.c_str())))) {} + ~WeaverAidlAdapter() {} + + bool isReady() { return aidl_weaver_ != nullptr; } + + ::ndk::ScopedAStatus getConfig(WeaverConfig* _aidl_return) { + return aidl_weaver_->getConfig(_aidl_return); } - virtual void TearDown() override {} + ::ndk::ScopedAStatus read(int32_t in_slotId, const std::vector& in_key, + WeaverReadResponse* _aidl_return) { + return aidl_weaver_->read(in_slotId, in_key, _aidl_return); + } - std::shared_ptr weaver; + ::ndk::ScopedAStatus write(int32_t in_slotId, const std::vector& in_key, + const std::vector& in_value) { + return aidl_weaver_->write(in_slotId, in_key, in_value); + } + + private: + std::shared_ptr aidl_weaver_; }; +class WeaverHidlAdapter : public WeaverAdapter { + public: + WeaverHidlAdapter(const std::string& param) : hidl_weaver_(HidlIWeaver::getService(param)) {} + ~WeaverHidlAdapter() {} + + bool isReady() { return hidl_weaver_ != nullptr; } + + ::ndk::ScopedAStatus getConfig(WeaverConfig* _aidl_return) { + bool callbackCalled = false; + HidlWeaverStatus status; + HidlWeaverConfig config; + auto ret = hidl_weaver_->getConfig([&](HidlWeaverStatus s, HidlWeaverConfig c) { + callbackCalled = true; + status = s; + config = c; + }); + if (!ret.isOk() || !callbackCalled || status != HidlWeaverStatus::OK) { + return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION); + } + _aidl_return->slots = config.slots; + _aidl_return->keySize = config.keySize; + _aidl_return->valueSize = config.valueSize; + return ::ndk::ScopedAStatus::ok(); + } + + ::ndk::ScopedAStatus read(int32_t in_slotId, const std::vector& in_key, + WeaverReadResponse* _aidl_return) { + bool callbackCalled = false; + HidlWeaverReadStatus status; + std::vector value; + uint32_t timeout; + auto ret = hidl_weaver_->read(in_slotId, in_key, + [&](HidlWeaverReadStatus s, HidlWeaverReadResponse r) { + callbackCalled = true; + status = s; + value = r.value; + timeout = r.timeout; + }); + if (!ret.isOk() || !callbackCalled) { + return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION); + } + switch (status) { + case HidlWeaverReadStatus::OK: + _aidl_return->status = WeaverReadStatus::OK; + break; + case HidlWeaverReadStatus::FAILED: + _aidl_return->status = WeaverReadStatus::FAILED; + break; + case HidlWeaverReadStatus::INCORRECT_KEY: + _aidl_return->status = WeaverReadStatus::INCORRECT_KEY; + break; + case HidlWeaverReadStatus::THROTTLE: + _aidl_return->status = WeaverReadStatus::THROTTLE; + break; + default: + ADD_FAILURE() << "Unknown HIDL read status: " << static_cast(status); + _aidl_return->status = WeaverReadStatus::FAILED; + break; + } + _aidl_return->value = value; + _aidl_return->timeout = timeout; + return ::ndk::ScopedAStatus::ok(); + } + + ::ndk::ScopedAStatus write(int32_t in_slotId, const std::vector& in_key, + const std::vector& in_value) { + auto status = hidl_weaver_->write(in_slotId, in_key, in_value); + switch (status) { + case HidlWeaverStatus::OK: + return ::ndk::ScopedAStatus::ok(); + case HidlWeaverStatus::FAILED: + return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION); + default: + ADD_FAILURE() << "Unknown HIDL write status: " << status.description(); + return ::ndk::ScopedAStatus::fromStatus(STATUS_FAILED_TRANSACTION); + } + } + + private: + android::sp hidl_weaver_; +}; + +class WeaverTest : public ::testing::TestWithParam> { + protected: + void SetUp() override; + void TearDown() override {} + + std::unique_ptr weaver; +}; + +void WeaverTest::SetUp() { + std::string api, instance_name; + std::tie(api, instance_name) = GetParam(); + if (api == "hidl") { + weaver.reset(new WeaverHidlAdapter(instance_name)); + } else if (api == "aidl") { + weaver.reset(new WeaverAidlAdapter(instance_name)); + } else { + FAIL() << "Bad test parameterization"; + } + ASSERT_TRUE(weaver->isReady()); +} + /* * Checks config values are suitably large */ -TEST_P(WeaverAidlTest, GetConfig) { +TEST_P(WeaverTest, GetConfig) { WeaverConfig config; auto ret = weaver->getConfig(&config); @@ -64,7 +200,7 @@ TEST_P(WeaverAidlTest, GetConfig) { /* * Gets the config twice and checks they are the same */ -TEST_P(WeaverAidlTest, GettingConfigMultipleTimesGivesSameResult) { +TEST_P(WeaverTest, GettingConfigMultipleTimesGivesSameResult) { WeaverConfig config1; WeaverConfig config2; @@ -80,7 +216,7 @@ TEST_P(WeaverAidlTest, GettingConfigMultipleTimesGivesSameResult) { /* * Gets the number of slots from the config and writes a key and value to the last one */ -TEST_P(WeaverAidlTest, WriteToLastSlot) { +TEST_P(WeaverTest, WriteToLastSlot) { WeaverConfig config; const auto configRet = weaver->getConfig(&config); @@ -95,7 +231,7 @@ TEST_P(WeaverAidlTest, WriteToLastSlot) { * Writes a key and value to a slot * Reads the slot with the same key and receives the value that was previously written */ -TEST_P(WeaverAidlTest, WriteFollowedByReadGivesTheSameValue) { +TEST_P(WeaverTest, WriteFollowedByReadGivesTheSameValue) { constexpr uint32_t slotId = 0; const auto ret = weaver->write(slotId, KEY, VALUE); ASSERT_TRUE(ret.isOk()); @@ -121,7 +257,7 @@ TEST_P(WeaverAidlTest, WriteFollowedByReadGivesTheSameValue) { * Overwrites the slot with a new key and value * Reads the slot with the new key and receives the new value */ -TEST_P(WeaverAidlTest, OverwritingSlotUpdatesTheValue) { +TEST_P(WeaverTest, OverwritingSlotUpdatesTheValue) { constexpr uint32_t slotId = 0; const auto initialWriteRet = weaver->write(slotId, WRONG_KEY, VALUE); ASSERT_TRUE(initialWriteRet.isOk()); @@ -149,7 +285,7 @@ TEST_P(WeaverAidlTest, OverwritingSlotUpdatesTheValue) { * Writes a key and value to a slot * Reads the slot with a different key so does not receive the value */ -TEST_P(WeaverAidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) { +TEST_P(WeaverTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) { constexpr uint32_t slotId = 0; const auto ret = weaver->write(slotId, KEY, VALUE); ASSERT_TRUE(ret.isOk()); @@ -171,7 +307,7 @@ TEST_P(WeaverAidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) { /* * Writing to an invalid slot fails */ -TEST_P(WeaverAidlTest, WritingToInvalidSlotFails) { +TEST_P(WeaverTest, WritingToInvalidSlotFails) { WeaverConfig config; const auto configRet = weaver->getConfig(&config); ASSERT_TRUE(configRet.isOk()); @@ -188,7 +324,7 @@ TEST_P(WeaverAidlTest, WritingToInvalidSlotFails) { /* * Reading from an invalid slot fails rather than incorrect key */ -TEST_P(WeaverAidlTest, ReadingFromInvalidSlotFails) { +TEST_P(WeaverTest, ReadingFromInvalidSlotFails) { WeaverConfig config; const auto configRet = weaver->getConfig(&config); ASSERT_TRUE(configRet.isOk()); @@ -218,7 +354,7 @@ TEST_P(WeaverAidlTest, ReadingFromInvalidSlotFails) { /* * Writing a key that is too large fails */ -TEST_P(WeaverAidlTest, WriteWithTooLargeKeyFails) { +TEST_P(WeaverTest, WriteWithTooLargeKeyFails) { WeaverConfig config; const auto configRet = weaver->getConfig(&config); ASSERT_TRUE(configRet.isOk()); @@ -233,7 +369,7 @@ TEST_P(WeaverAidlTest, WriteWithTooLargeKeyFails) { /* * Writing a value that is too large fails */ -TEST_P(WeaverAidlTest, WriteWithTooLargeValueFails) { +TEST_P(WeaverTest, WriteWithTooLargeValueFails) { WeaverConfig config; const auto configRet = weaver->getConfig(&config); ASSERT_TRUE(configRet.isOk()); @@ -248,7 +384,7 @@ TEST_P(WeaverAidlTest, WriteWithTooLargeValueFails) { /* * Reading with a key that is loo large fails */ -TEST_P(WeaverAidlTest, ReadWithTooLargeKeyFails) { +TEST_P(WeaverTest, ReadWithTooLargeKeyFails) { WeaverConfig config; const auto configRet = weaver->getConfig(&config); ASSERT_TRUE(configRet.isOk()); @@ -273,11 +409,29 @@ TEST_P(WeaverAidlTest, ReadWithTooLargeKeyFails) { EXPECT_EQ(status, WeaverReadStatus::FAILED); } -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WeaverAidlTest); +// Instantiate the test for each HIDL Weaver service. INSTANTIATE_TEST_SUITE_P( - PerInstance, WeaverAidlTest, - testing::ValuesIn(android::getAidlHalInstanceNames(IWeaver::descriptor)), - android::PrintInstanceNameToString); + PerHidlInstance, WeaverTest, + testing::Combine(testing::Values("hidl"), + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + HidlIWeaver::descriptor))), + [](const testing::TestParamInfo>& info) { + return android::hardware::PrintInstanceNameToString( + testing::TestParamInfo{std::get<1>(info.param), info.index}); + }); + +// Instantiate the test for each AIDL Weaver service. +INSTANTIATE_TEST_SUITE_P( + PerAidlInstance, WeaverTest, + testing::Combine(testing::Values("aidl"), + testing::ValuesIn(android::getAidlHalInstanceNames(IWeaver::descriptor))), + [](const testing::TestParamInfo>& info) { + // This name_generator makes the instance name be included in the test case names, e.g. + // "PerAidlInstance/WeaverTest#GetConfig/0_android_hardware_weaver_IWeaver_default" + // instead of "PerAidlInstance/WeaverTest#GetConfig/0". + return android::PrintInstanceNameToString( + testing::TestParamInfo{std::get<1>(info.param), info.index}); + }); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); From a8fc1ea0545a136c59058fb9a2b7103c86f558f1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 18 Jul 2023 02:33:59 +0000 Subject: [PATCH 057/152] Move VtsHalWeaverTargetTest to common directory Since VtsHalWeaverTargetTest now handles both AIDL and HIDL, move it from weaver/aidl/vts/ to weaver/vts/. Bug: 291284381 Test: 'atest VtsHalWeaverTargetTest' on bramble Change-Id: Icfa0ff3b22b036110df327674fda44820057aabd (cherry picked from commit f0d6907d20a72391762e3e479e4a5833e4091b3b) Merged-In: Icfa0ff3b22b036110df327674fda44820057aabd --- weaver/{aidl => }/vts/Android.bp | 0 weaver/{aidl => }/vts/VtsHalWeaverTargetTest.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename weaver/{aidl => }/vts/Android.bp (100%) rename weaver/{aidl => }/vts/VtsHalWeaverTargetTest.cpp (100%) diff --git a/weaver/aidl/vts/Android.bp b/weaver/vts/Android.bp similarity index 100% rename from weaver/aidl/vts/Android.bp rename to weaver/vts/Android.bp diff --git a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp b/weaver/vts/VtsHalWeaverTargetTest.cpp similarity index 100% rename from weaver/aidl/vts/VtsHalWeaverTargetTest.cpp rename to weaver/vts/VtsHalWeaverTargetTest.cpp From c9691dd624fc6a080c95687936184c31c93b5a56 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 18 Jul 2023 02:33:59 +0000 Subject: [PATCH 058/152] Remove redundant HIDL Weaver VTS test Now that there is a single Weaver VTS test that covers both the HIDL and AIDL services (weaver/vts/), the HIDL-specific test can be deleted. Bug: 291284381 Test: 'atest VtsHalWeaverTargetTest' on bramble Change-Id: Ie942825c154e6792e6ffdbf0c59248de9de10d92 (cherry picked from commit e2e40d69a6185494855e691e37cea2e40c7edd2f) Merged-In: Ie942825c154e6792e6ffdbf0c59248de9de10d92 --- weaver/1.0/vts/functional/Android.bp | 32 -- .../functional/VtsHalWeaverV1_0TargetTest.cpp | 343 ------------------ 2 files changed, 375 deletions(-) delete mode 100644 weaver/1.0/vts/functional/Android.bp delete mode 100644 weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp diff --git a/weaver/1.0/vts/functional/Android.bp b/weaver/1.0/vts/functional/Android.bp deleted file mode 100644 index cc1d28465d..0000000000 --- a/weaver/1.0/vts/functional/Android.bp +++ /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. -// - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_interfaces_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_interfaces_license"], -} - -cc_test { - name: "VtsHalWeaverV1_0TargetTest", - defaults: ["VtsHalTargetTestDefaults"], - srcs: ["VtsHalWeaverV1_0TargetTest.cpp"], - static_libs: ["android.hardware.weaver@1.0"], - test_suites: ["general-tests", "vts"], -} diff --git a/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp b/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp deleted file mode 100644 index 66465a9798..0000000000 --- a/weaver/1.0/vts/functional/VtsHalWeaverV1_0TargetTest.cpp +++ /dev/null @@ -1,343 +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 - -#include - -using ::android::hardware::weaver::V1_0::IWeaver; -using ::android::hardware::weaver::V1_0::WeaverConfig; -using ::android::hardware::weaver::V1_0::WeaverReadStatus; -using ::android::hardware::weaver::V1_0::WeaverReadResponse; -using ::android::hardware::weaver::V1_0::WeaverStatus; -using ::android::hardware::Return; -using ::android::sp; - -const std::vector KEY{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; -const std::vector WRONG_KEY{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -const std::vector VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; -const std::vector OTHER_VALUE{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 255, 255}; - -struct WeaverHidlTest : public ::testing::TestWithParam { - virtual void SetUp() override { - weaver = IWeaver::getService(GetParam()); - ASSERT_NE(weaver, nullptr); - } - - virtual void TearDown() override {} - - sp weaver; -}; - -/* - * Checks config values are suitably large - */ -TEST_P(WeaverHidlTest, GetConfig) { - WeaverStatus status; - WeaverConfig config; - - bool callbackCalled = false; - auto ret = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - callbackCalled = true; - status = s; - config = c; - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(callbackCalled); - ASSERT_EQ(status, WeaverStatus::OK); - - EXPECT_GE(config.slots, 16u); - EXPECT_GE(config.keySize, 16u); - EXPECT_GE(config.valueSize, 16u); -} - -/* - * Gets the config twice and checks they are the same - */ -TEST_P(WeaverHidlTest, GettingConfigMultipleTimesGivesSameResult) { - WeaverConfig config1; - WeaverConfig config2; - - WeaverStatus status; - bool callbackCalled = false; - auto ret = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - callbackCalled = true; - status = s; - config1 = c; - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(callbackCalled); - ASSERT_EQ(status, WeaverStatus::OK); - - callbackCalled = false; - ret = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - callbackCalled = true; - status = s; - config2 = c; - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_TRUE(callbackCalled); - ASSERT_EQ(status, WeaverStatus::OK); - - EXPECT_EQ(config1, config2); -} - -/* - * Gets the number of slots from the config and writes a key and value to the last one - */ -TEST_P(WeaverHidlTest, WriteToLastSlot) { - WeaverStatus status; - WeaverConfig config; - const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - status = s; - config = c; - }); - ASSERT_TRUE(configRet.isOk()); - ASSERT_EQ(status, WeaverStatus::OK); - - const uint32_t lastSlot = config.slots - 1; - const auto writeRet = weaver->write(lastSlot, KEY, VALUE); - ASSERT_TRUE(writeRet.isOk()); - ASSERT_EQ(writeRet, WeaverStatus::OK); -} - -/* - * Writes a key and value to a slot - * Reads the slot with the same key and receives the value that was previously written - */ -TEST_P(WeaverHidlTest, WriteFollowedByReadGivesTheSameValue) { - constexpr uint32_t slotId = 0; - const auto ret = weaver->write(slotId, KEY, VALUE); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(ret, WeaverStatus::OK); - - bool callbackCalled = false; - WeaverReadStatus status; - std::vector readValue; - uint32_t timeout; - const auto readRet = weaver->read(slotId, KEY, [&](WeaverReadStatus s, WeaverReadResponse r) { - callbackCalled = true; - status = s; - readValue = r.value; - timeout = r.timeout; - }); - ASSERT_TRUE(readRet.isOk()); - ASSERT_TRUE(callbackCalled); - ASSERT_EQ(status, WeaverReadStatus::OK); - EXPECT_EQ(readValue, VALUE); - EXPECT_EQ(timeout, 0u); -} - -/* - * Writes a key and value to a slot - * Overwrites the slot with a new key and value - * Reads the slot with the new key and receives the new value - */ -TEST_P(WeaverHidlTest, OverwritingSlotUpdatesTheValue) { - constexpr uint32_t slotId = 0; - const auto initialWriteRet = weaver->write(slotId, WRONG_KEY, VALUE); - ASSERT_TRUE(initialWriteRet.isOk()); - ASSERT_EQ(initialWriteRet, WeaverStatus::OK); - - const auto overwriteRet = weaver->write(slotId, KEY, OTHER_VALUE); - ASSERT_TRUE(overwriteRet.isOk()); - ASSERT_EQ(overwriteRet, WeaverStatus::OK); - - bool callbackCalled = false; - WeaverReadStatus status; - std::vector readValue; - uint32_t timeout; - const auto readRet = weaver->read(slotId, KEY, [&](WeaverReadStatus s, WeaverReadResponse r) { - callbackCalled = true; - status = s; - readValue = r.value; - timeout = r.timeout; - }); - ASSERT_TRUE(readRet.isOk()); - ASSERT_TRUE(callbackCalled); - ASSERT_EQ(status, WeaverReadStatus::OK); - EXPECT_EQ(readValue, OTHER_VALUE); - EXPECT_EQ(timeout, 0u); -} - -/* - * Writes a key and value to a slot - * Reads the slot with a different key so does not receive the value - */ -TEST_P(WeaverHidlTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) { - constexpr uint32_t slotId = 0; - const auto ret = weaver->write(slotId, KEY, VALUE); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(ret, WeaverStatus::OK); - - bool callbackCalled = false; - WeaverReadStatus status; - std::vector readValue; - const auto readRet = - weaver->read(slotId, WRONG_KEY, [&](WeaverReadStatus s, WeaverReadResponse r) { - callbackCalled = true; - status = s; - readValue = r.value; - }); - ASSERT_TRUE(callbackCalled); - ASSERT_TRUE(readRet.isOk()); - ASSERT_EQ(status, WeaverReadStatus::INCORRECT_KEY); - EXPECT_TRUE(readValue.empty()); -} - -/* - * Writing to an invalid slot fails - */ -TEST_P(WeaverHidlTest, WritingToInvalidSlotFails) { - WeaverStatus status; - WeaverConfig config; - const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - status = s; - config = c; - }); - ASSERT_TRUE(configRet.isOk()); - ASSERT_EQ(status, WeaverStatus::OK); - - if (config.slots == std::numeric_limits::max()) { - // If there are no invalid slots then pass - return; - } - - const auto writeRet = weaver->write(config.slots, KEY, VALUE); - ASSERT_TRUE(writeRet.isOk()); - ASSERT_EQ(writeRet, WeaverStatus::FAILED); -} - -/* - * Reading from an invalid slot fails rather than incorrect key - */ -TEST_P(WeaverHidlTest, ReadingFromInvalidSlotFails) { - WeaverStatus status; - WeaverConfig config; - const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - status = s; - config = c; - }); - ASSERT_TRUE(configRet.isOk()); - ASSERT_EQ(status, WeaverStatus::OK); - - if (config.slots == std::numeric_limits::max()) { - // If there are no invalid slots then pass - return; - } - - bool callbackCalled = false; - WeaverReadStatus readStatus; - std::vector readValue; - uint32_t timeout; - const auto readRet = - weaver->read(config.slots, KEY, [&](WeaverReadStatus s, WeaverReadResponse r) { - callbackCalled = true; - readStatus = s; - readValue = r.value; - timeout = r.timeout; - }); - ASSERT_TRUE(callbackCalled); - ASSERT_TRUE(readRet.isOk()); - ASSERT_EQ(readStatus, WeaverReadStatus::FAILED); - EXPECT_TRUE(readValue.empty()); - EXPECT_EQ(timeout, 0u); -} - -/* - * Writing a key that is too large fails - */ -TEST_P(WeaverHidlTest, WriteWithTooLargeKeyFails) { - WeaverStatus status; - WeaverConfig config; - const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - status = s; - config = c; - }); - ASSERT_TRUE(configRet.isOk()); - ASSERT_EQ(status, WeaverStatus::OK); - - std::vector bigKey(config.keySize + 1); - - constexpr uint32_t slotId = 0; - const auto writeRet = weaver->write(slotId, bigKey, VALUE); - ASSERT_TRUE(writeRet.isOk()); - ASSERT_EQ(writeRet, WeaverStatus::FAILED); -} - -/* - * Writing a value that is too large fails - */ -TEST_P(WeaverHidlTest, WriteWithTooLargeValueFails) { - WeaverStatus status; - WeaverConfig config; - const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - status = s; - config = c; - }); - ASSERT_TRUE(configRet.isOk()); - ASSERT_EQ(status, WeaverStatus::OK); - - std::vector bigValue(config.valueSize + 1); - - constexpr uint32_t slotId = 0; - const auto writeRet = weaver->write(slotId, KEY, bigValue); - ASSERT_TRUE(writeRet.isOk()); - ASSERT_EQ(writeRet, WeaverStatus::FAILED); -} - -/* - * Reading with a key that is loo large fails - */ -TEST_P(WeaverHidlTest, ReadWithTooLargeKeyFails) { - WeaverStatus status; - WeaverConfig config; - const auto configRet = weaver->getConfig([&](WeaverStatus s, WeaverConfig c) { - status = s; - config = c; - }); - ASSERT_TRUE(configRet.isOk()); - ASSERT_EQ(status, WeaverStatus::OK); - - std::vector bigKey(config.keySize + 1); - - constexpr uint32_t slotId = 0; - bool callbackCalled = false; - WeaverReadStatus readStatus; - std::vector readValue; - uint32_t timeout; - const auto readRet = - weaver->read(slotId, bigKey, [&](WeaverReadStatus s, WeaverReadResponse r) { - callbackCalled = true; - readStatus = s; - readValue = r.value; - timeout = r.timeout; - }); - ASSERT_TRUE(callbackCalled); - ASSERT_TRUE(readRet.isOk()); - ASSERT_EQ(readStatus, WeaverReadStatus::FAILED); - EXPECT_TRUE(readValue.empty()); - EXPECT_EQ(timeout, 0u); -} - -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WeaverHidlTest); -INSTANTIATE_TEST_SUITE_P( - PerInstance, WeaverHidlTest, - testing::ValuesIn(android::hardware::getAllHalInstanceNames(IWeaver::descriptor)), - android::hardware::PrintInstanceNameToString); From 42d76ae5dfa9aae45f0f971946ec9e962b21c8b6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 18 Jul 2023 02:34:00 +0000 Subject: [PATCH 059/152] Simplify Weaver VTS test - Get the config in SetUp() so that it's easily available to test cases. - Rename "weaver" class member to "weaver_" to match coding style. - Eliminate unnecessary variables when checking WeaverReadResponse. - Fix a typo. Bug: 291284381 Test: 'atest VtsHalWeaverTargetTest' on bramble Change-Id: Ia6dca996103057bfdc9002bc9ab2c039e2333ed9 (cherry picked from commit 961a138e47542b46b574f1f9ba94177e89e06c11) Merged-In: Ia6dca996103057bfdc9002bc9ab2c039e2333ed9 --- weaver/vts/VtsHalWeaverTargetTest.cpp | 171 ++++++++------------------ 1 file changed, 51 insertions(+), 120 deletions(-) diff --git a/weaver/vts/VtsHalWeaverTargetTest.cpp b/weaver/vts/VtsHalWeaverTargetTest.cpp index b75a56f039..047481e123 100644 --- a/weaver/vts/VtsHalWeaverTargetTest.cpp +++ b/weaver/vts/VtsHalWeaverTargetTest.cpp @@ -166,64 +166,56 @@ class WeaverTest : public ::testing::TestWithParam weaver; + std::unique_ptr weaver_; + WeaverConfig config_; }; void WeaverTest::SetUp() { std::string api, instance_name; std::tie(api, instance_name) = GetParam(); if (api == "hidl") { - weaver.reset(new WeaverHidlAdapter(instance_name)); + weaver_.reset(new WeaverHidlAdapter(instance_name)); } else if (api == "aidl") { - weaver.reset(new WeaverAidlAdapter(instance_name)); + weaver_.reset(new WeaverAidlAdapter(instance_name)); } else { FAIL() << "Bad test parameterization"; } - ASSERT_TRUE(weaver->isReady()); + ASSERT_TRUE(weaver_->isReady()); + + auto ret = weaver_->getConfig(&config_); + ASSERT_TRUE(ret.isOk()); + ASSERT_GT(config_.slots, 0); + GTEST_LOG_(INFO) << "WeaverConfig: slots=" << config_.slots << ", keySize=" << config_.keySize + << ", valueSize=" << config_.valueSize; } /* * Checks config values are suitably large */ TEST_P(WeaverTest, GetConfig) { - WeaverConfig config; - - auto ret = weaver->getConfig(&config); - - ASSERT_TRUE(ret.isOk()); - - EXPECT_GE(config.slots, 16u); - EXPECT_GE(config.keySize, 16u); - EXPECT_GE(config.valueSize, 16u); + EXPECT_GE(config_.slots, 16u); + EXPECT_GE(config_.keySize, 16u); + EXPECT_GE(config_.valueSize, 16u); } /* * Gets the config twice and checks they are the same */ TEST_P(WeaverTest, GettingConfigMultipleTimesGivesSameResult) { - WeaverConfig config1; WeaverConfig config2; - auto ret = weaver->getConfig(&config1); + auto ret = weaver_->getConfig(&config2); ASSERT_TRUE(ret.isOk()); - ret = weaver->getConfig(&config2); - ASSERT_TRUE(ret.isOk()); - - EXPECT_EQ(config1, config2); + EXPECT_EQ(config_, config2); } /* * Gets the number of slots from the config and writes a key and value to the last one */ TEST_P(WeaverTest, WriteToLastSlot) { - WeaverConfig config; - const auto configRet = weaver->getConfig(&config); - - ASSERT_TRUE(configRet.isOk()); - - const uint32_t lastSlot = config.slots - 1; - const auto writeRet = weaver->write(lastSlot, KEY, VALUE); + const uint32_t lastSlot = config_.slots - 1; + const auto writeRet = weaver_->write(lastSlot, KEY, VALUE); ASSERT_TRUE(writeRet.isOk()); } @@ -233,23 +225,15 @@ TEST_P(WeaverTest, WriteToLastSlot) { */ TEST_P(WeaverTest, WriteFollowedByReadGivesTheSameValue) { constexpr uint32_t slotId = 0; - const auto ret = weaver->write(slotId, KEY, VALUE); + const auto ret = weaver_->write(slotId, KEY, VALUE); ASSERT_TRUE(ret.isOk()); WeaverReadResponse response; - std::vector readValue; - uint32_t timeout; - WeaverReadStatus status; - const auto readRet = weaver->read(slotId, KEY, &response); - - readValue = response.value; - timeout = response.timeout; - status = response.status; - + const auto readRet = weaver_->read(slotId, KEY, &response); ASSERT_TRUE(readRet.isOk()); - EXPECT_EQ(readValue, VALUE); - EXPECT_EQ(timeout, 0u); - EXPECT_EQ(status, WeaverReadStatus::OK); + EXPECT_EQ(response.value, VALUE); + EXPECT_EQ(response.timeout, 0u); + EXPECT_EQ(response.status, WeaverReadStatus::OK); } /* @@ -259,26 +243,18 @@ TEST_P(WeaverTest, WriteFollowedByReadGivesTheSameValue) { */ TEST_P(WeaverTest, OverwritingSlotUpdatesTheValue) { constexpr uint32_t slotId = 0; - const auto initialWriteRet = weaver->write(slotId, WRONG_KEY, VALUE); + const auto initialWriteRet = weaver_->write(slotId, WRONG_KEY, VALUE); ASSERT_TRUE(initialWriteRet.isOk()); - const auto overwriteRet = weaver->write(slotId, KEY, OTHER_VALUE); + const auto overwriteRet = weaver_->write(slotId, KEY, OTHER_VALUE); ASSERT_TRUE(overwriteRet.isOk()); WeaverReadResponse response; - std::vector readValue; - uint32_t timeout; - WeaverReadStatus status; - const auto readRet = weaver->read(slotId, KEY, &response); - - readValue = response.value; - timeout = response.timeout; - status = response.status; - + const auto readRet = weaver_->read(slotId, KEY, &response); ASSERT_TRUE(readRet.isOk()); - EXPECT_EQ(readValue, OTHER_VALUE); - EXPECT_EQ(timeout, 0u); - EXPECT_EQ(status, WeaverReadStatus::OK); + EXPECT_EQ(response.value, OTHER_VALUE); + EXPECT_EQ(response.timeout, 0u); + EXPECT_EQ(response.status, WeaverReadStatus::OK); } /* @@ -287,37 +263,26 @@ TEST_P(WeaverTest, OverwritingSlotUpdatesTheValue) { */ TEST_P(WeaverTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) { constexpr uint32_t slotId = 0; - const auto ret = weaver->write(slotId, KEY, VALUE); - ASSERT_TRUE(ret.isOk()); + const auto writeRet = weaver_->write(slotId, KEY, VALUE); + ASSERT_TRUE(writeRet.isOk()); WeaverReadResponse response; - std::vector readValue; - WeaverReadStatus status; - const auto readRet = - weaver->read(slotId, WRONG_KEY, &response); - - readValue = response.value; - status = response.status; - + const auto readRet = weaver_->read(slotId, WRONG_KEY, &response); ASSERT_TRUE(readRet.isOk()); - EXPECT_TRUE(readValue.empty()); - EXPECT_EQ(status, WeaverReadStatus::INCORRECT_KEY); + EXPECT_TRUE(response.value.empty()); + EXPECT_EQ(response.status, WeaverReadStatus::INCORRECT_KEY); } /* * Writing to an invalid slot fails */ TEST_P(WeaverTest, WritingToInvalidSlotFails) { - WeaverConfig config; - const auto configRet = weaver->getConfig(&config); - ASSERT_TRUE(configRet.isOk()); - - if (config.slots == std::numeric_limits::max()) { + if (config_.slots == std::numeric_limits::max()) { // If there are no invalid slots then pass return; } - const auto writeRet = weaver->write(config.slots, KEY, VALUE); + const auto writeRet = weaver_->write(config_.slots, KEY, VALUE); ASSERT_FALSE(writeRet.isOk()); } @@ -325,44 +290,27 @@ TEST_P(WeaverTest, WritingToInvalidSlotFails) { * Reading from an invalid slot fails rather than incorrect key */ TEST_P(WeaverTest, ReadingFromInvalidSlotFails) { - WeaverConfig config; - const auto configRet = weaver->getConfig(&config); - ASSERT_TRUE(configRet.isOk()); - - if (config.slots == std::numeric_limits::max()) { + if (config_.slots == std::numeric_limits::max()) { // If there are no invalid slots then pass return; } WeaverReadResponse response; - std::vector readValue; - uint32_t timeout; - WeaverReadStatus status; - const auto readRet = - weaver->read(config.slots, KEY, &response); - - readValue = response.value; - timeout = response.timeout; - status = response.status; - + const auto readRet = weaver_->read(config_.slots, KEY, &response); ASSERT_TRUE(readRet.isOk()); - EXPECT_TRUE(readValue.empty()); - EXPECT_EQ(timeout, 0u); - EXPECT_EQ(status, WeaverReadStatus::FAILED); + EXPECT_TRUE(response.value.empty()); + EXPECT_EQ(response.timeout, 0u); + EXPECT_EQ(response.status, WeaverReadStatus::FAILED); } /* * Writing a key that is too large fails */ TEST_P(WeaverTest, WriteWithTooLargeKeyFails) { - WeaverConfig config; - const auto configRet = weaver->getConfig(&config); - ASSERT_TRUE(configRet.isOk()); - - std::vector bigKey(config.keySize + 1); + std::vector bigKey(config_.keySize + 1); constexpr uint32_t slotId = 0; - const auto writeRet = weaver->write(slotId, bigKey, VALUE); + const auto writeRet = weaver_->write(slotId, bigKey, VALUE); ASSERT_FALSE(writeRet.isOk()); } @@ -370,43 +318,26 @@ TEST_P(WeaverTest, WriteWithTooLargeKeyFails) { * Writing a value that is too large fails */ TEST_P(WeaverTest, WriteWithTooLargeValueFails) { - WeaverConfig config; - const auto configRet = weaver->getConfig(&config); - ASSERT_TRUE(configRet.isOk()); - - std::vector bigValue(config.valueSize + 1); + std::vector bigValue(config_.valueSize + 1); constexpr uint32_t slotId = 0; - const auto writeRet = weaver->write(slotId, KEY, bigValue); + const auto writeRet = weaver_->write(slotId, KEY, bigValue); ASSERT_FALSE(writeRet.isOk()); } /* - * Reading with a key that is loo large fails + * Reading with a key that is too large fails */ TEST_P(WeaverTest, ReadWithTooLargeKeyFails) { - WeaverConfig config; - const auto configRet = weaver->getConfig(&config); - ASSERT_TRUE(configRet.isOk()); - - std::vector bigKey(config.keySize + 1); + std::vector bigKey(config_.keySize + 1); constexpr uint32_t slotId = 0; WeaverReadResponse response; - std::vector readValue; - uint32_t timeout; - WeaverReadStatus status; - const auto readRet = - weaver->read(slotId, bigKey, &response); - - readValue = response.value; - timeout = response.timeout; - status = response.status; - + const auto readRet = weaver_->read(slotId, bigKey, &response); ASSERT_TRUE(readRet.isOk()); - EXPECT_TRUE(readValue.empty()); - EXPECT_EQ(timeout, 0u); - EXPECT_EQ(status, WeaverReadStatus::FAILED); + EXPECT_TRUE(response.value.empty()); + EXPECT_EQ(response.timeout, 0u); + EXPECT_EQ(response.status, WeaverReadStatus::FAILED); } // Instantiate the test for each HIDL Weaver service. From 86b9048544e01f3af3cd055ae841c007979018d3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 18 Jul 2023 02:34:00 +0000 Subject: [PATCH 060/152] Don't overwrite in-use Weaver slots during VTS VtsHalWeaverTargetTest always overwrote the first and last Weaver slots. Before Android 14, apparently this didn't cause problems because Android didn't use Weaver for users that never had an LSKF set. However, now users get a Weaver slot right away. That typically means that the first Weaver slot will be used by user 0. Fix the test to read /metadata/password_slots/slot_map to determine which slots are in use by the system, and only write to unused slots. Bug: 291284381 Test: 'atest -v VtsHalWeaverTargetTest'. Checked for INFO messages showing that slots 1 and 63 were used by the test. Then rebooted and verified that the device can still be unlocked. Change-Id: Id2cce4240d68999471e7d1e8fc7a8449587eed97 (cherry picked from commit 31380e7bc9122147e7a5d65cc1739ab78f853b24) Merged-In: Id2cce4240d68999471e7d1e8fc7a8449587eed97 --- weaver/vts/VtsHalWeaverTargetTest.cpp | 77 ++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/weaver/vts/VtsHalWeaverTargetTest.cpp b/weaver/vts/VtsHalWeaverTargetTest.cpp index 047481e123..9ee6d93cf0 100644 --- a/weaver/vts/VtsHalWeaverTargetTest.cpp +++ b/weaver/vts/VtsHalWeaverTargetTest.cpp @@ -17,6 +17,9 @@ #include #include +#include +#include +#include #include #include #include @@ -36,6 +39,7 @@ using HidlWeaverReadStatus = ::android::hardware::weaver::V1_0::WeaverReadStatus using HidlWeaverReadResponse = ::android::hardware::weaver::V1_0::WeaverReadResponse; using HidlWeaverStatus = ::android::hardware::weaver::V1_0::WeaverStatus; +const std::string kSlotMapFile = "/metadata/password_slots/slot_map"; const std::vector KEY{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; const std::vector WRONG_KEY{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const std::vector VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; @@ -165,9 +169,12 @@ class WeaverTest : public ::testing::TestWithParam weaver_; WeaverConfig config_; + uint32_t first_free_slot_; + uint32_t last_free_slot_; }; void WeaverTest::SetUp() { @@ -187,6 +194,56 @@ void WeaverTest::SetUp() { ASSERT_GT(config_.slots, 0); GTEST_LOG_(INFO) << "WeaverConfig: slots=" << config_.slots << ", keySize=" << config_.keySize << ", valueSize=" << config_.valueSize; + + FindFreeSlots(); + GTEST_LOG_(INFO) << "First free slot is " << first_free_slot_ << ", last free slot is " + << last_free_slot_; +} + +void WeaverTest::FindFreeSlots() { + // Determine which Weaver slots are in use by the system. These slots can't be used by the test. + std::set used_slots; + if (access(kSlotMapFile.c_str(), F_OK) == 0) { + std::string contents; + ASSERT_TRUE(android::base::ReadFileToString(kSlotMapFile, &contents)) + << "Failed to read " << kSlotMapFile; + for (const auto& line : android::base::Split(contents, "\n")) { + auto trimmed_line = android::base::Trim(line); + if (trimmed_line[0] == '#' || trimmed_line[0] == '\0') continue; + auto slot_and_user = android::base::Split(trimmed_line, "="); + uint32_t slot; + ASSERT_TRUE(slot_and_user.size() == 2 && + android::base::ParseUint(slot_and_user[0], &slot)) + << "Error parsing " << kSlotMapFile << " at \"" << line << "\""; + GTEST_LOG_(INFO) << "Slot " << slot << " is in use by " << slot_and_user[1]; + ASSERT_LT(slot, config_.slots); + used_slots.insert(slot); + } + } + // Starting in Android 14, the system will always use at least one Weaver slot if Weaver is + // supported at all. Make sure we saw at least one. + // TODO: uncomment after Android 14 is merged into AOSP + // ASSERT_FALSE(used_slots.empty()) + //<< "Could not determine which Weaver slots are in use by the system"; + + // Find the first free slot. + int found = 0; + for (uint32_t i = 0; i < config_.slots; i++) { + if (used_slots.find(i) == used_slots.end()) { + first_free_slot_ = i; + found++; + break; + } + } + // Find the last free slot. + for (uint32_t i = config_.slots; i > 0; i--) { + if (used_slots.find(i - 1) == used_slots.end()) { + last_free_slot_ = i - 1; + found++; + break; + } + } + ASSERT_EQ(found, 2) << "All Weaver slots are already in use by the system"; } /* @@ -211,11 +268,10 @@ TEST_P(WeaverTest, GettingConfigMultipleTimesGivesSameResult) { } /* - * Gets the number of slots from the config and writes a key and value to the last one + * Writes a key and value to the last free slot */ TEST_P(WeaverTest, WriteToLastSlot) { - const uint32_t lastSlot = config_.slots - 1; - const auto writeRet = weaver_->write(lastSlot, KEY, VALUE); + const auto writeRet = weaver_->write(last_free_slot_, KEY, VALUE); ASSERT_TRUE(writeRet.isOk()); } @@ -224,7 +280,7 @@ TEST_P(WeaverTest, WriteToLastSlot) { * Reads the slot with the same key and receives the value that was previously written */ TEST_P(WeaverTest, WriteFollowedByReadGivesTheSameValue) { - constexpr uint32_t slotId = 0; + const uint32_t slotId = first_free_slot_; const auto ret = weaver_->write(slotId, KEY, VALUE); ASSERT_TRUE(ret.isOk()); @@ -242,7 +298,7 @@ TEST_P(WeaverTest, WriteFollowedByReadGivesTheSameValue) { * Reads the slot with the new key and receives the new value */ TEST_P(WeaverTest, OverwritingSlotUpdatesTheValue) { - constexpr uint32_t slotId = 0; + const uint32_t slotId = first_free_slot_; const auto initialWriteRet = weaver_->write(slotId, WRONG_KEY, VALUE); ASSERT_TRUE(initialWriteRet.isOk()); @@ -262,7 +318,7 @@ TEST_P(WeaverTest, OverwritingSlotUpdatesTheValue) { * Reads the slot with a different key so does not receive the value */ TEST_P(WeaverTest, WriteFollowedByReadWithWrongKeyDoesNotGiveTheValue) { - constexpr uint32_t slotId = 0; + const uint32_t slotId = first_free_slot_; const auto writeRet = weaver_->write(slotId, KEY, VALUE); ASSERT_TRUE(writeRet.isOk()); @@ -309,8 +365,7 @@ TEST_P(WeaverTest, ReadingFromInvalidSlotFails) { TEST_P(WeaverTest, WriteWithTooLargeKeyFails) { std::vector bigKey(config_.keySize + 1); - constexpr uint32_t slotId = 0; - const auto writeRet = weaver_->write(slotId, bigKey, VALUE); + const auto writeRet = weaver_->write(first_free_slot_, bigKey, VALUE); ASSERT_FALSE(writeRet.isOk()); } @@ -320,8 +375,7 @@ TEST_P(WeaverTest, WriteWithTooLargeKeyFails) { TEST_P(WeaverTest, WriteWithTooLargeValueFails) { std::vector bigValue(config_.valueSize + 1); - constexpr uint32_t slotId = 0; - const auto writeRet = weaver_->write(slotId, KEY, bigValue); + const auto writeRet = weaver_->write(first_free_slot_, KEY, bigValue); ASSERT_FALSE(writeRet.isOk()); } @@ -331,9 +385,8 @@ TEST_P(WeaverTest, WriteWithTooLargeValueFails) { TEST_P(WeaverTest, ReadWithTooLargeKeyFails) { std::vector bigKey(config_.keySize + 1); - constexpr uint32_t slotId = 0; WeaverReadResponse response; - const auto readRet = weaver_->read(slotId, bigKey, &response); + const auto readRet = weaver_->read(first_free_slot_, bigKey, &response); ASSERT_TRUE(readRet.isOk()); EXPECT_TRUE(response.value.empty()); EXPECT_EQ(response.timeout, 0u); From 5f02a641416b2c3a933b5264044d07cca894c3a8 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Tue, 18 Jul 2023 21:20:33 +0000 Subject: [PATCH 061/152] Update effect AIDL state machine graph Bug: 271500140 Test: dot -Tpng state.gv -o state.png (cherry picked from https://android-review.googlesource.com/q/commit:a8c5e014db942d84340fcdd8e75cc5359ef03e44) Merged-In: Icbabe75e24497594f8bc62985553c1c13d268dae Change-Id: Icbabe75e24497594f8bc62985553c1c13d268dae --- audio/aidl/android/hardware/audio/effect/state.gv | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv index c88521e316..ce369ba5c8 100644 --- a/audio/aidl/android/hardware/audio/effect/state.gv +++ b/audio/aidl/android/hardware/audio/effect/state.gv @@ -25,12 +25,12 @@ digraph effect_state_machine { I -> INIT[label = "IFactory.createEffect" labelfontcolor = "navy"]; INIT -> F[label = "IFactory.destroyEffect"]; - INIT -> IDLE[label = "open()" labelfontcolor = "lime"]; - IDLE -> PROCESSING[label = "command(START"]; - PROCESSING -> IDLE[label = "command(STOP)\ncommand(RESET)"]; - IDLE -> INIT[label = "close()"]; + INIT -> IDLE[label = "IEffect.open()" labelfontcolor = "lime"]; + IDLE -> PROCESSING[label = "IEffect.command(START"]; + PROCESSING -> IDLE[label = "IEffect.command(STOP)\nIEffect.command(RESET)"]; + IDLE -> INIT[label = "IEffect.close()"]; - INIT -> INIT[label = "getState\ngetDescriptor"]; - IDLE -> IDLE[label = "getXXX\nsetParameter\ncommand(RESET)"]; - PROCESSING -> PROCESSING[label = "getXXX\nsetParameter"]; + INIT -> INIT[label = "IEffect.getState\nIEffect.getDescriptor"]; + IDLE -> IDLE[label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.command(RESET)"]; + PROCESSING -> PROCESSING[label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor"]; } From 821d5c05c2c4086dc07e23f88ee5b119fbb0d9f7 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 20 Jul 2023 19:11:37 +0000 Subject: [PATCH 062/152] Support per-port display configs in VTS Bug: 277855934 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:be1b4d6ccec45f47bbb9459bf9aa31b4c6875c7b) Merged-In: I92e1615d8eb9466b40e02f8e2df8b3432e927af6 Change-Id: I92e1615d8eb9466b40e02f8e2df8b3432e927af6 --- .../VtsHalGraphicsComposer3_ReadbackTest.cpp | 80 +++++++++++++------ 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp index b0472209dc..269abd150d 100644 --- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp +++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp @@ -129,33 +129,20 @@ class GraphicsCompositionTestBase : public ::testing::Test { return {false, graphicBuffer}; } - uint64_t getStableDisplayId(int64_t display) { - const auto& [status, identification] = - mComposerClient->getDisplayIdentificationData(display); - EXPECT_TRUE(status.isOk()); - - if (const auto info = ::android::parseDisplayIdentificationData( - static_cast(identification.port), identification.data)) { - return info->id.value; - } - - return ::android::PhysicalDisplayId::fromPort(static_cast(identification.port)) - .value; - } - // Gets the per-display XML config std::unique_ptr getDisplayConfigXml(int64_t display) { - std::stringstream pathBuilder; - pathBuilder << "/vendor/etc/displayconfig/display_id_" << getStableDisplayId(display) - << ".xml"; - const std::string path = pathBuilder.str(); - auto document = std::make_unique(); - const tinyxml2::XMLError error = document->LoadFile(path.c_str()); - if (error == tinyxml2::XML_SUCCESS) { + + if (auto document = getDisplayConfigXmlByStableId(getStableDisplayId(display)); + document != nullptr) { return document; - } else { - return nullptr; } + + // Fallback to looking up a per-port config if no config exists for the full ID + if (auto document = getDisplayConfigXmlByPort(getPort(display)); document != nullptr) { + return document; + } + + return nullptr; } // Gets the max display brightness for this display. @@ -256,6 +243,53 @@ class GraphicsCompositionTestBase : public ::testing::Test { } } } + + uint8_t getPort(int64_t display) { + const auto& [status, identification] = + mComposerClient->getDisplayIdentificationData(display); + EXPECT_TRUE(status.isOk()); + return static_cast(identification.port); + } + + uint64_t getStableDisplayId(int64_t display) { + const auto& [status, identification] = + mComposerClient->getDisplayIdentificationData(display); + EXPECT_TRUE(status.isOk()); + + if (const auto info = ::android::parseDisplayIdentificationData( + static_cast(identification.port), identification.data)) { + return info->id.value; + } + + return ::android::PhysicalDisplayId::fromPort(static_cast(identification.port)) + .value; + } + + std::unique_ptr loadXml(const std::string& path) { + auto document = std::make_unique(); + const tinyxml2::XMLError error = document->LoadFile(path.c_str()); + if (error != tinyxml2::XML_SUCCESS) { + ALOGD("%s: Failed to load config file: %s", __func__, path.c_str()); + return nullptr; + } + + ALOGD("%s: Successfully loaded config file: %s", __func__, path.c_str()); + return document; + } + + std::unique_ptr getDisplayConfigXmlByPort(uint8_t port) { + std::stringstream pathBuilder; + pathBuilder << "/vendor/etc/displayconfig/display_port_" << static_cast(port) + << ".xml"; + return loadXml(pathBuilder.str()); + } + + std::unique_ptr getDisplayConfigXmlByStableId(uint64_t stableId) { + std::stringstream pathBuilder; + pathBuilder << "/vendor/etc/displayconfig/display_id_" << stableId + << ".xml"; + return loadXml(pathBuilder.str()); + } }; class GraphicsCompositionTest : public GraphicsCompositionTestBase, From 3d1e0b7555ccbc761536256e71d486a0d748f444 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 24 Jul 2023 17:21:28 +0000 Subject: [PATCH 063/152] Allow uninstantiated WeaverTest Add back GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST, which I had accidentally removed while merging the AIDL and HIDL tests. I think this is still needed on devices that don't support Weaver at all. Bug: 291284381 Test: atest VtsHalWeaverTargetTest Change-Id: Iac1b4476620e51c645e3ad57444ee386cb879029 (cherry picked from commit 47b145a0d8522c41d0aa57e46dbb120bab0590bb) Merged-In: Iac1b4476620e51c645e3ad57444ee386cb879029 --- weaver/vts/VtsHalWeaverTargetTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/weaver/vts/VtsHalWeaverTargetTest.cpp b/weaver/vts/VtsHalWeaverTargetTest.cpp index 9ee6d93cf0..754d46710b 100644 --- a/weaver/vts/VtsHalWeaverTargetTest.cpp +++ b/weaver/vts/VtsHalWeaverTargetTest.cpp @@ -393,6 +393,8 @@ TEST_P(WeaverTest, ReadWithTooLargeKeyFails) { EXPECT_EQ(response.status, WeaverReadStatus::FAILED); } +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WeaverTest); + // Instantiate the test for each HIDL Weaver service. INSTANTIATE_TEST_SUITE_P( PerHidlInstance, WeaverTest, From 5055e3cb0796714d90d673c96175aa3111029ffc Mon Sep 17 00:00:00 2001 From: Jeff Pu Date: Thu, 27 Jul 2023 11:26:50 -0400 Subject: [PATCH 064/152] HAT validity check should be performed early in enrollment HAL operation. Bug: 293206206 Test: atest --no-bazel-mode VtsHalBiometricsFingerprintTargetTest Change-Id: I223615bbbd86d3f918f976c0d46e9ee93338f2a8 --- .../aidl/default/FakeFingerprintEngine.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp index 9f9ca96cd6..ec28846a6a 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp @@ -52,6 +52,14 @@ void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat, const std::future& cancel) { BEGIN_OP(0); + + // Do proper HAT verification in the real implementation. + if (hat.mac.empty()) { + LOG(ERROR) << "Fail: hat"; + cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); + return; + } + updateContext(WorkMode::kEnroll, cb, const_cast&>(cancel), 0, hat); } @@ -112,17 +120,10 @@ void FakeFingerprintEngine::fingerDownAction() { } bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb, - const keymaster::HardwareAuthToken& hat, + const keymaster::HardwareAuthToken&, const std::future& cancel) { BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency())); - // Do proper HAT verification in the real implementation. - if (hat.mac.empty()) { - LOG(ERROR) << "Fail: hat"; - cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); - return true; - } - // Force error-out auto err = FingerprintHalProperties::operation_enroll_error().value_or(0); if (err != 0) { From f0c772199bde052764a697b6de478851126fa596 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 27 Jul 2023 13:34:00 -0700 Subject: [PATCH 065/152] Set per-test timeout for IRadio 1.2-1.6 VTS to 5m To be consistent with the timeout set in IRadio 1.0/1.1 VTS This increases the timeout per-test, but there is still a timeout for all tests in the module to complete. Test: atest VtsHalRadioV1_*TargetTest for all Bug: 292197532 Change-Id: I421c13e65efa565753337dc21e6520682e726e81 --- radio/1.2/vts/functional/AndroidTest.xml | 1 + radio/1.3/vts/functional/AndroidTest.xml | 1 + radio/1.4/vts/functional/AndroidTest.xml | 1 + radio/1.5/vts/functional/AndroidTest.xml | 36 ++++++++++++++++++++++++ radio/1.6/vts/functional/AndroidTest.xml | 36 ++++++++++++++++++++++++ 5 files changed, 75 insertions(+) create mode 100644 radio/1.5/vts/functional/AndroidTest.xml create mode 100644 radio/1.6/vts/functional/AndroidTest.xml diff --git a/radio/1.2/vts/functional/AndroidTest.xml b/radio/1.2/vts/functional/AndroidTest.xml index e25249bda5..4a0be5662d 100644 --- a/radio/1.2/vts/functional/AndroidTest.xml +++ b/radio/1.2/vts/functional/AndroidTest.xml @@ -30,6 +30,7 @@ diff --git a/radio/1.3/vts/functional/AndroidTest.xml b/radio/1.3/vts/functional/AndroidTest.xml index 44b74191b3..a2cd791427 100644 --- a/radio/1.3/vts/functional/AndroidTest.xml +++ b/radio/1.3/vts/functional/AndroidTest.xml @@ -30,6 +30,7 @@ diff --git a/radio/1.4/vts/functional/AndroidTest.xml b/radio/1.4/vts/functional/AndroidTest.xml index d0843e6f6b..54051ed4f0 100644 --- a/radio/1.4/vts/functional/AndroidTest.xml +++ b/radio/1.4/vts/functional/AndroidTest.xml @@ -30,6 +30,7 @@ diff --git a/radio/1.5/vts/functional/AndroidTest.xml b/radio/1.5/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..d3617c81a9 --- /dev/null +++ b/radio/1.5/vts/functional/AndroidTest.xml @@ -0,0 +1,36 @@ + + + + diff --git a/radio/1.6/vts/functional/AndroidTest.xml b/radio/1.6/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..c3ecdb0761 --- /dev/null +++ b/radio/1.6/vts/functional/AndroidTest.xml @@ -0,0 +1,36 @@ + + + + From 7d8fb3e8bf45d0ab2ef8c876e895a5923f1fdd77 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 1 May 2023 13:34:51 -0700 Subject: [PATCH 066/152] audio: Use the canonical direction port direction in ModuleUsb Instead of relying on the device type, use the 'AudioPort.flags' field to determine the device direction. Remove 'isUsbInputDeviceType' and 'isUsbOutputtDeviceType' as they are too specific to particular device type and just add a maintenance burden. Bug: 266216550 Test: m Change-Id: Ia1b9330c2b419a1a4048ed78d914d05c1caf523f (cherry picked from commit 64fd6bd779070ce789765e8ac73743696a593dc0) Merged-In: Ia1b9330c2b419a1a4048ed78d914d05c1caf523f --- audio/aidl/common/include/Utils.h | 24 ------------------------ audio/aidl/default/usb/ModuleUsb.cpp | 4 ++-- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h index d354859a87..3b08de7f20 100644 --- a/audio/aidl/common/include/Utils.h +++ b/audio/aidl/common/include/Utils.h @@ -127,30 +127,6 @@ constexpr bool isTelephonyDeviceType( device == ::aidl::android::media::audio::common::AudioDeviceType::OUT_TELEPHONY_TX; } -constexpr bool isUsbInputDeviceType(::aidl::android::media::audio::common::AudioDeviceType type) { - switch (type) { - case ::aidl::android::media::audio::common::AudioDeviceType::IN_DOCK: - case ::aidl::android::media::audio::common::AudioDeviceType::IN_ACCESSORY: - case ::aidl::android::media::audio::common::AudioDeviceType::IN_DEVICE: - case ::aidl::android::media::audio::common::AudioDeviceType::IN_HEADSET: - return true; - default: - return false; - } -} - -constexpr bool isUsbOutputtDeviceType(::aidl::android::media::audio::common::AudioDeviceType type) { - switch (type) { - case ::aidl::android::media::audio::common::AudioDeviceType::OUT_DOCK: - case ::aidl::android::media::audio::common::AudioDeviceType::OUT_ACCESSORY: - case ::aidl::android::media::audio::common::AudioDeviceType::OUT_DEVICE: - case ::aidl::android::media::audio::common::AudioDeviceType::OUT_HEADSET: - return true; - default: - return false; - } -} - constexpr bool isValidAudioMode(::aidl::android::media::audio::common::AudioMode mode) { return std::find(kValidAudioModes.begin(), kValidAudioModes.end(), mode) != kValidAudioModes.end(); diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp index 9d3f21d505..5c9d4776ee 100644 --- a/audio/aidl/default/usb/ModuleUsb.cpp +++ b/audio/aidl/default/usb/ModuleUsb.cpp @@ -31,7 +31,6 @@ extern "C" { #include "alsa_device_profile.h" } -using aidl::android::hardware::audio::common::isUsbInputDeviceType; using aidl::android::hardware::audio::common::SinkMetadata; using aidl::android::hardware::audio::common::SourceMetadata; using aidl::android::media::audio::common::AudioChannelLayout; @@ -40,6 +39,7 @@ using aidl::android::media::audio::common::AudioDeviceDescription; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; +using aidl::android::media::audio::common::AudioIoFlags; using aidl::android::media::audio::common::AudioOffloadInfo; using aidl::android::media::audio::common::AudioPort; using aidl::android::media::audio::common::AudioPortConfig; @@ -141,7 +141,7 @@ ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } - const bool isInput = isUsbInputDeviceType(devicePort.device.type.type); + const bool isInput = audioPort->flags.getTag() == AudioIoFlags::input; alsa_device_profile profile; profile_init(&profile, isInput ? PCM_IN : PCM_OUT); profile.card = alsaAddress[0]; From 222e2a6c344e7e95d3fbe5c25b55e68a4518df65 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 6 Jul 2023 09:58:14 -0700 Subject: [PATCH 067/152] audio: Fix default surround sound config Ensure that all formats returned by AudioPolicyConfigXmlConverter::getDefaultSurroundSoundConfig can be converted into legacy values. Bug: 290116634 Test: atest audio_policy_config_xml_converter_tests Change-Id: I3a46ea5ee4805f719c8977064c9d8d681a75cff2 (cherry picked from commit 724b24f895ca8cce6cd6ce07bbea725e8eb6c79f) Merged-In: I3a46ea5ee4805f719c8977064c9d8d681a75cff2 --- audio/aidl/TEST_MAPPING | 6 +++ audio/aidl/default/Android.bp | 44 ++++++++++++++++ .../default/AudioPolicyConfigXmlConverter.cpp | 2 +- .../core-impl/AudioPolicyConfigXmlConverter.h | 3 +- .../AudioPolicyConfigXmlConverterTest.cpp | 50 +++++++++++++++++++ 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING index 3e06595fe1..12bce0b47c 100644 --- a/audio/aidl/TEST_MAPPING +++ b/audio/aidl/TEST_MAPPING @@ -3,6 +3,12 @@ { "name": "VtsHalAudioCoreTargetTest" }, + { + "name": "VtsHalAudioCoreConfigTargetTest" + }, + { + "name": "audio_policy_config_xml_converter_tests" + }, { "name": "VtsHalAudioEffectFactoryTargetTest" }, diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index e9294cf930..78b59d4efe 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -144,6 +144,50 @@ cc_binary { ], } +cc_test { + name: "audio_policy_config_xml_converter_tests", + vendor_available: true, + defaults: [ + "latest_android_media_audio_common_types_ndk_static", + "latest_android_hardware_audio_core_ndk_static", + ], + shared_libs: [ + "libaudio_aidl_conversion_common_ndk", + "libaudioaidlcommon", + "libaudioutils", + "libbase", + "libbinder_ndk", + "libcutils", + "libmedia_helper", + "libstagefright_foundation", + "libutils", + "libxml2", + ], + header_libs: [ + "libaudio_system_headers", + "libaudioaidl_headers", + "libxsdc-utils", + ], + generated_sources: [ + "audio_policy_configuration_aidl_default", + ], + generated_headers: [ + "audio_policy_configuration_aidl_default", + ], + srcs: [ + "AudioPolicyConfigXmlConverter.cpp", + "tests/AudioPolicyConfigXmlConverterTest.cpp", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-Wthread-safety", + "-DBACKEND_NDK", + ], + test_suites: ["general-tests"], +} + cc_defaults { name: "aidlaudioeffectservice_defaults", defaults: [ diff --git a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp index 2848d719c7..7452c8ec7a 100644 --- a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp +++ b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp @@ -137,7 +137,7 @@ const SurroundSoundConfig& AudioPolicyConfigXmlConverter::getDefaultSurroundSoun SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS), SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD), SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD_MA), - SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD), + SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P1), SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2), SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD), SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_EAC3_JOC), diff --git a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h index 94501a81ba..090d58585f 100644 --- a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h +++ b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h @@ -38,9 +38,10 @@ class AudioPolicyConfigXmlConverter { const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig(); const SurroundSoundConfig& getSurroundSoundConfig(); - private: + // Public for testing purposes. static const SurroundSoundConfig& getDefaultSurroundSoundConfig(); + private: const std::optional<::android::audio::policy::configuration::AudioPolicyConfiguration>& getXsdcConfig() const { return mConverter.getXsdcConfig(); diff --git a/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp b/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp new file mode 100644 index 0000000000..572bc5a77c --- /dev/null +++ b/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #include +// #include +// #include + +#include +#include +#define LOG_TAG "AudioPolicyConfigXmlConverterTest" +#include + +#include +#include + +using aidl::android::hardware::audio::core::internal::AudioPolicyConfigXmlConverter; +using aidl::android::media::audio::common::AudioFormatDescription; + +namespace { + +void ValidateAudioFormatDescription(const AudioFormatDescription& format) { + auto conv = ::aidl::android::aidl2legacy_AudioFormatDescription_audio_format_t(format); + ASSERT_TRUE(conv.ok()) << format.toString(); +} + +} // namespace + +TEST(AudioPolicyConfigXmlConverterTest, DefaultSurroundSoundConfigIsValid) { + auto config = AudioPolicyConfigXmlConverter::getDefaultSurroundSoundConfig(); + for (const auto& family : config.formatFamilies) { + EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(family.primaryFormat)); + SCOPED_TRACE(family.primaryFormat.toString()); + for (const auto& sub : family.subFormats) { + EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(sub)); + } + } +} From a4513dcf05154e8db981ef83d99401c6a9af01e2 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 7 Jul 2023 12:01:17 -0700 Subject: [PATCH 068/152] audio: Move tinyALSA-specific code to Module/StreamAlsa Extract code interacting with tinyALSA which is not specific to USB into "abstract" module and stream implementations ModuleAlsa and StreamAlsa. Also, move utility code which does not need module or stream context into Utils. This facilitates implementation of the CF core HAL which also uses tinyALSA, allowing to share common code. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Change-Id: I2134b15e970c78e8a48b254e15199b8207a8ab34 (cherry picked from commit c337a8799b8cc3029aaee2addee9c4212e812b3c) Merged-In: I2134b15e970c78e8a48b254e15199b8207a8ab34 --- audio/aidl/default/Android.bp | 5 +- audio/aidl/default/alsa/Mixer.cpp | 154 +++++++++ audio/aidl/default/alsa/Mixer.h | 82 +++++ audio/aidl/default/alsa/ModuleAlsa.cpp | 67 ++++ audio/aidl/default/alsa/StreamAlsa.cpp | 103 ++++++ audio/aidl/default/alsa/Utils.cpp | 293 ++++++++++++++++++ audio/aidl/default/alsa/Utils.h | 70 +++++ .../default/include/core-impl/ModuleAlsa.h | 38 +++ .../default/include/core-impl/ModuleUsb.h | 6 +- .../default/include/core-impl/StreamAlsa.h | 54 ++++ .../default/include/core-impl/StreamUsb.h | 33 +- audio/aidl/default/usb/ModuleUsb.cpp | 103 +----- audio/aidl/default/usb/StreamUsb.cpp | 160 ++-------- .../aidl/default/usb/UsbAlsaMixerControl.cpp | 140 +-------- audio/aidl/default/usb/UsbAlsaMixerControl.h | 62 +--- audio/aidl/default/usb/UsbAlsaUtils.cpp | 181 ----------- audio/aidl/default/usb/UsbAlsaUtils.h | 39 --- 17 files changed, 923 insertions(+), 667 deletions(-) create mode 100644 audio/aidl/default/alsa/Mixer.cpp create mode 100644 audio/aidl/default/alsa/Mixer.h create mode 100644 audio/aidl/default/alsa/ModuleAlsa.cpp create mode 100644 audio/aidl/default/alsa/StreamAlsa.cpp create mode 100644 audio/aidl/default/alsa/Utils.cpp create mode 100644 audio/aidl/default/alsa/Utils.h create mode 100644 audio/aidl/default/include/core-impl/ModuleAlsa.h create mode 100644 audio/aidl/default/include/core-impl/StreamAlsa.h delete mode 100644 audio/aidl/default/usb/UsbAlsaUtils.cpp delete mode 100644 audio/aidl/default/usb/UsbAlsaUtils.h diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 78b59d4efe..69443d4194 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -77,6 +77,10 @@ cc_library { "Stream.cpp", "StreamStub.cpp", "Telephony.cpp", + "alsa/Mixer.cpp", + "alsa/ModuleAlsa.cpp", + "alsa/StreamAlsa.cpp", + "alsa/Utils.cpp", "r_submix/ModuleRemoteSubmix.cpp", "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", @@ -84,7 +88,6 @@ cc_library { "usb/ModuleUsb.cpp", "usb/StreamUsb.cpp", "usb/UsbAlsaMixerControl.cpp", - "usb/UsbAlsaUtils.cpp", ], generated_sources: [ "audio_policy_configuration_aidl_default", diff --git a/audio/aidl/default/alsa/Mixer.cpp b/audio/aidl/default/alsa/Mixer.cpp new file mode 100644 index 0000000000..f0393e3a7e --- /dev/null +++ b/audio/aidl/default/alsa/Mixer.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_AlsaMixer" +#include + +#include + +#include + +#include "Mixer.h" + +namespace aidl::android::hardware::audio::core::alsa { + +//----------------------------------------------------------------------------- + +MixerControl::MixerControl(struct mixer_ctl* ctl) + : mCtl(ctl), + mNumValues(mixer_ctl_get_num_values(ctl)), + mMinValue(mixer_ctl_get_range_min(ctl)), + mMaxValue(mixer_ctl_get_range_max(ctl)) {} + +unsigned int MixerControl::getNumValues() const { + return mNumValues; +} + +int MixerControl::getMaxValue() const { + return mMaxValue; +} + +int MixerControl::getMinValue() const { + return mMinValue; +} + +int MixerControl::setArray(const void* array, size_t count) { + const std::lock_guard guard(mLock); + return mixer_ctl_set_array(mCtl, array, count); +} + +//----------------------------------------------------------------------------- + +// static +const std::map> + Mixer::kPossibleControls = { + {Mixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}}, + {Mixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}}, + {Mixer::HW_VOLUME, + {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT}, + {"Headset Playback Volume", MIXER_CTL_TYPE_INT}, + {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}}; + +// static +std::map> Mixer::initializeMixerControls( + struct mixer* mixer) { + std::map> mixerControls; + std::string mixerCtlNames; + for (const auto& [control, possibleCtls] : kPossibleControls) { + for (const auto& [ctlName, expectedCtlType] : possibleCtls) { + struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str()); + if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) { + mixerControls.emplace(control, std::make_unique(ctl)); + if (!mixerCtlNames.empty()) { + mixerCtlNames += ","; + } + mixerCtlNames += ctlName; + break; + } + } + } + LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]"; + return mixerControls; +} + +Mixer::Mixer(struct mixer* mixer) + : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {} + +Mixer::~Mixer() { + mixer_close(mMixer); +} + +namespace { + +int volumeFloatToInteger(float fValue, int maxValue, int minValue) { + return minValue + std::ceil((maxValue - minValue) * fValue); +} + +} // namespace + +ndk::ScopedAStatus Mixer::setMasterMute(bool muted) { + auto it = mMixerControls.find(Mixer::MASTER_SWITCH); + if (it == mMixerControls.end()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + const int numValues = it->second->getNumValues(); + std::vector values(numValues, muted ? 0 : 1); + if (int err = it->second->setArray(values.data(), numValues); err != 0) { + LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Mixer::setMasterVolume(float volume) { + auto it = mMixerControls.find(Mixer::MASTER_VOLUME); + if (it == mMixerControls.end()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + const int numValues = it->second->getNumValues(); + std::vector values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(), + it->second->getMinValue())); + if (int err = it->second->setArray(values.data(), numValues); err != 0) { + LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Mixer::setVolumes(const std::vector& volumes) { + auto it = mMixerControls.find(Mixer::HW_VOLUME); + if (it == mMixerControls.end()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + const int numValues = it->second->getNumValues(); + if (numValues < 0) { + LOG(FATAL) << __func__ << ": negative number of values: " << numValues; + } + const int maxValue = it->second->getMaxValue(); + const int minValue = it->second->getMinValue(); + std::vector values; + size_t i = 0; + for (; i < static_cast(numValues) && i < values.size(); ++i) { + values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue)); + } + if (int err = it->second->setArray(values.data(), values.size()); err != 0) { + LOG(ERROR) << __func__ << ": failed to set volume, err=" << err; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + return ndk::ScopedAStatus::ok(); +} + +} // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h new file mode 100644 index 0000000000..de9e6f42cd --- /dev/null +++ b/audio/aidl/default/alsa/Mixer.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +extern "C" { +#include +} + +namespace aidl::android::hardware::audio::core::alsa { + +class MixerControl { + public: + explicit MixerControl(struct mixer_ctl* ctl); + + unsigned int getNumValues() const; + int getMaxValue() const; + int getMinValue() const; + int setArray(const void* array, size_t count); + + private: + std::mutex mLock; + // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed. + struct mixer_ctl* mCtl GUARDED_BY(mLock); + const unsigned int mNumValues; + const int mMinValue; + const int mMaxValue; +}; + +class Mixer { + public: + explicit Mixer(struct mixer* mixer); + + ~Mixer(); + + bool isValid() const { return mMixer != nullptr; } + + ndk::ScopedAStatus setMasterMute(bool muted); + ndk::ScopedAStatus setMasterVolume(float volume); + ndk::ScopedAStatus setVolumes(const std::vector& volumes); + + private: + enum Control { + MASTER_SWITCH, + MASTER_VOLUME, + HW_VOLUME, + }; + using ControlNamesAndExpectedCtlType = std::pair; + static const std::map> kPossibleControls; + static std::map> initializeMixerControls( + struct mixer* mixer); + + // The mixer object is owned by ALSA and will be released when the mixer is closed. + struct mixer* mMixer; + // `mMixerControls` will only be initialized in constructor. After that, it wil only be + // read but not be modified. + const std::map> mMixerControls; +}; + +} // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/alsa/ModuleAlsa.cpp b/audio/aidl/default/alsa/ModuleAlsa.cpp new file mode 100644 index 0000000000..8e75d56843 --- /dev/null +++ b/audio/aidl/default/alsa/ModuleAlsa.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_ModuleAlsa" + +#include + +#include + +#include "Utils.h" +#include "core-impl/ModuleAlsa.h" + +extern "C" { +#include "alsa_device_profile.h" +} + +using aidl::android::media::audio::common::AudioChannelLayout; +using aidl::android::media::audio::common::AudioFormatType; +using aidl::android::media::audio::common::AudioPort; +using aidl::android::media::audio::common::AudioProfile; + +namespace aidl::android::hardware::audio::core { + +ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort) { + auto deviceProfile = alsa::getDeviceProfile(*audioPort); + if (!deviceProfile.has_value()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + auto profile = alsa::readAlsaDeviceInfo(*deviceProfile); + if (!profile.has_value()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + std::vector channels = alsa::getChannelMasksFromProfile(&profile.value()); + std::vector sampleRates = alsa::getSampleRatesFromProfile(&profile.value()); + + for (size_t i = 0; i < std::min(MAX_PROFILE_FORMATS, AUDIO_PORT_MAX_AUDIO_PROFILES) && + profile->formats[i] != PCM_FORMAT_INVALID; + ++i) { + auto audioFormatDescription = + alsa::c2aidl_pcm_format_AudioFormatDescription(profile->formats[i]); + if (audioFormatDescription.type == AudioFormatType::DEFAULT) { + LOG(WARNING) << __func__ << ": unknown pcm type=" << profile->formats[i]; + continue; + } + AudioProfile audioProfile = {.format = audioFormatDescription, + .channelMasks = channels, + .sampleRates = sampleRates}; + audioPort->profiles.push_back(std::move(audioProfile)); + } + return ndk::ScopedAStatus::ok(); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp new file mode 100644 index 0000000000..ecb3c78a65 --- /dev/null +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "AHAL_StreamAlsa" +#include + +#include +#include + +#include "core-impl/StreamAlsa.h" + +namespace aidl::android::hardware::audio::core { + +StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context) + : StreamCommonImpl(metadata, std::move(context)), + mFrameSizeBytes(getContext().getFrameSize()), + mIsInput(isInput(metadata)), + mConfig(alsa::getPcmConfig(getContext(), mIsInput)) {} + +::android::status_t StreamAlsa::init() { + return mConfig.has_value() ? ::android::OK : ::android::NO_INIT; +} + +::android::status_t StreamAlsa::standby() { + mAlsaDeviceProxies.clear(); + return ::android::OK; +} + +::android::status_t StreamAlsa::start() { + decltype(mAlsaDeviceProxies) alsaDeviceProxies; + for (const auto& device : getDeviceProfiles()) { + auto profile = alsa::readAlsaDeviceInfo(device); + if (!profile.has_value()) { + LOG(ERROR) << __func__ << ": unable to read device info, device address=" << device; + return ::android::UNKNOWN_ERROR; + } + + auto proxy = alsa::makeDeviceProxy(); + // Always ask for alsa configure as required since the configuration should be supported + // by the connected device. That is guaranteed by `setAudioPortConfig` and `setAudioPatch`. + if (int err = proxy_prepare(proxy.get(), &profile.value(), + const_cast(&mConfig.value()), + true /*require_exact_match*/); + err != 0) { + LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device + << " error=" << err; + return ::android::UNKNOWN_ERROR; + } + if (int err = proxy_open(proxy.get()); err != 0) { + LOG(ERROR) << __func__ << ": failed to open device, address=" << device + << " error=" << err; + return ::android::UNKNOWN_ERROR; + } + alsaDeviceProxies.push_back(std::move(proxy)); + } + mAlsaDeviceProxies = std::move(alsaDeviceProxies); + return ::android::OK; +} + +::android::status_t StreamAlsa::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, + int32_t* latencyMs) { + const size_t bytesToTransfer = frameCount * mFrameSizeBytes; + unsigned maxLatency = 0; + if (mIsInput) { + if (mAlsaDeviceProxies.empty()) { + LOG(FATAL) << __func__ << ": no input devices"; + return ::android::NO_INIT; + } + // For input case, only support single device. + proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer); + maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get()); + } else { + for (auto& proxy : mAlsaDeviceProxies) { + proxy_write(proxy.get(), buffer, bytesToTransfer); + maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get())); + } + } + *actualFrameCount = frameCount; + maxLatency = std::min(maxLatency, static_cast(std::numeric_limits::max())); + *latencyMs = maxLatency; + return ::android::OK; +} + +void StreamAlsa::shutdown() { + mAlsaDeviceProxies.clear(); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp new file mode 100644 index 0000000000..162f8529cf --- /dev/null +++ b/audio/aidl/default/alsa/Utils.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#define LOG_TAG "AHAL_AlsaUtils" +#include +#include +#include +#include + +#include "Utils.h" +#include "core-impl/utils.h" + +using aidl::android::hardware::audio::common::getChannelCount; +using aidl::android::media::audio::common::AudioChannelLayout; +using aidl::android::media::audio::common::AudioDeviceAddress; +using aidl::android::media::audio::common::AudioFormatDescription; +using aidl::android::media::audio::common::AudioFormatType; +using aidl::android::media::audio::common::AudioIoFlags; +using aidl::android::media::audio::common::AudioPortExt; +using aidl::android::media::audio::common::PcmType; + +namespace aidl::android::hardware::audio::core::alsa { + +namespace { + +using AudioChannelCountToMaskMap = std::map; +using AudioFormatDescToPcmFormatMap = std::map; +using PcmFormatToAudioFormatDescMap = std::map; + +AudioChannelLayout getInvalidChannelLayout() { + static const AudioChannelLayout invalidChannelLayout = + AudioChannelLayout::make(0); + return invalidChannelLayout; +} + +static AudioChannelCountToMaskMap make_ChannelCountToMaskMap( + const std::set& channelMasks) { + AudioChannelCountToMaskMap channelMaskToCountMap; + for (const auto& channelMask : channelMasks) { + channelMaskToCountMap.emplace(getChannelCount(channelMask), channelMask); + } + return channelMaskToCountMap; +} + +#define DEFINE_CHANNEL_LAYOUT_MASK(n) \ + AudioChannelLayout::make(AudioChannelLayout::LAYOUT_##n) + +const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() { + static const std::set supportedOutChannelLayouts = { + DEFINE_CHANNEL_LAYOUT_MASK(MONO), DEFINE_CHANNEL_LAYOUT_MASK(STEREO), + DEFINE_CHANNEL_LAYOUT_MASK(2POINT1), DEFINE_CHANNEL_LAYOUT_MASK(QUAD), + DEFINE_CHANNEL_LAYOUT_MASK(PENTA), DEFINE_CHANNEL_LAYOUT_MASK(5POINT1), + DEFINE_CHANNEL_LAYOUT_MASK(6POINT1), DEFINE_CHANNEL_LAYOUT_MASK(7POINT1), + DEFINE_CHANNEL_LAYOUT_MASK(7POINT1POINT4), DEFINE_CHANNEL_LAYOUT_MASK(22POINT2), + }; + static const AudioChannelCountToMaskMap outLayouts = + make_ChannelCountToMaskMap(supportedOutChannelLayouts); + return outLayouts; +} + +const AudioChannelCountToMaskMap& getSupportedChannelInLayoutMap() { + static const std::set supportedInChannelLayouts = { + DEFINE_CHANNEL_LAYOUT_MASK(MONO), + DEFINE_CHANNEL_LAYOUT_MASK(STEREO), + }; + static const AudioChannelCountToMaskMap inLayouts = + make_ChannelCountToMaskMap(supportedInChannelLayouts); + return inLayouts; +} + +#undef DEFINE_CHANNEL_LAYOUT_MASK +#define DEFINE_CHANNEL_INDEX_MASK(n) \ + AudioChannelLayout::make(AudioChannelLayout::INDEX_MASK_##n) + +const AudioChannelCountToMaskMap& getSupportedChannelIndexLayoutMap() { + static const std::set supportedIndexChannelLayouts = { + DEFINE_CHANNEL_INDEX_MASK(1), DEFINE_CHANNEL_INDEX_MASK(2), + DEFINE_CHANNEL_INDEX_MASK(3), DEFINE_CHANNEL_INDEX_MASK(4), + DEFINE_CHANNEL_INDEX_MASK(5), DEFINE_CHANNEL_INDEX_MASK(6), + DEFINE_CHANNEL_INDEX_MASK(7), DEFINE_CHANNEL_INDEX_MASK(8), + DEFINE_CHANNEL_INDEX_MASK(9), DEFINE_CHANNEL_INDEX_MASK(10), + DEFINE_CHANNEL_INDEX_MASK(11), DEFINE_CHANNEL_INDEX_MASK(12), + DEFINE_CHANNEL_INDEX_MASK(13), DEFINE_CHANNEL_INDEX_MASK(14), + DEFINE_CHANNEL_INDEX_MASK(15), DEFINE_CHANNEL_INDEX_MASK(16), + DEFINE_CHANNEL_INDEX_MASK(17), DEFINE_CHANNEL_INDEX_MASK(18), + DEFINE_CHANNEL_INDEX_MASK(19), DEFINE_CHANNEL_INDEX_MASK(20), + DEFINE_CHANNEL_INDEX_MASK(21), DEFINE_CHANNEL_INDEX_MASK(22), + DEFINE_CHANNEL_INDEX_MASK(23), DEFINE_CHANNEL_INDEX_MASK(24), + }; + static const AudioChannelCountToMaskMap indexLayouts = + make_ChannelCountToMaskMap(supportedIndexChannelLayouts); + return indexLayouts; +} + +#undef DEFINE_CHANNEL_INDEX_MASK + +AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) { + AudioFormatDescription result; + result.type = type; + return result; +} + +AudioFormatDescription make_AudioFormatDescription(PcmType pcm) { + auto result = make_AudioFormatDescription(AudioFormatType::PCM); + result.pcm = pcm; + return result; +} + +const AudioFormatDescToPcmFormatMap& getAudioFormatDescriptorToPcmFormatMap() { + static const AudioFormatDescToPcmFormatMap formatDescToPcmFormatMap = { + {make_AudioFormatDescription(PcmType::UINT_8_BIT), PCM_FORMAT_S8}, + {make_AudioFormatDescription(PcmType::INT_16_BIT), PCM_FORMAT_S16_LE}, + {make_AudioFormatDescription(PcmType::FIXED_Q_8_24), PCM_FORMAT_S24_LE}, + {make_AudioFormatDescription(PcmType::INT_24_BIT), PCM_FORMAT_S24_3LE}, + {make_AudioFormatDescription(PcmType::INT_32_BIT), PCM_FORMAT_S32_LE}, + {make_AudioFormatDescription(PcmType::FLOAT_32_BIT), PCM_FORMAT_FLOAT_LE}, + }; + return formatDescToPcmFormatMap; +} + +static PcmFormatToAudioFormatDescMap make_PcmFormatToAudioFormatDescMap( + const AudioFormatDescToPcmFormatMap& formatDescToPcmFormatMap) { + PcmFormatToAudioFormatDescMap result; + for (const auto& formatPair : formatDescToPcmFormatMap) { + result.emplace(formatPair.second, formatPair.first); + } + return result; +} + +const PcmFormatToAudioFormatDescMap& getPcmFormatToAudioFormatDescMap() { + static const PcmFormatToAudioFormatDescMap pcmFormatToFormatDescMap = + make_PcmFormatToAudioFormatDescMap(getAudioFormatDescriptorToPcmFormatMap()); + return pcmFormatToFormatDescMap; +} + +} // namespace + +std::ostream& operator<<(std::ostream& os, const DeviceProfile& device) { + return os << "<" << device.card << "," << device.device << ">"; +} + +AudioChannelLayout getChannelLayoutMaskFromChannelCount(unsigned int channelCount, int isInput) { + return findValueOrDefault( + isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(), + channelCount, getInvalidChannelLayout()); +} + +AudioChannelLayout getChannelIndexMaskFromChannelCount(unsigned int channelCount) { + return findValueOrDefault(getSupportedChannelIndexLayoutMap(), channelCount, + getInvalidChannelLayout()); +} + +unsigned int getChannelCountFromChannelMask(const AudioChannelLayout& channelMask, bool isInput) { + switch (channelMask.getTag()) { + case AudioChannelLayout::Tag::layoutMask: { + return findKeyOrDefault( + isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(), + static_cast(getChannelCount(channelMask)), 0u /*defaultValue*/); + } + case AudioChannelLayout::Tag::indexMask: { + return findKeyOrDefault(getSupportedChannelIndexLayoutMap(), + static_cast(getChannelCount(channelMask)), + 0u /*defaultValue*/); + } + case AudioChannelLayout::Tag::none: + case AudioChannelLayout::Tag::invalid: + case AudioChannelLayout::Tag::voiceMask: + default: + return 0; + } +} + +std::vector getChannelMasksFromProfile(const alsa_device_profile* profile) { + const bool isInput = profile->direction == PCM_IN; + std::vector channels; + for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) { + auto layoutMask = + alsa::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput); + if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) { + channels.push_back(layoutMask); + } + auto indexMask = alsa::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]); + if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) { + channels.push_back(indexMask); + } + } + return channels; +} + +std::optional getDeviceProfile( + const ::aidl::android::media::audio::common::AudioDevice& audioDevice, bool isInput) { + if (audioDevice.address.getTag() != AudioDeviceAddress::Tag::alsa) { + LOG(ERROR) << __func__ << ": not alsa address: " << audioDevice.toString(); + return std::nullopt; + } + auto& alsaAddress = audioDevice.address.get(); + if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) { + LOG(ERROR) << __func__ + << ": malformed alsa address: " << ::android::internal::ToString(alsaAddress); + return std::nullopt; + } + return DeviceProfile{.card = alsaAddress[0], + .device = alsaAddress[1], + .direction = isInput ? PCM_IN : PCM_OUT}; +} + +std::optional getDeviceProfile( + const ::aidl::android::media::audio::common::AudioPort& audioPort) { + if (audioPort.ext.getTag() != AudioPortExt::Tag::device) { + LOG(ERROR) << __func__ << ": port id " << audioPort.id << " is not a device port"; + return std::nullopt; + } + auto& devicePort = audioPort.ext.get(); + return getDeviceProfile(devicePort.device, audioPort.flags.getTag() == AudioIoFlags::input); +} + +std::optional getPcmConfig(const StreamContext& context, bool isInput) { + struct pcm_config config; + config.channels = alsa::getChannelCountFromChannelMask(context.getChannelLayout(), isInput); + if (config.channels == 0) { + LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString(); + return std::nullopt; + } + config.format = alsa::aidl2c_AudioFormatDescription_pcm_format(context.getFormat()); + if (config.format == PCM_FORMAT_INVALID) { + LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString(); + return std::nullopt; + } + config.rate = context.getSampleRate(); + if (config.rate == 0) { + LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate; + return std::nullopt; + } + return config; +} + +std::vector getSampleRatesFromProfile(const alsa_device_profile* profile) { + std::vector sampleRates; + for (int i = 0; i < std::min(MAX_PROFILE_SAMPLE_RATES, AUDIO_PORT_MAX_SAMPLING_RATES) && + profile->sample_rates[i] != 0; + i++) { + sampleRates.push_back(profile->sample_rates[i]); + } + return sampleRates; +} + +DeviceProxy makeDeviceProxy() { + return DeviceProxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) { + if (proxy != nullptr) { + proxy_close(proxy); + delete proxy; + } + }); +} + +std::optional readAlsaDeviceInfo(const DeviceProfile& deviceProfile) { + alsa_device_profile profile; + profile_init(&profile, deviceProfile.direction); + profile.card = deviceProfile.card; + profile.device = deviceProfile.device; + if (!profile_read_device_info(&profile)) { + LOG(ERROR) << __func__ << ": failed to read device info, card=" << profile.card + << ", device=" << profile.device; + return std::nullopt; + } + return profile; +} + +AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) { + return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription()); +} + +pcm_format aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription& aidl) { + return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID); +} + +} // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h new file mode 100644 index 0000000000..c1b9b380c0 --- /dev/null +++ b/audio/aidl/default/alsa/Utils.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "core-impl/Stream.h" + +extern "C" { +#include +#include "alsa_device_profile.h" +#include "alsa_device_proxy.h" +} + +namespace aidl::android::hardware::audio::core::alsa { + +struct DeviceProfile { + int card; + int device; + int direction; /* PCM_OUT or PCM_IN */ +}; +std::ostream& operator<<(std::ostream& os, const DeviceProfile& device); +using DeviceProxyDeleter = std::function; +using DeviceProxy = std::unique_ptr; + +::aidl::android::media::audio::common::AudioChannelLayout getChannelLayoutMaskFromChannelCount( + unsigned int channelCount, int isInput); +::aidl::android::media::audio::common::AudioChannelLayout getChannelIndexMaskFromChannelCount( + unsigned int channelCount); +unsigned int getChannelCountFromChannelMask( + const ::aidl::android::media::audio::common::AudioChannelLayout& channelMask, bool isInput); +std::vector<::aidl::android::media::audio::common::AudioChannelLayout> getChannelMasksFromProfile( + const alsa_device_profile* profile); +std::optional getDeviceProfile( + const ::aidl::android::media::audio::common::AudioDevice& audioDevice, bool isInput); +std::optional getDeviceProfile( + const ::aidl::android::media::audio::common::AudioPort& audioPort); +std::optional getPcmConfig(const StreamContext& context, bool isInput); +std::vector getSampleRatesFromProfile(const alsa_device_profile* profile); +DeviceProxy makeDeviceProxy(); +std::optional readAlsaDeviceInfo(const DeviceProfile& deviceProfile); + +::aidl::android::media::audio::common::AudioFormatDescription +c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy); +pcm_format aidl2c_AudioFormatDescription_pcm_format( + const ::aidl::android::media::audio::common::AudioFormatDescription& aidl); + +} // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/include/core-impl/ModuleAlsa.h b/audio/aidl/default/include/core-impl/ModuleAlsa.h new file mode 100644 index 0000000000..5815961f7c --- /dev/null +++ b/audio/aidl/default/include/core-impl/ModuleAlsa.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "core-impl/Module.h" + +namespace aidl::android::hardware::audio::core { + +// This class is intended to be used as a base class for implementations +// that use TinyAlsa. This can be either a primary module or a USB Audio +// module. This class does not define a complete module implementation, +// and should never be used on its own. Derived classes are expected to +// provide necessary overrides for all interface methods omitted here. +class ModuleAlsa : public Module { + public: + explicit ModuleAlsa(Module::Type type) : Module(type) {} + + protected: + // Extension methods of 'Module'. + ndk::ScopedAStatus populateConnectedDevicePort( + ::aidl::android::media::audio::common::AudioPort* audioPort) override; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h index 5a5429db64..ea7cc48214 100644 --- a/audio/aidl/default/include/core-impl/ModuleUsb.h +++ b/audio/aidl/default/include/core-impl/ModuleUsb.h @@ -16,13 +16,13 @@ #pragma once -#include "core-impl/Module.h" +#include "core-impl/ModuleAlsa.h" namespace aidl::android::hardware::audio::core { -class ModuleUsb : public Module { +class ModuleUsb final : public ModuleAlsa { public: - explicit ModuleUsb(Module::Type type) : Module(type) {} + explicit ModuleUsb(Module::Type type) : ModuleAlsa(type) {} private: // IModule interfaces diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h new file mode 100644 index 0000000000..edfc72860c --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "Stream.h" +#include "alsa/Utils.h" + +namespace aidl::android::hardware::audio::core { + +// This class is intended to be used as a base class for implementations +// that use TinyAlsa. +// This class does not define a complete stream implementation, +// and should never be used on its own. Derived classes are expected to +// provide necessary overrides for all interface methods omitted here. +class StreamAlsa : public StreamCommonImpl { + public: + StreamAlsa(const Metadata& metadata, StreamContext&& context); + // Methods of 'DriverInterface'. + ::android::status_t init() override; + ::android::status_t standby() override; + ::android::status_t start() override; + ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, + int32_t* latencyMs) override; + void shutdown() override; + + protected: + // Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty. + virtual std::vector getDeviceProfiles() = 0; + + const size_t mFrameSizeBytes; + const bool mIsInput; + const std::optional mConfig; + // All fields below are only used on the worker thread. + std::vector mAlsaDeviceProxies; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 8c40782db1..44f742a4dd 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -17,55 +17,34 @@ #pragma once #include -#include #include -#include #include #include -#include "core-impl/Stream.h" - -extern "C" { -#include -#include "alsa_device_proxy.h" -} +#include "StreamAlsa.h" namespace aidl::android::hardware::audio::core { -class StreamUsb : public StreamCommonImpl { +class StreamUsb : public StreamAlsa { public: StreamUsb(const Metadata& metadata, StreamContext&& context); // Methods of 'DriverInterface'. - ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; - ::android::status_t standby() override; - ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; - void shutdown() override; // Overridden methods of 'StreamCommonImpl', called on a Binder thread. - const ConnectedDevices& getConnectedDevices() const override; ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override; - private: - using AlsaDeviceProxyDeleter = std::function; - using AlsaDeviceProxy = std::unique_ptr; - - static std::optional maybePopulateConfig(const StreamContext& context, - bool isInput); + protected: + std::vector getDeviceProfiles() override; mutable std::mutex mLock; - - const size_t mFrameSizeBytes; - const bool mIsInput; - const std::optional mConfig; + std::vector mConnectedDeviceProfiles GUARDED_BY(mLock); std::atomic mConnectedDevicesUpdated = false; - // All fields below are only used on the worker thread. - std::vector mAlsaDeviceProxies; }; class StreamInUsb final : public StreamUsb, public StreamIn { @@ -94,7 +73,7 @@ class StreamOutUsb final : public StreamUsb, public StreamOut { ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; - int mChannelCount; + const int mChannelCount; std::vector mHwVolumes; }; diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp index 5c9d4776ee..a812e4d3a1 100644 --- a/audio/aidl/default/usb/ModuleUsb.cpp +++ b/audio/aidl/default/usb/ModuleUsb.cpp @@ -14,68 +14,34 @@ * limitations under the License. */ -#define LOG_TAG "AHAL_ModuleUsb" - #include +#define LOG_TAG "AHAL_ModuleUsb" #include #include -#include #include "UsbAlsaMixerControl.h" -#include "UsbAlsaUtils.h" +#include "alsa/Utils.h" #include "core-impl/ModuleUsb.h" #include "core-impl/StreamUsb.h" -extern "C" { -#include "alsa_device_profile.h" -} - using aidl::android::hardware::audio::common::SinkMetadata; using aidl::android::hardware::audio::common::SourceMetadata; -using aidl::android::media::audio::common::AudioChannelLayout; -using aidl::android::media::audio::common::AudioDeviceAddress; using aidl::android::media::audio::common::AudioDeviceDescription; -using aidl::android::media::audio::common::AudioDeviceType; -using aidl::android::media::audio::common::AudioFormatDescription; -using aidl::android::media::audio::common::AudioFormatType; -using aidl::android::media::audio::common::AudioIoFlags; using aidl::android::media::audio::common::AudioOffloadInfo; using aidl::android::media::audio::common::AudioPort; using aidl::android::media::audio::common::AudioPortConfig; using aidl::android::media::audio::common::AudioPortExt; -using aidl::android::media::audio::common::AudioProfile; using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { namespace { -std::vector populateChannelMasksFromProfile(const alsa_device_profile* profile, - bool isInput) { - std::vector channels; - for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) { - auto layoutMask = - usb::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput); - if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) { - channels.push_back(layoutMask); - } - auto indexMask = usb::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]); - if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) { - channels.push_back(indexMask); - } - } - return channels; -} - -std::vector populateSampleRatesFromProfile(const alsa_device_profile* profile) { - std::vector sampleRates; - for (int i = 0; i < std::min(MAX_PROFILE_SAMPLE_RATES, AUDIO_PORT_MAX_SAMPLING_RATES) && - profile->sample_rates[i] != 0; - i++) { - sampleRates.push_back(profile->sample_rates[i]); - } - return sampleRates; +bool isUsbDevicePort(const AudioPort& audioPort) { + return audioPort.ext.getTag() == AudioPortExt::Tag::device && + audioPort.ext.get().device.type.connection == + AudioDeviceDescription::CONNECTION_USB; } } // namespace @@ -122,55 +88,11 @@ ndk::ScopedAStatus ModuleUsb::createOutputStream(const SourceMetadata& sourceMet } ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) { - if (audioPort->ext.getTag() != AudioPortExt::Tag::device) { - LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a device port"; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - auto& devicePort = audioPort->ext.get(); - if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_USB) { + if (!isUsbDevicePort(*audioPort)) { LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a usb device port"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } - if (devicePort.device.address.getTag() != AudioDeviceAddress::Tag::alsa) { - LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not using alsa address"; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - auto& alsaAddress = devicePort.device.address.get(); - if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) { - LOG(ERROR) << __func__ << ": port id " << audioPort->id << " invalid alsa address"; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - const bool isInput = audioPort->flags.getTag() == AudioIoFlags::input; - alsa_device_profile profile; - profile_init(&profile, isInput ? PCM_IN : PCM_OUT); - profile.card = alsaAddress[0]; - profile.device = alsaAddress[1]; - if (!profile_read_device_info(&profile)) { - LOG(ERROR) << __func__ << ": failed to read device info, card=" << profile.card - << ", device=" << profile.device; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - - std::vector channels = populateChannelMasksFromProfile(&profile, isInput); - std::vector sampleRates = populateSampleRatesFromProfile(&profile); - - for (size_t i = 0; i < std::min(MAX_PROFILE_FORMATS, AUDIO_PORT_MAX_AUDIO_PROFILES) && - profile.formats[i] != PCM_FORMAT_INVALID; - ++i) { - auto audioFormatDescription = - usb::legacy2aidl_pcm_format_AudioFormatDescription(profile.formats[i]); - if (audioFormatDescription.type == AudioFormatType::DEFAULT) { - LOG(WARNING) << __func__ << ": unknown pcm type=" << profile.formats[i]; - continue; - } - AudioProfile audioProfile = {.format = audioFormatDescription, - .channelMasks = channels, - .sampleRates = sampleRates}; - audioPort->profiles.push_back(std::move(audioProfile)); - } - - return ndk::ScopedAStatus::ok(); + return ModuleAlsa::populateConnectedDevicePort(audioPort); } ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch( @@ -191,15 +113,14 @@ ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch( void ModuleUsb::onExternalDeviceConnectionChanged( const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected) { - if (audioPort.ext.getTag() != AudioPortExt::Tag::device) { + if (!isUsbDevicePort(audioPort)) { return; } - const auto& address = audioPort.ext.get().device.address; - if (address.getTag() != AudioDeviceAddress::alsa) { + auto profile = alsa::getDeviceProfile(audioPort); + if (!profile.has_value()) { return; } - const int card = address.get()[0]; - usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(card, getMasterMute(), + usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(profile->card, getMasterMute(), getMasterVolume(), connected); } diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index 17e1ab42f1..da0ad11be2 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -23,64 +23,20 @@ #include #include "UsbAlsaMixerControl.h" -#include "UsbAlsaUtils.h" -#include "core-impl/Module.h" #include "core-impl/StreamUsb.h" -extern "C" { -#include "alsa_device_profile.h" -} - using aidl::android::hardware::audio::common::getChannelCount; using aidl::android::hardware::audio::common::SinkMetadata; using aidl::android::hardware::audio::common::SourceMetadata; using aidl::android::media::audio::common::AudioDevice; -using aidl::android::media::audio::common::AudioDeviceAddress; using aidl::android::media::audio::common::AudioOffloadInfo; -using aidl::android::media::audio::common::AudioPortExt; using aidl::android::media::audio::common::MicrophoneDynamicInfo; using aidl::android::media::audio::common::MicrophoneInfo; -using android::OK; -using android::status_t; namespace aidl::android::hardware::audio::core { StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context) - : StreamCommonImpl(metadata, std::move(context)), - mFrameSizeBytes(getContext().getFrameSize()), - mIsInput(isInput(metadata)), - mConfig(maybePopulateConfig(getContext(), mIsInput)) {} - -// static -std::optional StreamUsb::maybePopulateConfig(const StreamContext& context, - bool isInput) { - struct pcm_config config; - config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput); - if (config.channels == 0) { - LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString(); - return std::nullopt; - } - config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat()); - if (config.format == PCM_FORMAT_INVALID) { - LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString(); - return std::nullopt; - } - config.rate = context.getSampleRate(); - if (config.rate == 0) { - LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate; - return std::nullopt; - } - return config; -} - -::android::status_t StreamUsb::init() { - return mConfig.has_value() ? ::android::OK : ::android::NO_INIT; -} - -const StreamCommonInterface::ConnectedDevices& StreamUsb::getConnectedDevices() const { - std::lock_guard guard(mLock); - return mConnectedDevices; -} + : StreamAlsa(metadata, std::move(context)) {} ndk::ScopedAStatus StreamUsb::setConnectedDevices( const std::vector& connectedDevices) { @@ -89,14 +45,19 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( << ") for input stream"; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } + std::vector connectedDeviceProfiles; for (const auto& connectedDevice : connectedDevices) { - if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) { - LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString(); + auto profile = alsa::getDeviceProfile(connectedDevice, mIsInput); + if (!profile.has_value()) { + LOG(ERROR) << __func__ + << ": unsupported device address=" << connectedDevice.address.toString(); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } + connectedDeviceProfiles.push_back(*profile); } - std::lock_guard guard(mLock); RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices)); + std::lock_guard guard(mLock); + mConnectedDeviceProfiles = std::move(connectedDeviceProfiles); mConnectedDevicesUpdated.store(true, std::memory_order_release); return ndk::ScopedAStatus::ok(); } @@ -119,87 +80,22 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( ::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) { - // 'setConnectedDevices' has been called. I/O will be restarted. + // 'setConnectedDevices' was called. I/O will be restarted. *actualFrameCount = 0; *latencyMs = StreamDescriptor::LATENCY_UNKNOWN; return ::android::OK; } - const size_t bytesToTransfer = frameCount * mFrameSizeBytes; - unsigned maxLatency = 0; - if (mIsInput) { - if (mAlsaDeviceProxies.empty()) { - LOG(FATAL) << __func__ << ": no input devices"; - return ::android::NO_INIT; - } - // For input case, only support single device. - proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer); - maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get()); - } else { - for (auto& proxy : mAlsaDeviceProxies) { - proxy_write(proxy.get(), buffer, bytesToTransfer); - maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get())); - } - } - *actualFrameCount = frameCount; - maxLatency = std::min(maxLatency, static_cast(std::numeric_limits::max())); - *latencyMs = maxLatency; - return ::android::OK; + return StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs); } -::android::status_t StreamUsb::standby() { - mAlsaDeviceProxies.clear(); - return ::android::OK; -} - -void StreamUsb::shutdown() { - mAlsaDeviceProxies.clear(); -} - -::android::status_t StreamUsb::start() { - std::vector connectedDevices; +std::vector StreamUsb::getDeviceProfiles() { + std::vector connectedDevices; { std::lock_guard guard(mLock); - std::transform(mConnectedDevices.begin(), mConnectedDevices.end(), - std::back_inserter(connectedDevices), - [](const auto& device) { return device.address; }); + connectedDevices = mConnectedDeviceProfiles; mConnectedDevicesUpdated.store(false, std::memory_order_release); } - decltype(mAlsaDeviceProxies) alsaDeviceProxies; - for (const auto& device : connectedDevices) { - alsa_device_profile profile; - profile_init(&profile, mIsInput ? PCM_IN : PCM_OUT); - profile.card = device.get()[0]; - profile.device = device.get()[1]; - if (!profile_read_device_info(&profile)) { - LOG(ERROR) << __func__ - << ": unable to read device info, device address=" << device.toString(); - return ::android::UNKNOWN_ERROR; - } - - AlsaDeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) { - proxy_close(proxy); - free(proxy); - }); - // Always ask for alsa configure as required since the configuration should be supported - // by the connected device. That is guaranteed by `setAudioPortConfig` and - // `setAudioPatch`. - if (int err = proxy_prepare(proxy.get(), &profile, - const_cast(&mConfig.value()), - true /*is_bit_perfect*/); - err != 0) { - LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device.toString() - << " error=" << err; - return ::android::UNKNOWN_ERROR; - } - if (int err = proxy_open(proxy.get()); err != 0) { - LOG(ERROR) << __func__ << ": failed to open device, address=" << device.toString() - << " error=" << err; - return ::android::UNKNOWN_ERROR; - } - alsaDeviceProxies.push_back(std::move(proxy)); - } - mAlsaDeviceProxies = std::move(alsaDeviceProxies); - return ::android::OK; + return connectedDevices; } StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context, @@ -214,9 +110,9 @@ ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional& offloadInfo) - : StreamUsb(sourceMetadata, std::move(context)), StreamOut(offloadInfo) { - mChannelCount = getChannelCount(getContext().getChannelLayout()); -} + : StreamUsb(sourceMetadata, std::move(context)), + StreamOut(offloadInfo), + mChannelCount(getChannelCount(getContext().getChannelLayout())) {} ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { *_aidl_return = mHwVolumes; @@ -224,17 +120,17 @@ ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { } ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector& in_channelVolumes) { + // Avoid using mConnectedDeviceProfiles because it requires a lock. for (const auto& device : getConnectedDevices()) { - if (device.address.getTag() != AudioDeviceAddress::alsa) { - LOG(DEBUG) << __func__ << ": skip as the device address is not alsa"; - continue; - } - const int card = device.address.get()[0]; - if (auto result = - usb::UsbAlsaMixerControl::getInstance().setVolumes(card, in_channelVolumes); - !result.isOk()) { - LOG(ERROR) << __func__ << ": failed to set volume for device, card=" << card; - return result; + if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput); + deviceProfile.has_value()) { + if (auto result = usb::UsbAlsaMixerControl::getInstance().setVolumes( + deviceProfile->card, in_channelVolumes); + !result.isOk()) { + LOG(ERROR) << __func__ + << ": failed to set volume for device address=" << *deviceProfile; + return result; + } } } mHwVolumes = in_channelVolumes; diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp index 6c0c24bc09..769d739969 100644 --- a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp +++ b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp @@ -17,144 +17,12 @@ #define LOG_TAG "AHAL_UsbAlsaMixerControl" #include -#include -#include -#include - #include #include "UsbAlsaMixerControl.h" namespace aidl::android::hardware::audio::core::usb { -//----------------------------------------------------------------------------- - -MixerControl::MixerControl(struct mixer_ctl* ctl) - : mCtl(ctl), - mNumValues(mixer_ctl_get_num_values(ctl)), - mMinValue(mixer_ctl_get_range_min(ctl)), - mMaxValue(mixer_ctl_get_range_max(ctl)) {} - -unsigned int MixerControl::getNumValues() const { - return mNumValues; -} - -int MixerControl::getMaxValue() const { - return mMaxValue; -} - -int MixerControl::getMinValue() const { - return mMinValue; -} - -int MixerControl::setArray(const void* array, size_t count) { - const std::lock_guard guard(mLock); - return mixer_ctl_set_array(mCtl, array, count); -} - -//----------------------------------------------------------------------------- - -// static -const std::map> - AlsaMixer::kPossibleControls = { - {AlsaMixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}}, - {AlsaMixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}}, - {AlsaMixer::HW_VOLUME, - {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT}, - {"Headset Playback Volume", MIXER_CTL_TYPE_INT}, - {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}}; - -// static -std::map> AlsaMixer::initializeMixerControls( - struct mixer* mixer) { - std::map> mixerControls; - std::string mixerCtlNames; - for (const auto& [control, possibleCtls] : kPossibleControls) { - for (const auto& [ctlName, expectedCtlType] : possibleCtls) { - struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str()); - if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) { - mixerControls.emplace(control, std::make_unique(ctl)); - if (!mixerCtlNames.empty()) { - mixerCtlNames += ","; - } - mixerCtlNames += ctlName; - break; - } - } - } - LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]"; - return mixerControls; -} - -AlsaMixer::AlsaMixer(struct mixer* mixer) - : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {} - -AlsaMixer::~AlsaMixer() { - mixer_close(mMixer); -} - -namespace { - -int volumeFloatToInteger(float fValue, int maxValue, int minValue) { - return minValue + std::ceil((maxValue - minValue) * fValue); -} - -} // namespace - -ndk::ScopedAStatus AlsaMixer::setMasterMute(bool muted) { - auto it = mMixerControls.find(AlsaMixer::MASTER_SWITCH); - if (it == mMixerControls.end()) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - const int numValues = it->second->getNumValues(); - std::vector values(numValues, muted ? 0 : 1); - if (int err = it->second->setArray(values.data(), numValues); err != 0) { - LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus AlsaMixer::setMasterVolume(float volume) { - auto it = mMixerControls.find(AlsaMixer::MASTER_VOLUME); - if (it == mMixerControls.end()) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - const int numValues = it->second->getNumValues(); - std::vector values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(), - it->second->getMinValue())); - if (int err = it->second->setArray(values.data(), numValues); err != 0) { - LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus AlsaMixer::setVolumes(std::vector volumes) { - auto it = mMixerControls.find(AlsaMixer::HW_VOLUME); - if (it == mMixerControls.end()) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - const int numValues = it->second->getNumValues(); - if (numValues < 0) { - LOG(FATAL) << __func__ << ": negative number of values: " << numValues; - } - const int maxValue = it->second->getMaxValue(); - const int minValue = it->second->getMinValue(); - std::vector values; - size_t i = 0; - for (; i < static_cast(numValues) && i < values.size(); ++i) { - values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue)); - } - if (int err = it->second->setArray(values.data(), values.size()); err != 0) { - LOG(ERROR) << __func__ << ": failed to set volume, err=" << err; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - return ndk::ScopedAStatus::ok(); -} - -//----------------------------------------------------------------------------- - // static UsbAlsaMixerControl& UsbAlsaMixerControl::getInstance() { static UsbAlsaMixerControl gInstance; @@ -170,7 +38,7 @@ void UsbAlsaMixerControl::setDeviceConnectionState(int card, bool masterMuted, f PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card; return; } - auto alsaMixer = std::make_shared(mixer); + auto alsaMixer = std::make_shared(mixer); alsaMixer->setMasterMute(masterMuted); alsaMixer->setMasterVolume(masterVolume); const std::lock_guard guard(mLock); @@ -209,7 +77,7 @@ ndk::ScopedAStatus UsbAlsaMixerControl::setMasterVolume(float volume) { return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, std::vector volumes) { +ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, const std::vector& volumes) { auto alsaMixer = getAlsaMixer(card); if (alsaMixer == nullptr) { LOG(ERROR) << __func__ << ": no mixer control found for card=" << card; @@ -218,13 +86,13 @@ ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, std::vector return alsaMixer->setVolumes(volumes); } -std::shared_ptr UsbAlsaMixerControl::getAlsaMixer(int card) { +std::shared_ptr UsbAlsaMixerControl::getAlsaMixer(int card) { const std::lock_guard guard(mLock); const auto it = mMixerControls.find(card); return it == mMixerControls.end() ? nullptr : it->second; } -std::map> UsbAlsaMixerControl::getAlsaMixers() { +std::map> UsbAlsaMixerControl::getAlsaMixers() { const std::lock_guard guard(mLock); return mMixerControls; } diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.h b/audio/aidl/default/usb/UsbAlsaMixerControl.h index cbcddd82c6..c3265f8fd3 100644 --- a/audio/aidl/default/usb/UsbAlsaMixerControl.h +++ b/audio/aidl/default/usb/UsbAlsaMixerControl.h @@ -19,67 +19,15 @@ #include #include #include -#include -#include #include #include #include -extern "C" { -#include -} +#include "alsa/Mixer.h" namespace aidl::android::hardware::audio::core::usb { -class MixerControl { - public: - explicit MixerControl(struct mixer_ctl* ctl); - - unsigned int getNumValues() const; - int getMaxValue() const; - int getMinValue() const; - int setArray(const void* array, size_t count); - - private: - std::mutex mLock; - // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed. - struct mixer_ctl* mCtl GUARDED_BY(mLock); - const unsigned int mNumValues; - const int mMinValue; - const int mMaxValue; -}; - -class AlsaMixer { - public: - explicit AlsaMixer(struct mixer* mixer); - - ~AlsaMixer(); - - bool isValid() const { return mMixer != nullptr; } - - ndk::ScopedAStatus setMasterMute(bool muted); - ndk::ScopedAStatus setMasterVolume(float volume); - ndk::ScopedAStatus setVolumes(std::vector volumes); - - private: - enum Control { - MASTER_SWITCH, - MASTER_VOLUME, - HW_VOLUME, - }; - using ControlNamesAndExpectedCtlType = std::pair; - static const std::map> kPossibleControls; - static std::map> initializeMixerControls( - struct mixer* mixer); - - // The mixer object is owned by ALSA and will be released when the mixer is closed. - struct mixer* mMixer; - // `mMixerControls` will only be initialized in constructor. After that, it wil only be - // read but not be modified. - const std::map> mMixerControls; -}; - class UsbAlsaMixerControl { public: static UsbAlsaMixerControl& getInstance(); @@ -91,16 +39,16 @@ class UsbAlsaMixerControl { ndk::ScopedAStatus setMasterMute(bool muted); ndk::ScopedAStatus setMasterVolume(float volume); // The volume settings can be different on sound cards. It is controlled by streams. - ndk::ScopedAStatus setVolumes(int card, std::vector volumes); + ndk::ScopedAStatus setVolumes(int card, const std::vector& volumes); private: - std::shared_ptr getAlsaMixer(int card); - std::map> getAlsaMixers(); + std::shared_ptr getAlsaMixer(int card); + std::map> getAlsaMixers(); std::mutex mLock; // A map whose key is the card number and value is a shared pointer to corresponding // AlsaMixer object. - std::map> mMixerControls GUARDED_BY(mLock); + std::map> mMixerControls GUARDED_BY(mLock); }; } // namespace aidl::android::hardware::audio::core::usb diff --git a/audio/aidl/default/usb/UsbAlsaUtils.cpp b/audio/aidl/default/usb/UsbAlsaUtils.cpp deleted file mode 100644 index 74d9c289a5..0000000000 --- a/audio/aidl/default/usb/UsbAlsaUtils.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include -#include -#include - -#include "UsbAlsaUtils.h" -#include "core-impl/utils.h" - -using aidl::android::hardware::audio::common::getChannelCount; -using aidl::android::media::audio::common::AudioChannelLayout; -using aidl::android::media::audio::common::AudioFormatDescription; -using aidl::android::media::audio::common::AudioFormatType; -using aidl::android::media::audio::common::PcmType; - -namespace aidl::android::hardware::audio::core::usb { - -namespace { - -using AudioChannelCountToMaskMap = std::map; -using AudioFormatDescToPcmFormatMap = std::map; -using PcmFormatToAudioFormatDescMap = std::map; - -static const AudioChannelLayout INVALID_CHANNEL_LAYOUT = - AudioChannelLayout::make(0); - -#define DEFINE_CHANNEL_LAYOUT_MASK(n) \ - AudioChannelLayout::make(AudioChannelLayout::LAYOUT_##n) - -static const std::set SUPPORTED_OUT_CHANNEL_LAYOUTS = { - DEFINE_CHANNEL_LAYOUT_MASK(MONO), DEFINE_CHANNEL_LAYOUT_MASK(STEREO), - DEFINE_CHANNEL_LAYOUT_MASK(2POINT1), DEFINE_CHANNEL_LAYOUT_MASK(QUAD), - DEFINE_CHANNEL_LAYOUT_MASK(PENTA), DEFINE_CHANNEL_LAYOUT_MASK(5POINT1), - DEFINE_CHANNEL_LAYOUT_MASK(6POINT1), DEFINE_CHANNEL_LAYOUT_MASK(7POINT1), - DEFINE_CHANNEL_LAYOUT_MASK(7POINT1POINT4), DEFINE_CHANNEL_LAYOUT_MASK(22POINT2), -}; - -static const std::set SUPPORTED_IN_CHANNEL_LAYOUTS = { - DEFINE_CHANNEL_LAYOUT_MASK(MONO), - DEFINE_CHANNEL_LAYOUT_MASK(STEREO), -}; - -#define DEFINE_CHANNEL_INDEX_MASK(n) \ - AudioChannelLayout::make(AudioChannelLayout::INDEX_MASK_##n) - -static const std::set SUPPORTED_INDEX_CHANNEL_LAYOUTS = { - DEFINE_CHANNEL_INDEX_MASK(1), DEFINE_CHANNEL_INDEX_MASK(2), DEFINE_CHANNEL_INDEX_MASK(3), - DEFINE_CHANNEL_INDEX_MASK(4), DEFINE_CHANNEL_INDEX_MASK(5), DEFINE_CHANNEL_INDEX_MASK(6), - DEFINE_CHANNEL_INDEX_MASK(7), DEFINE_CHANNEL_INDEX_MASK(8), DEFINE_CHANNEL_INDEX_MASK(9), - DEFINE_CHANNEL_INDEX_MASK(10), DEFINE_CHANNEL_INDEX_MASK(11), DEFINE_CHANNEL_INDEX_MASK(12), - DEFINE_CHANNEL_INDEX_MASK(13), DEFINE_CHANNEL_INDEX_MASK(14), DEFINE_CHANNEL_INDEX_MASK(15), - DEFINE_CHANNEL_INDEX_MASK(16), DEFINE_CHANNEL_INDEX_MASK(17), DEFINE_CHANNEL_INDEX_MASK(18), - DEFINE_CHANNEL_INDEX_MASK(19), DEFINE_CHANNEL_INDEX_MASK(20), DEFINE_CHANNEL_INDEX_MASK(21), - DEFINE_CHANNEL_INDEX_MASK(22), DEFINE_CHANNEL_INDEX_MASK(23), DEFINE_CHANNEL_INDEX_MASK(24), -}; - -static AudioChannelCountToMaskMap make_ChannelCountToMaskMap( - const std::set& channelMasks) { - AudioChannelCountToMaskMap channelMaskToCountMap; - for (const auto& channelMask : channelMasks) { - channelMaskToCountMap.emplace(getChannelCount(channelMask), channelMask); - } - return channelMaskToCountMap; -} - -const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() { - static const AudioChannelCountToMaskMap outLayouts = - make_ChannelCountToMaskMap(SUPPORTED_OUT_CHANNEL_LAYOUTS); - return outLayouts; -} - -const AudioChannelCountToMaskMap& getSupportedChannelInLayoutMap() { - static const AudioChannelCountToMaskMap inLayouts = - make_ChannelCountToMaskMap(SUPPORTED_IN_CHANNEL_LAYOUTS); - return inLayouts; -} - -const AudioChannelCountToMaskMap& getSupportedChannelIndexLayoutMap() { - static const AudioChannelCountToMaskMap indexLayouts = - make_ChannelCountToMaskMap(SUPPORTED_INDEX_CHANNEL_LAYOUTS); - return indexLayouts; -} - -AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) { - AudioFormatDescription result; - result.type = type; - return result; -} - -AudioFormatDescription make_AudioFormatDescription(PcmType pcm) { - auto result = make_AudioFormatDescription(AudioFormatType::PCM); - result.pcm = pcm; - return result; -} - -const AudioFormatDescToPcmFormatMap& getAudioFormatDescriptorToPcmFormatMap() { - static const AudioFormatDescToPcmFormatMap formatDescToPcmFormatMap = { - {make_AudioFormatDescription(PcmType::UINT_8_BIT), PCM_FORMAT_S8}, - {make_AudioFormatDescription(PcmType::INT_16_BIT), PCM_FORMAT_S16_LE}, - {make_AudioFormatDescription(PcmType::FIXED_Q_8_24), PCM_FORMAT_S24_LE}, - {make_AudioFormatDescription(PcmType::INT_24_BIT), PCM_FORMAT_S24_3LE}, - {make_AudioFormatDescription(PcmType::INT_32_BIT), PCM_FORMAT_S32_LE}, - {make_AudioFormatDescription(PcmType::FLOAT_32_BIT), PCM_FORMAT_FLOAT_LE}, - }; - return formatDescToPcmFormatMap; -} - -static PcmFormatToAudioFormatDescMap make_PcmFormatToAudioFormatDescMap( - const AudioFormatDescToPcmFormatMap& formatDescToPcmFormatMap) { - PcmFormatToAudioFormatDescMap result; - for (const auto& formatPair : formatDescToPcmFormatMap) { - result.emplace(formatPair.second, formatPair.first); - } - return result; -} - -const PcmFormatToAudioFormatDescMap& getPcmFormatToAudioFormatDescMap() { - static const PcmFormatToAudioFormatDescMap pcmFormatToFormatDescMap = - make_PcmFormatToAudioFormatDescMap(getAudioFormatDescriptorToPcmFormatMap()); - return pcmFormatToFormatDescMap; -} - -} // namespace - -AudioChannelLayout getChannelLayoutMaskFromChannelCount(unsigned int channelCount, int isInput) { - return findValueOrDefault( - isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(), - channelCount, INVALID_CHANNEL_LAYOUT); -} - -AudioChannelLayout getChannelIndexMaskFromChannelCount(unsigned int channelCount) { - return findValueOrDefault(getSupportedChannelIndexLayoutMap(), channelCount, - INVALID_CHANNEL_LAYOUT); -} - -unsigned int getChannelCountFromChannelMask(const AudioChannelLayout& channelMask, bool isInput) { - switch (channelMask.getTag()) { - case AudioChannelLayout::Tag::layoutMask: { - return findKeyOrDefault( - isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(), - (unsigned int)getChannelCount(channelMask), 0u /*defaultValue*/); - } - case AudioChannelLayout::Tag::indexMask: { - return findKeyOrDefault(getSupportedChannelIndexLayoutMap(), - (unsigned int)getChannelCount(channelMask), - 0u /*defaultValue*/); - } - case AudioChannelLayout::Tag::none: - case AudioChannelLayout::Tag::invalid: - case AudioChannelLayout::Tag::voiceMask: - default: - return 0; - } -} - -AudioFormatDescription legacy2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) { - return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription()); -} - -pcm_format aidl2legacy_AudioFormatDescription_pcm_format(const AudioFormatDescription& aidl) { - return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID); -} - -} // namespace aidl::android::hardware::audio::core::usb diff --git a/audio/aidl/default/usb/UsbAlsaUtils.h b/audio/aidl/default/usb/UsbAlsaUtils.h deleted file mode 100644 index 2d2f0f4342..0000000000 --- a/audio/aidl/default/usb/UsbAlsaUtils.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -extern "C" { -#include -} - -namespace aidl::android::hardware::audio::core::usb { - -::aidl::android::media::audio::common::AudioChannelLayout getChannelLayoutMaskFromChannelCount( - unsigned int channelCount, int isInput); -::aidl::android::media::audio::common::AudioChannelLayout getChannelIndexMaskFromChannelCount( - unsigned int channelCount); -unsigned int getChannelCountFromChannelMask( - const ::aidl::android::media::audio::common::AudioChannelLayout& channelMask, bool isInput); -::aidl::android::media::audio::common::AudioFormatDescription -legacy2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy); -pcm_format aidl2legacy_AudioFormatDescription_pcm_format( - const ::aidl::android::media::audio::common::AudioFormatDescription& aidl); - -} // namespace aidl::android::hardware::audio::core::usb \ No newline at end of file From 38f8530b2359d5372e6fbf0085c39718c8c39ddc Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 11 Jul 2023 17:24:08 -0700 Subject: [PATCH 069/152] audio: Create ModulePrimary and ModuleStub Make 'Module' more abstract by moving stream creation methods to more concrete 'ModulePrimary' and 'ModuleStub'. 'ModulePrimary' is now closer to the CF primary module: it was stripped off USB devices from its configuration, these got moved to 'ModuleUsb', and got rid of BT A2DP and LE interfaces, these will be on 'ModuleBluetooth'. Note that 'ModulePrimary' still uses stub streams, this will be changed in subsequent patches. 'ModuleStub' is what 'Module' used to be, just a module for improving test coverage. It includes simulation of offload streams and dummy BT objects. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Change-Id: I5e4da0c32c00d65688f2eda78b2c79594e4e4671 (cherry picked from commit 521fc49fba3de4f0843a04625ebc369933b47352) Merged-In: I5e4da0c32c00d65688f2eda78b2c79594e4e4671 --- audio/aidl/default/Android.bp | 4 +- audio/aidl/default/Configuration.cpp | 171 +++++++++++++----- audio/aidl/default/Module.cpp | 68 +++---- audio/aidl/default/ModulePrimary.cpp | 60 ++++++ .../android.hardware.audio.service-aidl.xml | 5 + .../include/core-impl/ChildInterface.h | 48 +++++ .../default/include/core-impl/Configuration.h | 1 + audio/aidl/default/include/core-impl/Module.h | 34 +--- .../default/include/core-impl/ModulePrimary.h | 46 +++++ .../include/core-impl/ModuleRemoteSubmix.h | 2 +- .../default/include/core-impl/ModuleStub.h | 50 +++++ .../default/include/core-impl/ModuleUsb.h | 2 +- audio/aidl/default/main.cpp | 18 +- audio/aidl/default/stub/ModuleStub.cpp | 78 ++++++++ audio/aidl/default/{ => stub}/StreamStub.cpp | 0 15 files changed, 463 insertions(+), 124 deletions(-) create mode 100644 audio/aidl/default/ModulePrimary.cpp create mode 100644 audio/aidl/default/include/core-impl/ChildInterface.h create mode 100644 audio/aidl/default/include/core-impl/ModulePrimary.h create mode 100644 audio/aidl/default/include/core-impl/ModuleStub.h create mode 100644 audio/aidl/default/stub/ModuleStub.cpp rename audio/aidl/default/{ => stub}/StreamStub.cpp (100%) diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 69443d4194..19b2397de6 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -73,9 +73,9 @@ cc_library { "Configuration.cpp", "EngineConfigXmlConverter.cpp", "Module.cpp", + "ModulePrimary.cpp", "SoundDose.cpp", "Stream.cpp", - "StreamStub.cpp", "Telephony.cpp", "alsa/Mixer.cpp", "alsa/ModuleAlsa.cpp", @@ -85,6 +85,8 @@ cc_library { "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", "r_submix/StreamRemoteSubmix.cpp", + "stub/ModuleStub.cpp", + "stub/StreamStub.cpp", "usb/ModuleUsb.cpp", "usb/StreamUsb.cpp", "usb/UsbAlsaMixerControl.cpp", diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index d41ea67329..a71c6ea734 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -144,10 +144,6 @@ static AudioRoute createRoute(const std::vector& sources, const Audio // - no profiles specified // * "FM Tuner", IN_FM_TUNER // - no profiles specified -// * "USB Out", OUT_DEVICE, CONNECTION_USB -// - no profiles specified -// * "USB In", IN_DEVICE, CONNECTION_USB -// - no profiles specified // // Mix ports: // * "primary output", PRIMARY, 1 max open, 1 max active stream @@ -172,8 +168,7 @@ static AudioRoute createRoute(const std::vector& sources, const Audio // // Routes: // "primary out", "compressed offload" -> "Speaker" -// "primary out", "compressed offload" -> "USB Out" -// "Built-in Mic", "USB In" -> "primary input" +// "Built-in Mic" -> "primary input" // "telephony_tx" -> "Telephony Tx" // "Telephony Rx" -> "telephony_rx" // "FM Tuner" -> "fm_tuner" @@ -185,14 +180,6 @@ static AudioRoute createRoute(const std::vector& sources, const Audio // * "Telephony Rx" device port: PCM 24-bit; MONO; 48000 // * "FM Tuner" device port: PCM 24-bit; STEREO; 48000 // -// Profiles for device port connected state: -// * USB Out": -// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// * USB In": -// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// std::unique_ptr getPrimaryConfiguration() { static const Configuration configuration = []() { const std::vector standardPcmAudioProfiles = { @@ -252,19 +239,6 @@ std::unique_ptr getPrimaryConfiguration() { AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true, createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0))); - AudioPort usbOutDevice = - createPort(c.nextPortId++, "USB Out", 0, false, - createDeviceExt(AudioDeviceType::OUT_DEVICE, 0, - AudioDeviceDescription::CONNECTION_USB)); - c.ports.push_back(usbOutDevice); - c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles; - - AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true, - createDeviceExt(AudioDeviceType::IN_DEVICE, 0, - AudioDeviceDescription::CONNECTION_USB)); - c.ports.push_back(usbInDevice); - c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles; - // Mix ports AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output", @@ -323,8 +297,7 @@ std::unique_ptr getPrimaryConfiguration() { c.ports.push_back(fmTunerInMix); c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, speakerOutDevice)); - c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, usbOutDevice)); - c.routes.push_back(createRoute({micInDevice, usbInDevice}, primaryInMix)); + c.routes.push_back(createRoute({micInDevice}, primaryInMix)); c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice)); c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix)); c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix)); @@ -406,22 +379,31 @@ std::unique_ptr getRSubmixConfiguration() { // Usb configuration: // // Device ports: +// * "USB Device Out", OUT_DEVICE, CONNECTION_USB +// - no profiles specified // * "USB Headset Out", OUT_HEADSET, CONNECTION_USB // - no profiles specified +// * "USB Device In", IN_DEVICE, CONNECTION_USB +// - no profiles specified // * "USB Headset In", IN_HEADSET, CONNECTION_USB // - no profiles specified // // Mix ports: -// * "usb_headset output", 1 max open, 1 max active stream +// * "usb_device output", 1 max open, 1 max active stream // - no profiles specified -// * "usb_headset input", 1 max open, 1 max active stream +// * "usb_device input", 1 max open, 1 max active stream // - no profiles specified // +// Routes: +// * "usb_device output" -> "USB Device Out" +// * "usb_device output" -> "USB Headset Out" +// * "USB Device In", "USB Headset In" -> "usb_device input" +// // Profiles for device port connected state: -// * USB Headset Out": +// * "USB Device Out", "USB Headset Out": // - profile PCM 16-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000 // - profile PCM 24-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000 -// * USB Headset In": +// * "USB Device In", "USB Headset In": // - profile PCM 16-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000 // - profile PCM 24-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000 // @@ -440,6 +422,13 @@ std::unique_ptr getUsbConfiguration() { // Device ports + AudioPort usbOutDevice = + createPort(c.nextPortId++, "USB Device Out", 0, false, + createDeviceExt(AudioDeviceType::OUT_DEVICE, 0, + AudioDeviceDescription::CONNECTION_USB)); + c.ports.push_back(usbOutDevice); + c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles; + AudioPort usbOutHeadset = createPort(c.nextPortId++, "USB Headset Out", 0, false, createDeviceExt(AudioDeviceType::OUT_HEADSET, 0, @@ -447,6 +436,12 @@ std::unique_ptr getUsbConfiguration() { c.ports.push_back(usbOutHeadset); c.connectedProfiles[usbOutHeadset.id] = standardPcmAudioProfiles; + AudioPort usbInDevice = createPort(c.nextPortId++, "USB Device In", 0, true, + createDeviceExt(AudioDeviceType::IN_DEVICE, 0, + AudioDeviceDescription::CONNECTION_USB)); + c.ports.push_back(usbInDevice); + c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles; + AudioPort usbInHeadset = createPort(c.nextPortId++, "USB Headset In", 0, true, createDeviceExt(AudioDeviceType::IN_HEADSET, 0, @@ -456,16 +451,110 @@ std::unique_ptr getUsbConfiguration() { // Mix ports - AudioPort usbHeadsetOutMix = - createPort(c.nextPortId++, "usb_headset output", 0, false, createPortMixExt(1, 1)); - c.ports.push_back(usbHeadsetOutMix); + AudioPort usbDeviceOutMix = + createPort(c.nextPortId++, "usb_device output", 0, false, createPortMixExt(1, 1)); + c.ports.push_back(usbDeviceOutMix); - AudioPort usbHeadsetInMix = - createPort(c.nextPortId++, "usb_headset input", 0, true, createPortMixExt(1, 1)); - c.ports.push_back(usbHeadsetInMix); + AudioPort usbDeviceInMix = + createPort(c.nextPortId++, "usb_device input", 0, true, createPortMixExt(1, 1)); + c.ports.push_back(usbDeviceInMix); - c.routes.push_back(createRoute({usbHeadsetOutMix}, usbOutHeadset)); - c.routes.push_back(createRoute({usbInHeadset}, usbHeadsetInMix)); + c.routes.push_back(createRoute({usbDeviceOutMix}, usbOutDevice)); + c.routes.push_back(createRoute({usbDeviceOutMix}, usbOutHeadset)); + c.routes.push_back(createRoute({usbInDevice, usbInHeadset}, usbDeviceInMix)); + + return c; + }(); + return std::make_unique(configuration); +} + +// Stub configuration: +// +// Device ports: +// * "Test Out", OUT_AFE_PROXY +// - no profiles specified +// * "Test In", IN_AFE_PROXY +// - no profiles specified +// +// Mix ports: +// * "test output", 1 max open, 1 max active stream +// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 +// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream +// - profile MP3; MONO, STEREO; 44100, 48000 +// * "test input", 2 max open, 2 max active streams +// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK; +// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +// +// Routes: +// "test output", "compressed offload" -> "Test Out" +// "Test In" -> "test input" +// +// Initial port configs: +// * "Test Out" device port: PCM 24-bit; STEREO; 48000 +// * "Test In" device port: PCM 24-bit; MONO; 48000 +// +std::unique_ptr getStubConfiguration() { + static const Configuration configuration = []() { + Configuration c; + + // Device ports + + AudioPort testOutDevice = createPort(c.nextPortId++, "Test Out", 0, false, + createDeviceExt(AudioDeviceType::OUT_AFE_PROXY, 0)); + c.ports.push_back(testOutDevice); + c.initialConfigs.push_back( + createPortConfig(testOutDevice.id, testOutDevice.id, PcmType::INT_24_BIT, + AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false, + createDeviceExt(AudioDeviceType::OUT_AFE_PROXY, 0))); + + AudioPort testInDevice = createPort(c.nextPortId++, "Test In", 0, true, + createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0)); + c.ports.push_back(testInDevice); + c.initialConfigs.push_back( + createPortConfig(testInDevice.id, testInDevice.id, PcmType::INT_24_BIT, + AudioChannelLayout::LAYOUT_MONO, 48000, 0, true, + createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0))); + + // Mix ports + + AudioPort testOutMix = + createPort(c.nextPortId++, "test output", 0, false, createPortMixExt(1, 1)); + testOutMix.profiles.push_back( + createProfile(PcmType::INT_24_BIT, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {8000, 11025, 16000, 32000, 44100, 48000})); + c.ports.push_back(testOutMix); + + AudioPort compressedOffloadOutMix = + createPort(c.nextPortId++, "compressed offload", + makeBitPositionFlagMask({AudioOutputFlags::DIRECT, + AudioOutputFlags::COMPRESS_OFFLOAD, + AudioOutputFlags::NON_BLOCKING}), + false, createPortMixExt(1, 1)); + compressedOffloadOutMix.profiles.push_back( + createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {44100, 48000})); + c.ports.push_back(compressedOffloadOutMix); + + AudioPort testInMIx = + createPort(c.nextPortId++, "test input", 0, true, createPortMixExt(2, 2)); + testInMIx.profiles.push_back( + createProfile(PcmType::INT_16_BIT, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, + AudioChannelLayout::LAYOUT_FRONT_BACK}, + {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); + testInMIx.profiles.push_back( + createProfile(PcmType::INT_24_BIT, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, + AudioChannelLayout::LAYOUT_FRONT_BACK}, + {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); + c.ports.push_back(testInMIx); + + c.routes.push_back(createRoute({testOutMix, compressedOffloadOutMix}, testOutDevice)); + c.routes.push_back(createRoute({testInDevice}, testInMIx)); + + c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end()); return c; }(); diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 48d14580a7..12bbbb0cba 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -25,13 +25,12 @@ #include #include -#include "core-impl/Bluetooth.h" #include "core-impl/Module.h" +#include "core-impl/ModulePrimary.h" #include "core-impl/ModuleRemoteSubmix.h" +#include "core-impl/ModuleStub.h" #include "core-impl/ModuleUsb.h" #include "core-impl/SoundDose.h" -#include "core-impl/StreamStub.h" -#include "core-impl/Telephony.h" #include "core-impl/utils.h" using aidl::android::hardware::audio::common::getFrameSizeInBytes; @@ -110,13 +109,14 @@ bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& forma // static std::shared_ptr Module::createInstance(Type type) { switch (type) { - case Module::Type::USB: - return ndk::SharedRefBase::make(type); - case Type::R_SUBMIX: - return ndk::SharedRefBase::make(type); case Type::DEFAULT: - default: - return ndk::SharedRefBase::make(type); + return ndk::SharedRefBase::make(); + case Type::R_SUBMIX: + return ndk::SharedRefBase::make(); + case Type::STUB: + return ndk::SharedRefBase::make(); + case Type::USB: + return ndk::SharedRefBase::make(); } } @@ -128,6 +128,9 @@ std::ostream& operator<<(std::ostream& os, Module::Type t) { case Module::Type::R_SUBMIX: os << "r_submix"; break; + case Module::Type::STUB: + os << "stub"; + break; case Module::Type::USB: os << "usb"; break; @@ -292,6 +295,9 @@ internal::Configuration& Module::getConfig() { case Type::R_SUBMIX: mConfig = std::move(internal::getRSubmixConfiguration()); break; + case Type::STUB: + mConfig = std::move(internal::getStubConfiguration()); + break; case Type::USB: mConfig = std::move(internal::getUsbConfiguration()); break; @@ -395,38 +401,26 @@ ndk::ScopedAStatus Module::setModuleDebug( } ndk::ScopedAStatus Module::getTelephony(std::shared_ptr* _aidl_return) { - if (!mTelephony) { - mTelephony = ndk::SharedRefBase::make(); - } - *_aidl_return = mTelephony.getPtr(); - LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get(); + *_aidl_return = nullptr; + LOG(DEBUG) << __func__ << ": returning null"; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Module::getBluetooth(std::shared_ptr* _aidl_return) { - if (!mBluetooth) { - mBluetooth = ndk::SharedRefBase::make(); - } - *_aidl_return = mBluetooth.getPtr(); - LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get(); + *_aidl_return = nullptr; + LOG(DEBUG) << __func__ << ": returning null"; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Module::getBluetoothA2dp(std::shared_ptr* _aidl_return) { - if (!mBluetoothA2dp) { - mBluetoothA2dp = ndk::SharedRefBase::make(); - } - *_aidl_return = mBluetoothA2dp.getPtr(); - LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get(); + *_aidl_return = nullptr; + LOG(DEBUG) << __func__ << ": returning null"; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Module::getBluetoothLe(std::shared_ptr* _aidl_return) { - if (!mBluetoothLe) { - mBluetoothLe = ndk::SharedRefBase::make(); - } - *_aidl_return = mBluetoothLe.getPtr(); - LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get(); + *_aidl_return = nullptr; + LOG(DEBUG) << __func__ << ": returning null"; return ndk::ScopedAStatus::ok(); } @@ -1334,22 +1328,6 @@ bool Module::isMmapSupported() { return mIsMmapSupported.value(); } -ndk::ScopedAStatus Module::createInputStream(const SinkMetadata& sinkMetadata, - StreamContext&& context, - const std::vector& microphones, - std::shared_ptr* result) { - return createStreamInstance(result, sinkMetadata, std::move(context), - microphones); -} - -ndk::ScopedAStatus Module::createOutputStream(const SourceMetadata& sourceMetadata, - StreamContext&& context, - const std::optional& offloadInfo, - std::shared_ptr* result) { - return createStreamInstance(result, sourceMetadata, std::move(context), - offloadInfo); -} - ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) { LOG(VERBOSE) << __func__ << ": do nothing and return ok"; return ndk::ScopedAStatus::ok(); diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp new file mode 100644 index 0000000000..cbb6730372 --- /dev/null +++ b/audio/aidl/default/ModulePrimary.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "AHAL_ModulePrimary" +#include +#include + +#include "core-impl/ModulePrimary.h" +#include "core-impl/StreamStub.h" +#include "core-impl/Telephony.h" + +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::media::audio::common::AudioOffloadInfo; +using aidl::android::media::audio::common::AudioPort; +using aidl::android::media::audio::common::AudioPortConfig; +using aidl::android::media::audio::common::MicrophoneInfo; + +namespace aidl::android::hardware::audio::core { + +ndk::ScopedAStatus ModulePrimary::getTelephony(std::shared_ptr* _aidl_return) { + if (!mTelephony) { + mTelephony = ndk::SharedRefBase::make(); + } + *_aidl_return = mTelephony.getPtr(); + LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModulePrimary::createInputStream(const SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector& microphones, + std::shared_ptr* result) { + return createStreamInstance(result, sinkMetadata, std::move(context), + microphones); +} + +ndk::ScopedAStatus ModulePrimary::createOutputStream( + const SourceMetadata& sourceMetadata, StreamContext&& context, + const std::optional& offloadInfo, std::shared_ptr* result) { + return createStreamInstance(result, sourceMetadata, std::move(context), + offloadInfo); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml index 9636a58d48..c9d6314e32 100644 --- a/audio/aidl/default/android.hardware.audio.service-aidl.xml +++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml @@ -9,6 +9,11 @@ 1 IModule/r_submix + + android.hardware.audio.core + 1 + IModule/stub + android.hardware.audio.core 1 diff --git a/audio/aidl/default/include/core-impl/ChildInterface.h b/audio/aidl/default/include/core-impl/ChildInterface.h new file mode 100644 index 0000000000..1b31691556 --- /dev/null +++ b/audio/aidl/default/include/core-impl/ChildInterface.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace aidl::android::hardware::audio::core { + +// Helper used for interfaces that require a persistent instance. We hold them via a strong +// pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'. +template +struct ChildInterface : private std::pair, ndk::SpAIBinder> { + ChildInterface() = default; + ChildInterface& operator=(const std::shared_ptr& c) { + return operator=(std::shared_ptr(c)); + } + ChildInterface& operator=(std::shared_ptr&& c) { + this->first = std::move(c); + this->second = this->first->asBinder(); + AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); + return *this; + } + explicit operator bool() const { return !!this->first; } + C& operator*() const { return *(this->first); } + C* operator->() const { return this->first; } + std::shared_ptr getPtr() const { return this->first; } +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h index 70320e46aa..25bf7afa81 100644 --- a/audio/aidl/default/include/core-impl/Configuration.h +++ b/audio/aidl/default/include/core-impl/Configuration.h @@ -45,6 +45,7 @@ struct Configuration { std::unique_ptr getPrimaryConfiguration(); std::unique_ptr getRSubmixConfiguration(); +std::unique_ptr getStubConfiguration(); std::unique_ptr getUsbConfiguration(); } // namespace aidl::android::hardware::audio::core::internal diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index 4a23637d86..ee0458be49 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -16,12 +16,14 @@ #pragma once +#include #include #include #include #include +#include "core-impl/ChildInterface.h" #include "core-impl/Configuration.h" #include "core-impl/Stream.h" @@ -31,7 +33,7 @@ class Module : public BnModule { public: // This value is used for all AudioPatches and reported by all streams. static constexpr int32_t kLatencyMs = 10; - enum Type : int { DEFAULT, R_SUBMIX, USB }; + enum Type : int { DEFAULT, R_SUBMIX, STUB, USB }; static std::shared_ptr createInstance(Type type); @@ -132,26 +134,6 @@ class Module : public BnModule { bool forceTransientBurst = false; bool forceSynchronousDrain = false; }; - // Helper used for interfaces that require a persistent instance. We hold them via a strong - // pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'. - template - struct ChildInterface : private std::pair, ndk::SpAIBinder> { - ChildInterface() {} - ChildInterface& operator=(const std::shared_ptr& c) { - return operator=(std::shared_ptr(c)); - } - ChildInterface& operator=(std::shared_ptr&& c) { - this->first = std::move(c); - this->second = this->first->asBinder(); - AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL, - ANDROID_PRIORITY_AUDIO); - return *this; - } - explicit operator bool() const { return !!this->first; } - C& operator*() const { return *(this->first); } - C* operator->() const { return this->first; } - std::shared_ptr getPtr() const { return this->first; } - }; // ids of device ports created at runtime via 'connectExternalDevice'. // Also stores a list of ids of mix ports with dynamic profiles that were populated from // the connected port. This list can be empty, thus an int->int multimap can't be used. @@ -164,10 +146,6 @@ class Module : public BnModule { std::unique_ptr mConfig; ModuleDebug mDebug; VendorDebug mVendorDebug; - ChildInterface mTelephony; - ChildInterface mBluetooth; - ChildInterface mBluetoothA2dp; - ChildInterface mBluetoothLe; ConnectedDevicePorts mConnectedDevicePorts; Streams mStreams; Patches mPatches; @@ -184,13 +162,13 @@ class Module : public BnModule { const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, - std::shared_ptr* result); + std::shared_ptr* result) = 0; virtual ndk::ScopedAStatus createOutputStream( const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo, - std::shared_ptr* result); + std::shared_ptr* result) = 0; // If the module is unable to populate the connected device port correctly, the returned error // code must correspond to the errors of `IModule.connectedExternalDevice` method. virtual ndk::ScopedAStatus populateConnectedDevicePort( @@ -232,4 +210,6 @@ class Module : public BnModule { const AudioPatch& newPatch); }; +std::ostream& operator<<(std::ostream& os, Module::Type t); + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/ModulePrimary.h b/audio/aidl/default/include/core-impl/ModulePrimary.h new file mode 100644 index 0000000000..bc808ab03d --- /dev/null +++ b/audio/aidl/default/include/core-impl/ModulePrimary.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "core-impl/Module.h" + +namespace aidl::android::hardware::audio::core { + +class ModulePrimary final : public Module { + public: + ModulePrimary() : Module(Type::DEFAULT) {} + + protected: + ndk::ScopedAStatus getTelephony(std::shared_ptr* _aidl_return) override; + + ndk::ScopedAStatus createInputStream( + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, + std::shared_ptr* result) override; + ndk::ScopedAStatus createOutputStream( + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo, + std::shared_ptr* result) override; + + private: + ChildInterface mTelephony; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h index 7b1d375117..ccfcdd9462 100644 --- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h @@ -22,7 +22,7 @@ namespace aidl::android::hardware::audio::core { class ModuleRemoteSubmix : public Module { public: - explicit ModuleRemoteSubmix(Module::Type type) : Module(type) {} + ModuleRemoteSubmix() : Module(Type::R_SUBMIX) {} private: // IModule interfaces diff --git a/audio/aidl/default/include/core-impl/ModuleStub.h b/audio/aidl/default/include/core-impl/ModuleStub.h new file mode 100644 index 0000000000..59c343f4b7 --- /dev/null +++ b/audio/aidl/default/include/core-impl/ModuleStub.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "core-impl/Module.h" + +namespace aidl::android::hardware::audio::core { + +class ModuleStub final : public Module { + public: + ModuleStub() : Module(Type::STUB) {} + + protected: + ndk::ScopedAStatus getBluetooth(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getBluetoothLe(std::shared_ptr* _aidl_return) override; + + ndk::ScopedAStatus createInputStream( + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, + std::shared_ptr* result) override; + ndk::ScopedAStatus createOutputStream( + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo, + std::shared_ptr* result) override; + + private: + ChildInterface mBluetooth; + ChildInterface mBluetoothA2dp; + ChildInterface mBluetoothLe; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h index ea7cc48214..e6b3e66e41 100644 --- a/audio/aidl/default/include/core-impl/ModuleUsb.h +++ b/audio/aidl/default/include/core-impl/ModuleUsb.h @@ -22,7 +22,7 @@ namespace aidl::android::hardware::audio::core { class ModuleUsb final : public ModuleAlsa { public: - explicit ModuleUsb(Module::Type type) : ModuleAlsa(type) {} + ModuleUsb() : ModuleAlsa(Type::USB) {} private: // IModule interfaces diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp index 12c0c4b53e..93fb36607e 100644 --- a/audio/aidl/default/main.cpp +++ b/audio/aidl/default/main.cpp @@ -16,20 +16,21 @@ #include #include +#include #include +#include #include +#include #include #include #include #include "core-impl/Config.h" #include "core-impl/Module.h" -#include "core-impl/ModuleUsb.h" using aidl::android::hardware::audio::core::Config; using aidl::android::hardware::audio::core::Module; -using aidl::android::hardware::audio::core::ModuleUsb; int main() { // Random values are used in the implementation. @@ -52,18 +53,19 @@ int main() { CHECK_EQ(STATUS_OK, status); // Make modules - auto createModule = [](Module::Type type, const std::string& instance) { + auto createModule = [](Module::Type type) { auto module = Module::createInstance(type); ndk::SpAIBinder moduleBinder = module->asBinder(); - const std::string moduleName = std::string(Module::descriptor).append("/").append(instance); + std::stringstream moduleName; + moduleName << Module::descriptor << "/" << type; AIBinder_setMinSchedulerPolicy(moduleBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); - binder_status_t status = AServiceManager_addService(moduleBinder.get(), moduleName.c_str()); + binder_status_t status = + AServiceManager_addService(moduleBinder.get(), moduleName.str().c_str()); CHECK_EQ(STATUS_OK, status); return std::make_pair(module, moduleBinder); }; - auto modules = {createModule(Module::Type::DEFAULT, "default"), - createModule(Module::Type::R_SUBMIX, "r_submix"), - createModule(Module::Type::USB, "usb")}; + auto modules = {createModule(Module::Type::DEFAULT), createModule(Module::Type::R_SUBMIX), + createModule(Module::Type::USB), createModule(Module::Type::STUB)}; (void)modules; ABinderProcess_joinThreadPool(); diff --git a/audio/aidl/default/stub/ModuleStub.cpp b/audio/aidl/default/stub/ModuleStub.cpp new file mode 100644 index 0000000000..a60075221d --- /dev/null +++ b/audio/aidl/default/stub/ModuleStub.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "AHAL_ModuleStub" +#include +#include + +#include "core-impl/Bluetooth.h" +#include "core-impl/ModuleStub.h" +#include "core-impl/StreamStub.h" + +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::media::audio::common::AudioOffloadInfo; +using aidl::android::media::audio::common::AudioPort; +using aidl::android::media::audio::common::AudioPortConfig; +using aidl::android::media::audio::common::MicrophoneInfo; + +namespace aidl::android::hardware::audio::core { + +ndk::ScopedAStatus ModuleStub::getBluetooth(std::shared_ptr* _aidl_return) { + if (!mBluetooth) { + mBluetooth = ndk::SharedRefBase::make(); + } + *_aidl_return = mBluetooth.getPtr(); + LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModuleStub::getBluetoothA2dp(std::shared_ptr* _aidl_return) { + if (!mBluetoothA2dp) { + mBluetoothA2dp = ndk::SharedRefBase::make(); + } + *_aidl_return = mBluetoothA2dp.getPtr(); + LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModuleStub::getBluetoothLe(std::shared_ptr* _aidl_return) { + if (!mBluetoothLe) { + mBluetoothLe = ndk::SharedRefBase::make(); + } + *_aidl_return = mBluetoothLe.getPtr(); + LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModuleStub::createInputStream(const SinkMetadata& sinkMetadata, + StreamContext&& context, + const std::vector& microphones, + std::shared_ptr* result) { + return createStreamInstance(result, sinkMetadata, std::move(context), + microphones); +} + +ndk::ScopedAStatus ModuleStub::createOutputStream( + const SourceMetadata& sourceMetadata, StreamContext&& context, + const std::optional& offloadInfo, std::shared_ptr* result) { + return createStreamInstance(result, sourceMetadata, std::move(context), + offloadInfo); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp similarity index 100% rename from audio/aidl/default/StreamStub.cpp rename to audio/aidl/default/stub/StreamStub.cpp From a639f1900ec92d11ae27932432b7c0b06164fd5a Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 13 Jul 2023 11:08:29 -0700 Subject: [PATCH 070/152] audio: Add optional 'DriverInterface::getPosition' method. This is a method which can be optionally implemented by a stream in case it can provide more exact position, for example by taking into account data in intermediate buffers. Implemented this method for StreamAlsa and StreamRemoteSubmix. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Change-Id: I392933f8f6b22d784726925199db00dcb0313648 (cherry picked from commit 704aec434e921c3cee833f9e113d89c3216c1f14) Merged-In: I392933f8f6b22d784726925199db00dcb0313648 --- audio/aidl/default/Stream.cpp | 8 +++-- audio/aidl/default/alsa/StreamAlsa.cpp | 32 +++++++++++++++++++ audio/aidl/default/include/core-impl/Stream.h | 6 ++++ .../default/include/core-impl/StreamAlsa.h | 1 + .../include/core-impl/StreamRemoteSubmix.h | 1 + .../default/r_submix/StreamRemoteSubmix.cpp | 21 ++++++++++++ 6 files changed, 66 insertions(+), 3 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 251dea09e5..215de94a31 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -110,10 +110,12 @@ void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply, if (isConnected) { reply->observable.frames = mFrameCount; reply->observable.timeNs = ::android::elapsedRealtimeNano(); - } else { - reply->observable.frames = StreamDescriptor::Position::UNKNOWN; - reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN; + if (auto status = mDriver->getPosition(&reply->observable); status == ::android::OK) { + return; + } } + reply->observable.frames = StreamDescriptor::Position::UNKNOWN; + reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN; } void StreamWorkerCommonLogic::populateReplyWrongState( diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp index ecb3c78a65..17c7febdd1 100644 --- a/audio/aidl/default/alsa/StreamAlsa.cpp +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "core-impl/StreamAlsa.h" @@ -96,6 +97,37 @@ StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context) return ::android::OK; } +::android::status_t StreamAlsa::getPosition(StreamDescriptor::Position* position) { + if (mAlsaDeviceProxies.empty()) { + LOG(FATAL) << __func__ << ": no input devices"; + return ::android::NO_INIT; + } + if (mIsInput) { + if (int ret = proxy_get_capture_position(mAlsaDeviceProxies[0].get(), &position->frames, + &position->timeNs); + ret != 0) { + LOG(WARNING) << __func__ << ": failed to retrieve capture position: " << ret; + return ::android::INVALID_OPERATION; + } + } else { + uint64_t hwFrames; + struct timespec timestamp; + if (int ret = proxy_get_presentation_position(mAlsaDeviceProxies[0].get(), &hwFrames, + ×tamp); + ret == 0) { + if (hwFrames > std::numeric_limits::max()) { + hwFrames -= std::numeric_limits::max(); + } + position->frames = static_cast(hwFrames); + position->timeNs = audio_utils_ns_from_timespec(×tamp); + } else { + LOG(WARNING) << __func__ << ": failed to retrieve presentation position: " << ret; + return ::android::INVALID_OPERATION; + } + } + return ::android::OK; +} + void StreamAlsa::shutdown() { mAlsaDeviceProxies.clear(); } diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index aaf58601b5..e64c578b68 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -184,6 +184,12 @@ struct DriverInterface { virtual ::android::status_t start() = 0; virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) = 0; + // No need to implement 'getPosition' unless the driver can provide more precise + // data than just total frame count. For example, the driver may correctly account + // for any intermediate buffers. + virtual ::android::status_t getPosition(StreamDescriptor::Position* /*position*/) { + return ::android::OK; + } virtual void shutdown() = 0; // This function is only called once. }; diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h index edfc72860c..5744d665f3 100644 --- a/audio/aidl/default/include/core-impl/StreamAlsa.h +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -38,6 +38,7 @@ class StreamAlsa : public StreamCommonImpl { ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; + ::android::status_t getPosition(StreamDescriptor::Position* position) override; void shutdown() override; protected: diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h index 2253ec76cd..1bca910995 100644 --- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -39,6 +39,7 @@ class StreamRemoteSubmix : public StreamCommonImpl { ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; + ::android::status_t getPosition(StreamDescriptor::Position* position) override; void shutdown() override; // Overridden methods of 'StreamCommonImpl', called on a Binder thread. diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 5af0d914b8..6d5185b346 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -179,6 +179,27 @@ void StreamRemoteSubmix::shutdown() { : outWrite(buffer, frameCount, actualFrameCount)); } +::android::status_t StreamRemoteSubmix::getPosition(StreamDescriptor::Position* position) { + sp source = mCurrentRoute->getSource(); + if (source == nullptr) { + return ::android::NO_INIT; + } + const ssize_t framesInPipe = source->availableToRead(); + if (framesInPipe < 0) { + return ::android::INVALID_OPERATION; + } + if (mIsInput) { + position->frames += framesInPipe; + } else { + if (position->frames > framesInPipe) { + position->frames -= framesInPipe; + } else { + position->frames = 0; + } + } + return ::android::OK; +} + // Calculate the maximum size of the pipe buffer in frames for the specified stream. size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { auto pipeConfig = mCurrentRoute->mPipeConfig; From 1ea9e5c5930b82b0b6303ebf3972065e0b6951cd Mon Sep 17 00:00:00 2001 From: Peter Yoon Date: Thu, 13 Jul 2023 17:04:37 +0900 Subject: [PATCH 071/152] audio: Allow Module subclasses to customize Configuration When a vendor HAL reuses libaudioserviceexampleimpl, a subclass of Module cannot change Configuration. This change adds virtual method Module::initializeConfig(), then a vendor HAL can override it to load custom Configuration. Test: atest VtsHalAudioCoreTargetTest Change-Id: I63fa8d70f3c4e13c8938070ee5431ebefd36bb58 (cherry picked from commit 918a6a5ce9f0583f4aefb12334e40412bfe6288e) Merged-In: I63fa8d70f3c4e13c8938070ee5431ebefd36bb58 --- audio/aidl/default/Module.cpp | 34 +++++++++++-------- audio/aidl/default/include/core-impl/Module.h | 2 ++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 12bbbb0cba..5478633d02 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -286,22 +286,28 @@ std::set Module::portIdsFromPortConfigIds(C portConfigIds) { return result; } +std::unique_ptr Module::initializeConfig() { + std::unique_ptr config; + switch (getType()) { + case Type::DEFAULT: + config = std::move(internal::getPrimaryConfiguration()); + break; + case Type::R_SUBMIX: + config = std::move(internal::getRSubmixConfiguration()); + break; + case Type::STUB: + config = std::move(internal::getStubConfiguration()); + break; + case Type::USB: + config = std::move(internal::getUsbConfiguration()); + break; + } + return config; +} + internal::Configuration& Module::getConfig() { if (!mConfig) { - switch (mType) { - case Type::DEFAULT: - mConfig = std::move(internal::getPrimaryConfiguration()); - break; - case Type::R_SUBMIX: - mConfig = std::move(internal::getRSubmixConfiguration()); - break; - case Type::STUB: - mConfig = std::move(internal::getStubConfiguration()); - break; - case Type::USB: - mConfig = std::move(internal::getUsbConfiguration()); - break; - } + mConfig = std::move(initializeConfig()); } return *mConfig; } diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index ee0458be49..294cc0e7b9 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -182,6 +182,7 @@ class Module : public BnModule { const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected); virtual ndk::ScopedAStatus onMasterMuteChanged(bool mute); virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume); + virtual std::unique_ptr initializeConfig(); // Utility and helper functions accessible to subclasses. void cleanUpPatch(int32_t patchId); @@ -202,6 +203,7 @@ class Module : public BnModule { bool getMicMute() const { return mMicMute; } const Patches& getPatches() const { return mPatches; } const Streams& getStreams() const { return mStreams; } + Type getType() const { return mType; } bool isMmapSupported(); template std::set portIdsFromPortConfigIds(C portConfigIds); From 53c69987b8a7b36e774845179ccfa7dafbddd4bc Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 18 Jul 2023 14:46:18 -0700 Subject: [PATCH 072/152] audio: Fix state machine initial and final state symbols In UML, the initial state is a solid circle, the final state is a double circle. In the Core HAL diagrams it was the opposite. Test: dot -Tpng stream-{in|out}-[async-]sm.gv -o ... Change-Id: Id69f17d0a47227e744eb6dadcb5fee08c07bb0bd (cherry picked from commit f082902b41cb9151e0336c78550f11e6959d512e) Merged-In: Id69f17d0a47227e744eb6dadcb5fee08c07bb0bd --- audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv | 4 ++-- audio/aidl/android/hardware/audio/core/stream-in-sm.gv | 4 ++-- audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv | 4 ++-- audio/aidl/android/hardware/audio/core/stream-out-sm.gv | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv index 818b18eda7..6b69845f40 100644 --- a/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv +++ b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv @@ -14,8 +14,8 @@ // To render: dot -Tpng stream-in-async-sm.gv -o stream-in-async-sm.png digraph stream_in_async_state_machine { - node [shape=doublecircle style=filled fillcolor=black width=0.5] I; - node [shape=point width=0.5] F; + node [shape=point style=filled fillcolor=black width=0.5] I; + node [shape=doublecircle width=0.5] F; node [shape=oval width=1]; node [fillcolor=lightgreen] STANDBY; // buffer is empty node [fillcolor=tomato] CLOSED; diff --git a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv index 805dc3267c..aa7af54fcf 100644 --- a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv +++ b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv @@ -14,8 +14,8 @@ // To render: dot -Tpng stream-in-sm.gv -o stream-in-sm.png digraph stream_in_state_machine { - node [shape=doublecircle style=filled fillcolor=black width=0.5] I; - node [shape=point width=0.5] F; + node [shape=point style=filled fillcolor=black width=0.5] I; + node [shape=doublecircle width=0.5] F; node [shape=oval width=1]; node [fillcolor=lightgreen] STANDBY; // buffer is empty node [fillcolor=tomato] CLOSED; diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv index 501dc0169d..a3f0de9e59 100644 --- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv +++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv @@ -14,8 +14,8 @@ // To render: dot -Tpng stream-out-async-sm.gv -o stream-out-async-sm.png digraph stream_out_async_state_machine { - node [shape=doublecircle style=filled fillcolor=black width=0.5] I; - node [shape=point width=0.5] F; + node [shape=point style=filled fillcolor=black width=0.5] I; + node [shape=doublecircle width=0.5] F; node [shape=oval width=1]; node [fillcolor=lightgreen] STANDBY; // buffer is empty node [fillcolor=lightgreen] IDLE; // buffer is empty diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv index 47e7fda568..23fb5d9cde 100644 --- a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv +++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv @@ -14,8 +14,8 @@ // To render: dot -Tpng stream-out-sm.gv -o stream-out-sm.png digraph stream_out_state_machine { - node [shape=doublecircle style=filled fillcolor=black width=0.5] I; - node [shape=point width=0.5] F; + node [shape=point style=filled fillcolor=black width=0.5] I; + node [shape=doublecircle width=0.5] F; node [shape=oval width=1]; node [fillcolor=lightgreen] STANDBY; // buffer is empty node [fillcolor=lightgreen] IDLE; // buffer is empty From 50f2065706dc053acfc8598582099fb393944d29 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Wed, 19 Jul 2023 16:43:50 +0530 Subject: [PATCH 073/152] Audio : Fix minor comments in r_submix module Add missing check for StandbyTransition variable Add missing & in const arguments Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Change-Id: Id7a30e0697da80a272768bbf2aa8e3ed748e93f4 (cherry picked from commit 7770c158a13509442295a504586a0e6b9c2eb58e) Merged-In: Id7a30e0697da80a272768bbf2aa8e3ed748e93f4 --- audio/aidl/default/r_submix/SubmixRoute.cpp | 10 +++++----- audio/aidl/default/r_submix/SubmixRoute.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp index 8f5b8cb4e0..ddac64d387 100644 --- a/audio/aidl/default/r_submix/SubmixRoute.cpp +++ b/audio/aidl/default/r_submix/SubmixRoute.cpp @@ -27,7 +27,7 @@ using aidl::android::hardware::audio::common::getChannelCount; namespace aidl::android::hardware::audio::core::r_submix { // Verify a submix input or output stream can be opened. -bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig streamConfig) { +bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig& streamConfig) { // If the stream is already open, don't open it again. // ENABLE_LEGACY_INPUT_OPEN is default behaviour if (!isInput && isStreamOutOpen()) { @@ -43,7 +43,7 @@ bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig streamConf // Compare this stream config with existing pipe config, returning false if they do *not* // match, true otherwise. -bool SubmixRoute::isStreamConfigCompatible(const AudioConfig streamConfig) { +bool SubmixRoute::isStreamConfigCompatible(const AudioConfig& streamConfig) { if (streamConfig.channelLayout != mPipeConfig.channelLayout) { LOG(ERROR) << __func__ << ": channel count mismatch, stream channels = " << streamConfig.channelLayout.toString() @@ -126,7 +126,7 @@ void SubmixRoute::closeStream(bool isInput) { // If SubmixRoute doesn't exist for a port, create a pipe for the submix audio device of size // buffer_size_frames and store config of the submix audio device. -::android::status_t SubmixRoute::createPipe(const AudioConfig streamConfig) { +::android::status_t SubmixRoute::createPipe(const AudioConfig& streamConfig) { const int channelCount = getChannelCount(streamConfig.channelLayout); const audio_format_t audioFormat = VALUE_OR_RETURN_STATUS( aidl2legacy_AudioFormatDescription_audio_format_t(streamConfig.format)); @@ -201,9 +201,9 @@ void SubmixRoute::standby(bool isInput) { if (isInput) { mStreamInStandby = true; - } else { + } else if (!mStreamOutStandby) { mStreamOutStandby = true; - mStreamOutStandbyTransition = !mStreamOutStandbyTransition; + mStreamOutStandbyTransition = true; } } diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h index 5f7ea75934..1a98df2340 100644 --- a/audio/aidl/default/r_submix/SubmixRoute.h +++ b/audio/aidl/default/r_submix/SubmixRoute.h @@ -93,9 +93,9 @@ class SubmixRoute { return mSource; } - bool isStreamConfigValid(bool isInput, const AudioConfig streamConfig); + bool isStreamConfigValid(bool isInput, const AudioConfig& streamConfig); void closeStream(bool isInput); - ::android::status_t createPipe(const AudioConfig streamConfig); + ::android::status_t createPipe(const AudioConfig& streamConfig); void exitStandby(bool isInput); bool hasAtleastOneStreamOpen(); int notifyReadError(); @@ -107,7 +107,7 @@ class SubmixRoute { long updateReadCounterFrames(size_t frameCount); private: - bool isStreamConfigCompatible(const AudioConfig streamConfig); + bool isStreamConfigCompatible(const AudioConfig& streamConfig); std::mutex mLock; From d21b0e7e559073df7fa4bc08a1fd3e034212c77d Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 13 Jul 2023 15:25:36 -0700 Subject: [PATCH 074/152] audio: Simplify and extend alsa::Mixer Remove alsa::MixerControl. tinyALSA contains utility functions for setting values in percents, they use the same logic as used to be there for handling the "volume" control. Use access serialization at the mixer level, rather than for each control. Move the call to 'mixer_open' to alsa::Mixer. Add controls for capture (mic) mute and gain. They will be used by the primary HAL. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Change-Id: I0fad994153de96aceec3eb8f2fec19805ec912f8 (cherry picked from commit f12d4a1ef804f4c382e6bfcef545f37ebbff6a2e) Merged-In: I0fad994153de96aceec3eb8f2fec19805ec912f8 --- audio/aidl/default/alsa/Mixer.cpp | 207 +++++++++++------- audio/aidl/default/alsa/Mixer.h | 51 +++-- .../aidl/default/usb/UsbAlsaMixerControl.cpp | 6 +- 3 files changed, 153 insertions(+), 111 deletions(-) diff --git a/audio/aidl/default/alsa/Mixer.cpp b/audio/aidl/default/alsa/Mixer.cpp index f0393e3a7e..126c033f66 100644 --- a/audio/aidl/default/alsa/Mixer.cpp +++ b/audio/aidl/default/alsa/Mixer.cpp @@ -14,44 +14,17 @@ * limitations under the License. */ -#define LOG_TAG "AHAL_AlsaMixer" -#include - +#include #include +#define LOG_TAG "AHAL_AlsaMixer" +#include #include #include "Mixer.h" namespace aidl::android::hardware::audio::core::alsa { -//----------------------------------------------------------------------------- - -MixerControl::MixerControl(struct mixer_ctl* ctl) - : mCtl(ctl), - mNumValues(mixer_ctl_get_num_values(ctl)), - mMinValue(mixer_ctl_get_range_min(ctl)), - mMaxValue(mixer_ctl_get_range_max(ctl)) {} - -unsigned int MixerControl::getNumValues() const { - return mNumValues; -} - -int MixerControl::getMaxValue() const { - return mMaxValue; -} - -int MixerControl::getMinValue() const { - return mMinValue; -} - -int MixerControl::setArray(const void* array, size_t count) { - const std::lock_guard guard(mLock); - return mixer_ctl_set_array(mCtl, array, count); -} - -//----------------------------------------------------------------------------- - // static const std::map> Mixer::kPossibleControls = { @@ -60,18 +33,20 @@ const std::map> Mixer::initializeMixerControls( - struct mixer* mixer) { - std::map> mixerControls; +Mixer::Controls Mixer::initializeMixerControls(struct mixer* mixer) { + if (mixer == nullptr) return {}; + Controls mixerControls; std::string mixerCtlNames; for (const auto& [control, possibleCtls] : kPossibleControls) { for (const auto& [ctlName, expectedCtlType] : possibleCtls) { struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str()); if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) { - mixerControls.emplace(control, std::make_unique(ctl)); + mixerControls.emplace(control, ctl); if (!mixerCtlNames.empty()) { mixerCtlNames += ","; } @@ -84,71 +59,141 @@ std::map> Mixer::initializeMixerCo return mixerControls; } -Mixer::Mixer(struct mixer* mixer) - : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {} +std::ostream& operator<<(std::ostream& s, Mixer::Control c) { + switch (c) { + case Mixer::Control::MASTER_SWITCH: + s << "master mute"; + break; + case Mixer::Control::MASTER_VOLUME: + s << "master volume"; + break; + case Mixer::Control::HW_VOLUME: + s << "volume"; + break; + case Mixer::Control::MIC_SWITCH: + s << "mic mute"; + break; + case Mixer::Control::MIC_GAIN: + s << "mic gain"; + break; + } + return s; +} + +Mixer::Mixer(int card) : mMixer(mixer_open(card)), mMixerControls(initializeMixerControls(mMixer)) { + if (!isValid()) { + PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card; + } +} Mixer::~Mixer() { - mixer_close(mMixer); + if (isValid()) { + std::lock_guard l(mMixerAccess); + mixer_close(mMixer); + } } -namespace { - -int volumeFloatToInteger(float fValue, int maxValue, int minValue) { - return minValue + std::ceil((maxValue - minValue) * fValue); -} - -} // namespace - ndk::ScopedAStatus Mixer::setMasterMute(bool muted) { - auto it = mMixerControls.find(Mixer::MASTER_SWITCH); - if (it == mMixerControls.end()) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - const int numValues = it->second->getNumValues(); - std::vector values(numValues, muted ? 0 : 1); - if (int err = it->second->setArray(values.data(), numValues); err != 0) { - LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - return ndk::ScopedAStatus::ok(); + return setMixerControlMute(MASTER_SWITCH, muted); } ndk::ScopedAStatus Mixer::setMasterVolume(float volume) { - auto it = mMixerControls.find(Mixer::MASTER_VOLUME); - if (it == mMixerControls.end()) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - const int numValues = it->second->getNumValues(); - std::vector values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(), - it->second->getMinValue())); - if (int err = it->second->setArray(values.data(), numValues); err != 0) { - LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - return ndk::ScopedAStatus::ok(); + return setMixerControlVolume(MASTER_VOLUME, volume); +} + +ndk::ScopedAStatus Mixer::setMicGain(float gain) { + return setMixerControlVolume(MIC_GAIN, gain); +} + +ndk::ScopedAStatus Mixer::setMicMute(bool muted) { + return setMixerControlMute(MIC_SWITCH, muted); } ndk::ScopedAStatus Mixer::setVolumes(const std::vector& volumes) { + if (!isValid()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } auto it = mMixerControls.find(Mixer::HW_VOLUME); if (it == mMixerControls.end()) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } - const int numValues = it->second->getNumValues(); - if (numValues < 0) { - LOG(FATAL) << __func__ << ": negative number of values: " << numValues; - } - const int maxValue = it->second->getMaxValue(); - const int minValue = it->second->getMinValue(); - std::vector values; - size_t i = 0; - for (; i < static_cast(numValues) && i < values.size(); ++i) { - values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue)); - } - if (int err = it->second->setArray(values.data(), values.size()); err != 0) { + std::vector percents; + std::transform( + volumes.begin(), volumes.end(), std::back_inserter(percents), + [](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); }); + std::lock_guard l(mMixerAccess); + if (int err = setMixerControlPercent(it->second, percents); err != 0) { LOG(ERROR) << __func__ << ": failed to set volume, err=" << err; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) { + if (!isValid()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + auto it = mMixerControls.find(ctl); + if (it == mMixerControls.end()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + std::lock_guard l(mMixerAccess); + if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) { + LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) { + if (!isValid()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + auto it = mMixerControls.find(ctl); + if (it == mMixerControls.end()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + volume = std::clamp(volume, 0.0f, 1.0f); + std::lock_guard l(mMixerAccess); + if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) { + LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + return ndk::ScopedAStatus::ok(); +} + +int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) { + int ret = 0; + const unsigned int n = mixer_ctl_get_num_values(ctl); + for (unsigned int id = 0; id < n; id++) { + if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) { + ret = error; + } + } + return ret; +} + +int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector& percents) { + int ret = 0; + const unsigned int n = mixer_ctl_get_num_values(ctl); + for (unsigned int id = 0; id < n; id++) { + if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0); + error != 0) { + ret = error; + } + } + return ret; +} + +int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) { + int ret = 0; + const unsigned int n = mixer_ctl_get_num_values(ctl); + for (unsigned int id = 0; id < n; id++) { + if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) { + ret = error; + } + } + return ret; +} + } // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h index de9e6f42cd..78728c296e 100644 --- a/audio/aidl/default/alsa/Mixer.h +++ b/audio/aidl/default/alsa/Mixer.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -31,34 +32,17 @@ extern "C" { namespace aidl::android::hardware::audio::core::alsa { -class MixerControl { - public: - explicit MixerControl(struct mixer_ctl* ctl); - - unsigned int getNumValues() const; - int getMaxValue() const; - int getMinValue() const; - int setArray(const void* array, size_t count); - - private: - std::mutex mLock; - // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed. - struct mixer_ctl* mCtl GUARDED_BY(mLock); - const unsigned int mNumValues; - const int mMinValue; - const int mMaxValue; -}; - class Mixer { public: - explicit Mixer(struct mixer* mixer); - + explicit Mixer(int card); ~Mixer(); bool isValid() const { return mMixer != nullptr; } ndk::ScopedAStatus setMasterMute(bool muted); ndk::ScopedAStatus setMasterVolume(float volume); + ndk::ScopedAStatus setMicGain(float gain); + ndk::ScopedAStatus setMicMute(bool muted); ndk::ScopedAStatus setVolumes(const std::vector& volumes); private: @@ -66,17 +50,32 @@ class Mixer { MASTER_SWITCH, MASTER_VOLUME, HW_VOLUME, + MIC_SWITCH, + MIC_GAIN, }; using ControlNamesAndExpectedCtlType = std::pair; - static const std::map> kPossibleControls; - static std::map> initializeMixerControls( - struct mixer* mixer); + using Controls = std::map; + friend std::ostream& operator<<(std::ostream&, Control); + static const std::map> kPossibleControls; + static Controls initializeMixerControls(struct mixer* mixer); + + ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted); + ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume); + + int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess); + int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector& percents) + REQUIRES(mMixerAccess); + int setMixerControlValue(struct mixer_ctl* ctl, int value) REQUIRES(mMixerAccess); + + // Since ALSA functions do not use internal locking, enforce thread safety at our level. + std::mutex mMixerAccess; // The mixer object is owned by ALSA and will be released when the mixer is closed. - struct mixer* mMixer; + struct mixer* const mMixer; // `mMixerControls` will only be initialized in constructor. After that, it wil only be - // read but not be modified. - const std::map> mMixerControls; + // read but not be modified. Each mixer_ctl object is owned by ALSA, it's life span is + // the same as of the mixer itself. + const Controls mMixerControls; }; } // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp index 769d739969..0a49446e5a 100644 --- a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp +++ b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp @@ -33,12 +33,10 @@ void UsbAlsaMixerControl::setDeviceConnectionState(int card, bool masterMuted, f bool connected) { LOG(DEBUG) << __func__ << ": card=" << card << ", connected=" << connected; if (connected) { - struct mixer* mixer = mixer_open(card); - if (mixer == nullptr) { - PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card; + auto alsaMixer = std::make_shared(card); + if (!alsaMixer->isValid()) { return; } - auto alsaMixer = std::make_shared(mixer); alsaMixer->setMasterMute(masterMuted); alsaMixer->setMasterVolume(masterVolume); const std::lock_guard guard(mLock); From ee8417a4aba2d347a9b5e1af2c3176a3d8843aaa Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 13 Jul 2023 16:32:08 -0700 Subject: [PATCH 075/152] audio: Update StreamAlsa and alsa utils for built-in devices Use new functions added to alsa proxy layer for opening attached (built-in) devices. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Change-Id: Ia2a47ff96fa62f99ce4ec4a0993ca3fd86f82c9d (cherry picked from commit 422f7e6b1b36359e5dd1492b17d29afbbe546c87) Merged-In: Ia2a47ff96fa62f99ce4ec4a0993ca3fd86f82c9d --- audio/aidl/default/Stream.cpp | 12 +++- audio/aidl/default/alsa/StreamAlsa.cpp | 59 +++++++++++-------- audio/aidl/default/alsa/Utils.cpp | 54 ++++++++++++++++- audio/aidl/default/alsa/Utils.h | 5 ++ audio/aidl/default/include/core-impl/Stream.h | 1 + .../default/include/core-impl/StreamAlsa.h | 6 +- .../default/include/core-impl/StreamUsb.h | 3 - audio/aidl/default/usb/StreamUsb.cpp | 17 +----- 8 files changed, 109 insertions(+), 48 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 215de94a31..470b65b749 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -47,13 +47,19 @@ void StreamContext::fillDescriptor(StreamDescriptor* desc) { desc->reply = mReplyMQ->dupeDesc(); } if (mDataMQ) { - const size_t frameSize = getFrameSize(); - desc->frameSizeBytes = frameSize; - desc->bufferSizeFrames = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / frameSize; + desc->frameSizeBytes = getFrameSize(); + desc->bufferSizeFrames = getBufferSizeInFrames(); desc->audio.set(mDataMQ->dupeDesc()); } } +size_t StreamContext::getBufferSizeInFrames() const { + if (mDataMQ) { + return mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / getFrameSize(); + } + return 0; +} + size_t StreamContext::getFrameSize() const { return getFrameSizeInBytes(mFormat, mChannelLayout); } diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp index 17c7febdd1..bdbe5733b9 100644 --- a/audio/aidl/default/alsa/StreamAlsa.cpp +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -27,16 +27,32 @@ namespace aidl::android::hardware::audio::core { -StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context) +StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context, int readWriteRetries) : StreamCommonImpl(metadata, std::move(context)), mFrameSizeBytes(getContext().getFrameSize()), mIsInput(isInput(metadata)), - mConfig(alsa::getPcmConfig(getContext(), mIsInput)) {} + mConfig(alsa::getPcmConfig(getContext(), mIsInput)), + mReadWriteRetries(readWriteRetries) {} ::android::status_t StreamAlsa::init() { return mConfig.has_value() ? ::android::OK : ::android::NO_INIT; } +::android::status_t StreamAlsa::drain(StreamDescriptor::DrainMode) { + usleep(1000); + return ::android::OK; +} + +::android::status_t StreamAlsa::flush() { + usleep(1000); + return ::android::OK; +} + +::android::status_t StreamAlsa::pause() { + usleep(1000); + return ::android::OK; +} + ::android::status_t StreamAlsa::standby() { mAlsaDeviceProxies.clear(); return ::android::OK; @@ -45,27 +61,21 @@ StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context) ::android::status_t StreamAlsa::start() { decltype(mAlsaDeviceProxies) alsaDeviceProxies; for (const auto& device : getDeviceProfiles()) { - auto profile = alsa::readAlsaDeviceInfo(device); - if (!profile.has_value()) { - LOG(ERROR) << __func__ << ": unable to read device info, device address=" << device; - return ::android::UNKNOWN_ERROR; + alsa::DeviceProxy proxy; + if (device.isExternal) { + // Always ask alsa configure as required since the configuration should be supported + // by the connected device. That is guaranteed by `setAudioPortConfig` and + // `setAudioPatch`. + proxy = alsa::openProxyForExternalDevice( + device, const_cast(&mConfig.value()), + true /*require_exact_match*/); + } else { + proxy = alsa::openProxyForAttachedDevice( + device, const_cast(&mConfig.value()), + getContext().getBufferSizeInFrames()); } - - auto proxy = alsa::makeDeviceProxy(); - // Always ask for alsa configure as required since the configuration should be supported - // by the connected device. That is guaranteed by `setAudioPortConfig` and `setAudioPatch`. - if (int err = proxy_prepare(proxy.get(), &profile.value(), - const_cast(&mConfig.value()), - true /*require_exact_match*/); - err != 0) { - LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device - << " error=" << err; - return ::android::UNKNOWN_ERROR; - } - if (int err = proxy_open(proxy.get()); err != 0) { - LOG(ERROR) << __func__ << ": failed to open device, address=" << device - << " error=" << err; - return ::android::UNKNOWN_ERROR; + if (!proxy) { + return ::android::NO_INIT; } alsaDeviceProxies.push_back(std::move(proxy)); } @@ -83,11 +93,12 @@ StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context) return ::android::NO_INIT; } // For input case, only support single device. - proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer); + proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer, + mReadWriteRetries); maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get()); } else { for (auto& proxy : mAlsaDeviceProxies) { - proxy_write(proxy.get(), buffer, bytesToTransfer); + proxy_write_with_retries(proxy.get(), buffer, bytesToTransfer, mReadWriteRetries); maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get())); } } diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp index 162f8529cf..20f77978fd 100644 --- a/audio/aidl/default/alsa/Utils.cpp +++ b/audio/aidl/default/alsa/Utils.cpp @@ -217,7 +217,8 @@ std::optional getDeviceProfile( } return DeviceProfile{.card = alsaAddress[0], .device = alsaAddress[1], - .direction = isInput ? PCM_IN : PCM_OUT}; + .direction = isInput ? PCM_IN : PCM_OUT, + .isExternal = !audioDevice.type.connection.empty()}; } std::optional getDeviceProfile( @@ -269,6 +270,57 @@ DeviceProxy makeDeviceProxy() { }); } +DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile, + struct pcm_config* pcmConfig, size_t bufferFrameCount) { + if (deviceProfile.isExternal) { + LOG(FATAL) << __func__ << ": called for an external device, address=" << deviceProfile; + } + alsa_device_profile profile; + profile_init(&profile, deviceProfile.direction); + profile.card = deviceProfile.card; + profile.device = deviceProfile.device; + if (!profile_fill_builtin_device_info(&profile, pcmConfig, bufferFrameCount)) { + LOG(FATAL) << __func__ << ": failed to init for built-in device, address=" << deviceProfile; + } + auto proxy = makeDeviceProxy(); + if (int err = proxy_prepare_from_default_config(proxy.get(), &profile); err != 0) { + LOG(FATAL) << __func__ << ": fail to prepare for device address=" << deviceProfile + << " error=" << err; + return nullptr; + } + if (int err = proxy_open(proxy.get()); err != 0) { + LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile + << " error=" << err; + return nullptr; + } + return proxy; +} + +DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile, + struct pcm_config* pcmConfig, bool requireExactMatch) { + if (!deviceProfile.isExternal) { + LOG(FATAL) << __func__ << ": called for an attached device, address=" << deviceProfile; + } + auto profile = readAlsaDeviceInfo(deviceProfile); + if (!profile.has_value()) { + LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile; + return nullptr; + } + auto proxy = makeDeviceProxy(); + if (int err = proxy_prepare(proxy.get(), &profile.value(), pcmConfig, requireExactMatch); + err != 0) { + LOG(ERROR) << __func__ << ": fail to prepare for device address=" << deviceProfile + << " error=" << err; + return nullptr; + } + if (int err = proxy_open(proxy.get()); err != 0) { + LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile + << " error=" << err; + return nullptr; + } + return proxy; +} + std::optional readAlsaDeviceInfo(const DeviceProfile& deviceProfile) { alsa_device_profile profile; profile_init(&profile, deviceProfile.direction); diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h index c1b9b380c0..615e657064 100644 --- a/audio/aidl/default/alsa/Utils.h +++ b/audio/aidl/default/alsa/Utils.h @@ -40,6 +40,7 @@ struct DeviceProfile { int card; int device; int direction; /* PCM_OUT or PCM_IN */ + bool isExternal; }; std::ostream& operator<<(std::ostream& os, const DeviceProfile& device); using DeviceProxyDeleter = std::function; @@ -60,6 +61,10 @@ std::optional getDeviceProfile( std::optional getPcmConfig(const StreamContext& context, bool isInput); std::vector getSampleRatesFromProfile(const alsa_device_profile* profile); DeviceProxy makeDeviceProxy(); +DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile, + struct pcm_config* pcmConfig, size_t bufferFrameCount); +DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile, + struct pcm_config* pcmConfig, bool requireExactMatch); std::optional readAlsaDeviceInfo(const DeviceProfile& deviceProfile); ::aidl::android::media::audio::common::AudioFormatDescription diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index e64c578b68..a1bc9b4b85 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -132,6 +132,7 @@ class StreamContext { void fillDescriptor(StreamDescriptor* desc); std::shared_ptr getAsyncCallback() const { return mAsyncCallback; } + size_t getBufferSizeInFrames() const; ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const { return mChannelLayout; } diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h index 5744d665f3..700573f1da 100644 --- a/audio/aidl/default/include/core-impl/StreamAlsa.h +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -31,9 +31,12 @@ namespace aidl::android::hardware::audio::core { // provide necessary overrides for all interface methods omitted here. class StreamAlsa : public StreamCommonImpl { public: - StreamAlsa(const Metadata& metadata, StreamContext&& context); + StreamAlsa(const Metadata& metadata, StreamContext&& context, int readWriteRetries); // Methods of 'DriverInterface'. ::android::status_t init() override; + ::android::status_t drain(StreamDescriptor::DrainMode) override; + ::android::status_t flush() override; + ::android::status_t pause() override; ::android::status_t standby() override; ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, @@ -48,6 +51,7 @@ class StreamAlsa : public StreamCommonImpl { const size_t mFrameSizeBytes; const bool mIsInput; const std::optional mConfig; + const int mReadWriteRetries; // All fields below are only used on the worker thread. std::vector mAlsaDeviceProxies; }; diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 44f742a4dd..0189b6b7ed 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -30,9 +30,6 @@ class StreamUsb : public StreamAlsa { public: StreamUsb(const Metadata& metadata, StreamContext&& context); // Methods of 'DriverInterface'. - ::android::status_t drain(StreamDescriptor::DrainMode) override; - ::android::status_t flush() override; - ::android::status_t pause() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index da0ad11be2..f6642450c8 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -36,7 +36,7 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context) - : StreamAlsa(metadata, std::move(context)) {} + : StreamAlsa(metadata, std::move(context), 1 /*readWriteRetries*/) {} ndk::ScopedAStatus StreamUsb::setConnectedDevices( const std::vector& connectedDevices) { @@ -62,21 +62,6 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( return ndk::ScopedAStatus::ok(); } -::android::status_t StreamUsb::drain(StreamDescriptor::DrainMode) { - usleep(1000); - return ::android::OK; -} - -::android::status_t StreamUsb::flush() { - usleep(1000); - return ::android::OK; -} - -::android::status_t StreamUsb::pause() { - usleep(1000); - return ::android::OK; -} - ::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) { From 291712fd1948d8de1b0aaf015825e88e8091af7c Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 19 Jul 2023 14:28:47 -0700 Subject: [PATCH 076/152] audio: Use ChildInterface in StreamCommonImpl Replace the pair of 'shared_ptr<>, Binder' with the equivalent ChildInterface. Fix logging of returned sub-objects to print their Binder value instead of the local pointer. Bug: 264712385 Test: m Change-Id: I1350e7b3720c6244cd8527e1d021ee9577399291 (cherry picked from commit 2eabaf995ba70c296ea30df9f30f9a03bf2b3910) Merged-In: I1350e7b3720c6244cd8527e1d021ee9577399291 --- audio/aidl/default/ModulePrimary.cpp | 3 ++- audio/aidl/default/Stream.cpp | 6 ++---- audio/aidl/default/include/core-impl/Stream.h | 4 ++-- audio/aidl/default/stub/ModuleStub.cpp | 9 ++++++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp index cbb6730372..f66da373f9 100644 --- a/audio/aidl/default/ModulePrimary.cpp +++ b/audio/aidl/default/ModulePrimary.cpp @@ -38,7 +38,8 @@ ndk::ScopedAStatus ModulePrimary::getTelephony(std::shared_ptr* _aid mTelephony = ndk::SharedRefBase::make(); } *_aidl_return = mTelephony.getPtr(); - LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get(); + LOG(DEBUG) << __func__ + << ": returning instance of ITelephony: " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 470b65b749..b11edff8e4 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -603,18 +603,16 @@ StreamCommonImpl::~StreamCommonImpl() { ndk::ScopedAStatus StreamCommonImpl::initInstance( const std::shared_ptr& delegate) { mCommon = ndk::SharedRefBase::make(delegate); - mCommonBinder = mCommon->asBinder(); - AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); return mWorker->start() ? ndk::ScopedAStatus::ok() : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon( std::shared_ptr* _aidl_return) { - if (mCommon == nullptr) { + if (!mCommon) { LOG(FATAL) << __func__ << ": the common interface was not created"; } - *_aidl_return = mCommon; + *_aidl_return = mCommon.getPtr(); LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index a1bc9b4b85..b65efb26f2 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -43,6 +43,7 @@ #include #include +#include "core-impl/ChildInterface.h" #include "core-impl/utils.h" namespace aidl::android::hardware::audio::core { @@ -466,8 +467,7 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr Metadata mMetadata; StreamContext mContext; std::unique_ptr mWorker; - std::shared_ptr mCommon; - ndk::SpAIBinder mCommonBinder; + ChildInterface mCommon; ConnectedDevices mConnectedDevices; }; diff --git a/audio/aidl/default/stub/ModuleStub.cpp b/audio/aidl/default/stub/ModuleStub.cpp index a60075221d..72f2241c03 100644 --- a/audio/aidl/default/stub/ModuleStub.cpp +++ b/audio/aidl/default/stub/ModuleStub.cpp @@ -38,7 +38,8 @@ ndk::ScopedAStatus ModuleStub::getBluetooth(std::shared_ptr* _aidl_r mBluetooth = ndk::SharedRefBase::make(); } *_aidl_return = mBluetooth.getPtr(); - LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get(); + LOG(DEBUG) << __func__ + << ": returning instance of IBluetooth: " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); } @@ -47,7 +48,8 @@ ndk::ScopedAStatus ModuleStub::getBluetoothA2dp(std::shared_ptr* mBluetoothA2dp = ndk::SharedRefBase::make(); } *_aidl_return = mBluetoothA2dp.getPtr(); - LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get(); + LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " + << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); } @@ -56,7 +58,8 @@ ndk::ScopedAStatus ModuleStub::getBluetoothLe(std::shared_ptr* _ai mBluetoothLe = ndk::SharedRefBase::make(); } *_aidl_return = mBluetoothLe.getPtr(); - LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get(); + LOG(DEBUG) << __func__ + << ": returning instance of IBluetoothLe: " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); } From bff67d3e1245a3973d8a8b19164477456422bd7a Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 19 Jul 2023 17:30:06 -0700 Subject: [PATCH 077/152] audio: Move StreamContext ownership out from StreamCommonImpl Upcoming implementations of the streams of the primary module will need to change the underlying stream type depending on the current connected device. The stream context must persist, thus its life time must be bound to the IStreamIn/Out implementation. Move the StreamContext instance under ownership of StreamIn/Out. Add StreamCommonImpl::onClose so that the owner of the context may know when it is safe to reset it. Re-arrange the order of the arguments when creating a stream so that the context always comes first. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Change-Id: Iaf13d4bc3a53cbfc27264d3abd1f6c417ece3941 (cherry picked from commit 6ddefdbcdf24f28d3477f29adf0bd57d1be04195) Merged-In: Iaf13d4bc3a53cbfc27264d3abd1f6c417ece3941 --- audio/aidl/default/Module.cpp | 4 +-- audio/aidl/default/ModulePrimary.cpp | 10 +++--- audio/aidl/default/Stream.cpp | 18 +++++++--- audio/aidl/default/alsa/StreamAlsa.cpp | 4 +-- audio/aidl/default/include/core-impl/Module.h | 4 +-- .../default/include/core-impl/ModulePrimary.h | 4 +-- .../include/core-impl/ModuleRemoteSubmix.h | 4 +-- .../default/include/core-impl/ModuleStub.h | 4 +-- .../default/include/core-impl/ModuleUsb.h | 4 +-- audio/aidl/default/include/core-impl/Stream.h | 33 ++++++++++++------- .../default/include/core-impl/StreamAlsa.h | 2 +- .../include/core-impl/StreamRemoteSubmix.h | 14 +++++--- .../default/include/core-impl/StreamStub.h | 18 ++++++---- .../default/include/core-impl/StreamUsb.h | 14 ++++---- .../default/r_submix/ModuleRemoteSubmix.cpp | 8 ++--- .../default/r_submix/StreamRemoteSubmix.cpp | 18 +++++----- audio/aidl/default/stub/ModuleStub.cpp | 10 +++--- audio/aidl/default/stub/StreamStub.cpp | 12 +++---- audio/aidl/default/usb/ModuleUsb.cpp | 12 +++---- audio/aidl/default/usb/StreamUsb.cpp | 16 ++++----- 20 files changed, 122 insertions(+), 91 deletions(-) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 5478633d02..eb9cbc3445 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -675,7 +675,7 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar nullptr, nullptr, &context)); context.fillDescriptor(&_aidl_return->desc); std::shared_ptr stream; - RETURN_STATUS_IF_ERROR(createInputStream(in_args.sinkMetadata, std::move(context), + RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata, mConfig->microphones, &stream)); StreamWrapper streamWrapper(stream); if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) { @@ -721,7 +721,7 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_ in_args.eventCallback, &context)); context.fillDescriptor(&_aidl_return->desc); std::shared_ptr stream; - RETURN_STATUS_IF_ERROR(createOutputStream(in_args.sourceMetadata, std::move(context), + RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata, in_args.offloadInfo, &stream)); StreamWrapper streamWrapper(stream); if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) { diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp index f66da373f9..d8ea9e7731 100644 --- a/audio/aidl/default/ModulePrimary.cpp +++ b/audio/aidl/default/ModulePrimary.cpp @@ -43,18 +43,18 @@ ndk::ScopedAStatus ModulePrimary::getTelephony(std::shared_ptr* _aid return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus ModulePrimary::createInputStream(const SinkMetadata& sinkMetadata, - StreamContext&& context, +ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context, + const SinkMetadata& sinkMetadata, const std::vector& microphones, std::shared_ptr* result) { - return createStreamInstance(result, sinkMetadata, std::move(context), + return createStreamInstance(result, std::move(context), sinkMetadata, microphones); } ndk::ScopedAStatus ModulePrimary::createOutputStream( - const SourceMetadata& sourceMetadata, StreamContext&& context, + StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo, std::shared_ptr* result) { - return createStreamInstance(result, sourceMetadata, std::move(context), + return createStreamInstance(result, std::move(context), sourceMetadata, offloadInfo); } diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index b11edff8e4..f4194d23c1 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -663,7 +663,7 @@ ndk::ScopedAStatus StreamCommonImpl::close() { LOG(DEBUG) << __func__ << ": joining the worker thread..."; mWorker->stop(); LOG(DEBUG) << __func__ << ": worker thread joined"; - mContext.reset(); + onClose(); mWorker->setClosed(); return ndk::ScopedAStatus::ok(); } else { @@ -727,11 +727,15 @@ static std::map transformMicrophones( } } // namespace -StreamIn::StreamIn(const std::vector& microphones) - : mMicrophones(transformMicrophones(microphones)) { +StreamIn::StreamIn(StreamContext&& context, const std::vector& microphones) + : mContext(std::move(context)), mMicrophones(transformMicrophones(microphones)) { LOG(DEBUG) << __func__; } +void StreamIn::defaultOnClose() { + mContext.reset(); +} + ndk::ScopedAStatus StreamIn::getActiveMicrophones( std::vector* _aidl_return) { std::vector result; @@ -784,11 +788,15 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector& in_channelGains return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -StreamOut::StreamOut(const std::optional& offloadInfo) - : mOffloadInfo(offloadInfo) { +StreamOut::StreamOut(StreamContext&& context, const std::optional& offloadInfo) + : mContext(std::move(context)), mOffloadInfo(offloadInfo) { LOG(DEBUG) << __func__; } +void StreamOut::defaultOnClose() { + mContext.reset(); +} + ndk::ScopedAStatus StreamOut::updateOffloadMetadata( const AudioOffloadMetadata& in_offloadMetadata) { LOG(DEBUG) << __func__; diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp index bdbe5733b9..c7fb02248a 100644 --- a/audio/aidl/default/alsa/StreamAlsa.cpp +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -27,8 +27,8 @@ namespace aidl::android::hardware::audio::core { -StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context, int readWriteRetries) - : StreamCommonImpl(metadata, std::move(context)), +StreamAlsa::StreamAlsa(const StreamContext& context, const Metadata& metadata, int readWriteRetries) + : StreamCommonImpl(context, metadata), mFrameSizeBytes(getContext().getFrameSize()), mIsInput(isInput(metadata)), mConfig(alsa::getPcmConfig(getContext(), mIsInput)), diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index 294cc0e7b9..539221d5d2 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -159,13 +159,13 @@ class Module : public BnModule { // The following virtual functions are intended for vendor extension via inheritance. virtual ndk::ScopedAStatus createInputStream( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, std::shared_ptr* result) = 0; virtual ndk::ScopedAStatus createOutputStream( - const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo, std::shared_ptr* result) = 0; diff --git a/audio/aidl/default/include/core-impl/ModulePrimary.h b/audio/aidl/default/include/core-impl/ModulePrimary.h index bc808ab03d..6264237fe3 100644 --- a/audio/aidl/default/include/core-impl/ModulePrimary.h +++ b/audio/aidl/default/include/core-impl/ModulePrimary.h @@ -28,13 +28,13 @@ class ModulePrimary final : public Module { ndk::ScopedAStatus getTelephony(std::shared_ptr* _aidl_return) override; ndk::ScopedAStatus createInputStream( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, std::shared_ptr* result) override; ndk::ScopedAStatus createOutputStream( - const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo, std::shared_ptr* result) override; diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h index ccfcdd9462..e87be3d9d2 100644 --- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h @@ -33,13 +33,13 @@ class ModuleRemoteSubmix : public Module { // Module interfaces ndk::ScopedAStatus createInputStream( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, std::shared_ptr* result) override; ndk::ScopedAStatus createOutputStream( - const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo, std::shared_ptr* result) override; diff --git a/audio/aidl/default/include/core-impl/ModuleStub.h b/audio/aidl/default/include/core-impl/ModuleStub.h index 59c343f4b7..4f771611ab 100644 --- a/audio/aidl/default/include/core-impl/ModuleStub.h +++ b/audio/aidl/default/include/core-impl/ModuleStub.h @@ -30,13 +30,13 @@ class ModuleStub final : public Module { ndk::ScopedAStatus getBluetoothLe(std::shared_ptr* _aidl_return) override; ndk::ScopedAStatus createInputStream( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, std::shared_ptr* result) override; ndk::ScopedAStatus createOutputStream( - const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo, std::shared_ptr* result) override; diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h index e6b3e66e41..a296b8c042 100644 --- a/audio/aidl/default/include/core-impl/ModuleUsb.h +++ b/audio/aidl/default/include/core-impl/ModuleUsb.h @@ -33,13 +33,13 @@ class ModuleUsb final : public ModuleAlsa { // Module interfaces ndk::ScopedAStatus createInputStream( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, std::shared_ptr* result) override; ndk::ScopedAStatus createOutputStream( - const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo, std::shared_ptr* result) override; diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index b65efb26f2..355d3b4cb8 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -411,16 +411,17 @@ class StreamCommonDelegator : public BnStreamCommon { }; // The implementation of DriverInterface must be provided by each concrete stream implementation. +// Note that StreamCommonImpl does not own the context. This is to support swapping on the fly +// implementations of the stream while keeping the same IStreamIn/Out instance. It's that instance +// who must be owner of the context. class StreamCommonImpl : virtual public StreamCommonInterface, virtual public DriverInterface { public: - StreamCommonImpl(const Metadata& metadata, StreamContext&& context, + StreamCommonImpl(const StreamContext& context, const Metadata& metadata, const StreamWorkerInterface::CreateInstance& createWorker) - : mMetadata(metadata), - mContext(std::move(context)), - mWorker(createWorker(mContext, this)) {} - StreamCommonImpl(const Metadata& metadata, StreamContext&& context) + : mContext(context), mMetadata(metadata), mWorker(createWorker(mContext, this)) {} + StreamCommonImpl(const StreamContext& context, const Metadata& metadata) : StreamCommonImpl( - metadata, std::move(context), + context, metadata, isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {} ~StreamCommonImpl(); @@ -462,10 +463,11 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr }; } + virtual void onClose() = 0; void stopWorker(); + const StreamContext& mContext; Metadata mMetadata; - StreamContext mContext; std::unique_ptr mWorker; ChildInterface mCommon; ConnectedDevices mConnectedDevices; @@ -475,6 +477,8 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr // concrete input/output stream implementations. class StreamIn : virtual public StreamCommonInterface, public BnStreamIn { protected: + void defaultOnClose(); + ndk::ScopedAStatus getStreamCommon(std::shared_ptr* _aidl_return) override { return getStreamCommonCommon(_aidl_return); } @@ -494,14 +498,17 @@ class StreamIn : virtual public StreamCommonInterface, public BnStreamIn { friend class ndk::SharedRefBase; - explicit StreamIn( - const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + StreamIn(StreamContext&& context, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + StreamContext mContext; const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones; }; class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { protected: + void defaultOnClose(); + ndk::ScopedAStatus getStreamCommon(std::shared_ptr* _aidl_return) override { return getStreamCommonCommon(_aidl_return); } @@ -535,10 +542,12 @@ class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { friend class ndk::SharedRefBase; - explicit StreamOut(const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& - offloadInfo); + StreamOut(StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo); - std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo; + StreamContext mContext; + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo; std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata; }; diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h index 700573f1da..90d2e36df7 100644 --- a/audio/aidl/default/include/core-impl/StreamAlsa.h +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -31,7 +31,7 @@ namespace aidl::android::hardware::audio::core { // provide necessary overrides for all interface methods omitted here. class StreamAlsa : public StreamCommonImpl { public: - StreamAlsa(const Metadata& metadata, StreamContext&& context, int readWriteRetries); + StreamAlsa(const StreamContext& context, const Metadata& metadata, int readWriteRetries); // Methods of 'DriverInterface'. ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h index 1bca910995..4c984afff9 100644 --- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -29,7 +29,7 @@ using aidl::android::hardware::audio::core::r_submix::SubmixRoute; class StreamRemoteSubmix : public StreamCommonImpl { public: - StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context); + StreamRemoteSubmix(const StreamContext& context, const Metadata& metadata); ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; @@ -72,28 +72,32 @@ class StreamRemoteSubmix : public StreamCommonImpl { static constexpr int kReadAttemptSleepUs = 5000; }; -class StreamInRemoteSubmix final : public StreamRemoteSubmix, public StreamIn { +class StreamInRemoteSubmix final : public StreamIn, public StreamRemoteSubmix { public: friend class ndk::SharedRefBase; StreamInRemoteSubmix( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: + void onClose() override { defaultOnClose(); } ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; }; -class StreamOutRemoteSubmix final : public StreamRemoteSubmix, public StreamOut { +class StreamOutRemoteSubmix final : public StreamOut, public StreamRemoteSubmix { public: friend class ndk::SharedRefBase; StreamOutRemoteSubmix( - const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo); + + private: + void onClose() override { defaultOnClose(); } }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index 6b1b2ddc89..2a92deb07c 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -22,7 +22,7 @@ namespace aidl::android::hardware::audio::core { class StreamStub : public StreamCommonImpl { public: - StreamStub(const Metadata& metadata, StreamContext&& context); + StreamStub(const StreamContext& context, const Metadata& metadata); // Methods of 'DriverInterface'. ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; @@ -43,22 +43,28 @@ class StreamStub : public StreamCommonImpl { bool mIsStandby = true; // Used for validating the state machine logic. }; -class StreamInStub final : public StreamStub, public StreamIn { +class StreamInStub final : public StreamIn, public StreamStub { public: friend class ndk::SharedRefBase; StreamInStub( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + + private: + void onClose() override { defaultOnClose(); } }; -class StreamOutStub final : public StreamStub, public StreamOut { +class StreamOutStub final : public StreamOut, public StreamStub { public: friend class ndk::SharedRefBase; - StreamOutStub(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, - StreamContext&& context, + StreamOutStub(StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo); + + private: + void onClose() override { defaultOnClose(); } }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 0189b6b7ed..7dc7296399 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -28,7 +28,7 @@ namespace aidl::android::hardware::audio::core { class StreamUsb : public StreamAlsa { public: - StreamUsb(const Metadata& metadata, StreamContext&& context); + StreamUsb(const StreamContext& context, const Metadata& metadata); // Methods of 'DriverInterface'. ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; @@ -44,29 +44,31 @@ class StreamUsb : public StreamAlsa { std::atomic mConnectedDevicesUpdated = false; }; -class StreamInUsb final : public StreamUsb, public StreamIn { +class StreamInUsb final : public StreamIn, public StreamUsb { public: friend class ndk::SharedRefBase; StreamInUsb( - const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: + void onClose() override { defaultOnClose(); } ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; }; -class StreamOutUsb final : public StreamUsb, public StreamOut { +class StreamOutUsb final : public StreamOut, public StreamUsb { public: friend class ndk::SharedRefBase; - StreamOutUsb(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, - StreamContext&& context, + StreamOutUsb(StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo); private: + void onClose() override { defaultOnClose(); } ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp index 2b79f51117..9be783758d 100644 --- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp @@ -56,16 +56,16 @@ ndk::ScopedAStatus ModuleRemoteSubmix::setMicMute(bool in_mute __unused) { } ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream( - const SinkMetadata& sinkMetadata, StreamContext&& context, + StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones, std::shared_ptr* result) { - return createStreamInstance(result, sinkMetadata, std::move(context), + return createStreamInstance(result, std::move(context), sinkMetadata, microphones); } ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream( - const SourceMetadata& sourceMetadata, StreamContext&& context, + StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo, std::shared_ptr* result) { - return createStreamInstance(result, sourceMetadata, std::move(context), + return createStreamInstance(result, std::move(context), sourceMetadata, offloadInfo); } diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 6d5185b346..53d4aa61ab 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -29,8 +29,8 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -StreamRemoteSubmix::StreamRemoteSubmix(const Metadata& metadata, StreamContext&& context) - : StreamCommonImpl(metadata, std::move(context)), +StreamRemoteSubmix::StreamRemoteSubmix(const StreamContext& context, const Metadata& metadata) + : StreamCommonImpl(context, metadata), mPortId(context.getPortId()), mIsInput(isInput(metadata)) { mStreamConfig.frameSize = context.getFrameSize(); @@ -353,10 +353,11 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { return ::android::OK; } -StreamInRemoteSubmix::StreamInRemoteSubmix(const SinkMetadata& sinkMetadata, - StreamContext&& context, +StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context, + const SinkMetadata& sinkMetadata, const std::vector& microphones) - : StreamRemoteSubmix(sinkMetadata, std::move(context)), StreamIn(microphones) {} + : StreamIn(std::move(context), microphones), + StreamRemoteSubmix(StreamIn::mContext, sinkMetadata) {} ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones( std::vector* _aidl_return) { @@ -365,9 +366,10 @@ ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones( return ndk::ScopedAStatus::ok(); } -StreamOutRemoteSubmix::StreamOutRemoteSubmix(const SourceMetadata& sourceMetadata, - StreamContext&& context, +StreamOutRemoteSubmix::StreamOutRemoteSubmix(StreamContext&& context, + const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) - : StreamRemoteSubmix(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {} + : StreamOut(std::move(context), offloadInfo), + StreamRemoteSubmix(StreamOut::mContext, sourceMetadata) {} } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/stub/ModuleStub.cpp b/audio/aidl/default/stub/ModuleStub.cpp index 72f2241c03..5e4cd88ff6 100644 --- a/audio/aidl/default/stub/ModuleStub.cpp +++ b/audio/aidl/default/stub/ModuleStub.cpp @@ -63,18 +63,18 @@ ndk::ScopedAStatus ModuleStub::getBluetoothLe(std::shared_ptr* _ai return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus ModuleStub::createInputStream(const SinkMetadata& sinkMetadata, - StreamContext&& context, +ndk::ScopedAStatus ModuleStub::createInputStream(StreamContext&& context, + const SinkMetadata& sinkMetadata, const std::vector& microphones, std::shared_ptr* result) { - return createStreamInstance(result, sinkMetadata, std::move(context), + return createStreamInstance(result, std::move(context), sinkMetadata, microphones); } ndk::ScopedAStatus ModuleStub::createOutputStream( - const SourceMetadata& sourceMetadata, StreamContext&& context, + StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo, std::shared_ptr* result) { - return createStreamInstance(result, sourceMetadata, std::move(context), + return createStreamInstance(result, std::move(context), sourceMetadata, offloadInfo); } diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp index 2dcf4d4d42..e916fea0fd 100644 --- a/audio/aidl/default/stub/StreamStub.cpp +++ b/audio/aidl/default/stub/StreamStub.cpp @@ -31,8 +31,8 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context) - : StreamCommonImpl(metadata, std::move(context)), +StreamStub::StreamStub(const StreamContext& context, const Metadata& metadata) + : StreamCommonImpl(context, metadata), mFrameSizeBytes(getContext().getFrameSize()), mSampleRate(getContext().getSampleRate()), mIsAsynchronous(!!getContext().getAsyncCallback()), @@ -118,12 +118,12 @@ void StreamStub::shutdown() { mIsInitialized = false; } -StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context, +StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) - : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {} + : StreamIn(std::move(context), microphones), StreamStub(StreamIn::mContext, sinkMetadata) {} -StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context, +StreamOutStub::StreamOutStub(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) - : StreamStub(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {} + : StreamOut(std::move(context), offloadInfo), StreamStub(StreamOut::mContext, sourceMetadata) {} } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp index a812e4d3a1..f926e09399 100644 --- a/audio/aidl/default/usb/ModuleUsb.cpp +++ b/audio/aidl/default/usb/ModuleUsb.cpp @@ -68,22 +68,22 @@ ndk::ScopedAStatus ModuleUsb::setMicMute(bool in_mute __unused) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -ndk::ScopedAStatus ModuleUsb::createInputStream(const SinkMetadata& sinkMetadata, - StreamContext&& context, +ndk::ScopedAStatus ModuleUsb::createInputStream(StreamContext&& context, + const SinkMetadata& sinkMetadata, const std::vector& microphones, std::shared_ptr* result) { - return createStreamInstance(result, sinkMetadata, std::move(context), microphones); + return createStreamInstance(result, std::move(context), sinkMetadata, microphones); } -ndk::ScopedAStatus ModuleUsb::createOutputStream(const SourceMetadata& sourceMetadata, - StreamContext&& context, +ndk::ScopedAStatus ModuleUsb::createOutputStream(StreamContext&& context, + const SourceMetadata& sourceMetadata, const std::optional& offloadInfo, std::shared_ptr* result) { if (offloadInfo.has_value()) { LOG(ERROR) << __func__ << ": offload is not supported"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } - return createStreamInstance(result, sourceMetadata, std::move(context), + return createStreamInstance(result, std::move(context), sourceMetadata, offloadInfo); } diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index f6642450c8..def12e094c 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -35,8 +35,8 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context) - : StreamAlsa(metadata, std::move(context), 1 /*readWriteRetries*/) {} +StreamUsb::StreamUsb(const StreamContext& context, const Metadata& metadata) + : StreamAlsa(context, metadata, 1 /*readWriteRetries*/) {} ndk::ScopedAStatus StreamUsb::setConnectedDevices( const std::vector& connectedDevices) { @@ -55,7 +55,7 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( } connectedDeviceProfiles.push_back(*profile); } - RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices)); + RETURN_STATUS_IF_ERROR(setConnectedDevices(connectedDevices)); std::lock_guard guard(mLock); mConnectedDeviceProfiles = std::move(connectedDeviceProfiles); mConnectedDevicesUpdated.store(true, std::memory_order_release); @@ -83,9 +83,9 @@ std::vector StreamUsb::getDeviceProfiles() { return connectedDevices; } -StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context, +StreamInUsb::StreamInUsb(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) - : StreamUsb(sinkMetadata, std::move(context)), StreamIn(microphones) {} + : StreamIn(std::move(context), microphones), StreamUsb(StreamIn::mContext, sinkMetadata) {} ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( std::vector* _aidl_return __unused) { @@ -93,10 +93,10 @@ ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context, +StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) - : StreamUsb(sourceMetadata, std::move(context)), - StreamOut(offloadInfo), + : StreamOut(std::move(context), offloadInfo), + StreamUsb(StreamOut::mContext, sourceMetadata), mChannelCount(getChannelCount(getContext().getChannelLayout())) {} ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { From 2e3b3e4c17c9bdb6d6c4a6bb52fa47a65cfc88e7 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 21 Jul 2023 17:01:38 -0700 Subject: [PATCH 078/152] audio: Update ChildInterface to set scheduler policy lazily Since the client may end up never retrieving the interface instance for sending it over Binder, postpone setting of the scheduler policy to until that very moment. Rename 'ChildInterface::getPtr' to 'getInstance' for clarity. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Change-Id: I31f9dd832c7f85f9632d1d389a8b1063d237d4c1 (cherry picked from commit 780fefb331e915d84e7f19176706740476152bb3) Merged-In: I31f9dd832c7f85f9632d1d389a8b1063d237d4c1 --- audio/aidl/default/Module.cpp | 2 +- audio/aidl/default/ModulePrimary.cpp | 2 +- audio/aidl/default/Stream.cpp | 2 +- .../aidl/default/include/core-impl/ChildInterface.h | 12 +++++++++--- audio/aidl/default/stub/ModuleStub.cpp | 6 +++--- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index eb9cbc3445..b59bd7c081 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -1129,7 +1129,7 @@ ndk::ScopedAStatus Module::getSoundDose(std::shared_ptr* _aidl_retur if (!mSoundDose) { mSoundDose = ndk::SharedRefBase::make(); } - *_aidl_return = mSoundDose.getPtr(); + *_aidl_return = mSoundDose.getInstance(); LOG(DEBUG) << __func__ << ": returning instance of ISoundDose: " << _aidl_return->get(); return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp index d8ea9e7731..29e81264ac 100644 --- a/audio/aidl/default/ModulePrimary.cpp +++ b/audio/aidl/default/ModulePrimary.cpp @@ -37,7 +37,7 @@ ndk::ScopedAStatus ModulePrimary::getTelephony(std::shared_ptr* _aid if (!mTelephony) { mTelephony = ndk::SharedRefBase::make(); } - *_aidl_return = mTelephony.getPtr(); + *_aidl_return = mTelephony.getInstance(); LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index f4194d23c1..032fa87a7f 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -612,7 +612,7 @@ ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon( if (!mCommon) { LOG(FATAL) << __func__ << ": the common interface was not created"; } - *_aidl_return = mCommon.getPtr(); + *_aidl_return = mCommon.getInstance(); LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/default/include/core-impl/ChildInterface.h b/audio/aidl/default/include/core-impl/ChildInterface.h index 1b31691556..2421b59a1a 100644 --- a/audio/aidl/default/include/core-impl/ChildInterface.h +++ b/audio/aidl/default/include/core-impl/ChildInterface.h @@ -35,14 +35,20 @@ struct ChildInterface : private std::pair, ndk::SpAIBinder> { } ChildInterface& operator=(std::shared_ptr&& c) { this->first = std::move(c); - this->second = this->first->asBinder(); - AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); return *this; } explicit operator bool() const { return !!this->first; } C& operator*() const { return *(this->first); } C* operator->() const { return this->first; } - std::shared_ptr getPtr() const { return this->first; } + // Use 'getInstance' when returning the interface instance. + std::shared_ptr getInstance() { + if (this->second.get() == nullptr) { + this->second = this->first->asBinder(); + AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL, + ANDROID_PRIORITY_AUDIO); + } + return this->first; + } }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/stub/ModuleStub.cpp b/audio/aidl/default/stub/ModuleStub.cpp index 5e4cd88ff6..9f6e0b47cb 100644 --- a/audio/aidl/default/stub/ModuleStub.cpp +++ b/audio/aidl/default/stub/ModuleStub.cpp @@ -37,7 +37,7 @@ ndk::ScopedAStatus ModuleStub::getBluetooth(std::shared_ptr* _aidl_r if (!mBluetooth) { mBluetooth = ndk::SharedRefBase::make(); } - *_aidl_return = mBluetooth.getPtr(); + *_aidl_return = mBluetooth.getInstance(); LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); @@ -47,7 +47,7 @@ ndk::ScopedAStatus ModuleStub::getBluetoothA2dp(std::shared_ptr* if (!mBluetoothA2dp) { mBluetoothA2dp = ndk::SharedRefBase::make(); } - *_aidl_return = mBluetoothA2dp.getPtr(); + *_aidl_return = mBluetoothA2dp.getInstance(); LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); @@ -57,7 +57,7 @@ ndk::ScopedAStatus ModuleStub::getBluetoothLe(std::shared_ptr* _ai if (!mBluetoothLe) { mBluetoothLe = ndk::SharedRefBase::make(); } - *_aidl_return = mBluetoothLe.getPtr(); + *_aidl_return = mBluetoothLe.getInstance(); LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get()->asBinder().get(); return ndk::ScopedAStatus::ok(); From a5e31540243fe76a6128f7a3162d034161a9d62c Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 21 Jul 2023 17:45:28 -0700 Subject: [PATCH 079/152] audio: Move frame counter to StreamContext Moving frame counter to the StreamContext class enables switching stream drivers on the fly while keeping the frame count monotonically increasing. StreamWorkerCommonLogic now holds a pointer to StreamContext, which makes redundant storing copies of the fields of the latter. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Change-Id: If6716f4051c484b52927cbfe4032df7c907eb3a5 (cherry picked from commit 1eedc130e886ad56ed6c1969a9409d6fb84e8fda) Merged-In: If6716f4051c484b52927cbfe4032df7c907eb3a5 --- audio/aidl/default/Stream.cpp | 81 ++++++++++--------- audio/aidl/default/alsa/StreamAlsa.cpp | 2 +- audio/aidl/default/include/core-impl/Stream.h | 62 +++++++------- .../default/include/core-impl/StreamAlsa.h | 2 +- .../include/core-impl/StreamRemoteSubmix.h | 2 +- .../default/include/core-impl/StreamStub.h | 2 +- .../default/include/core-impl/StreamUsb.h | 2 +- .../default/r_submix/StreamRemoteSubmix.cpp | 16 ++-- audio/aidl/default/stub/StreamStub.cpp | 7 +- audio/aidl/default/usb/StreamUsb.cpp | 6 +- 10 files changed, 93 insertions(+), 89 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 032fa87a7f..740788288a 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -91,17 +91,18 @@ void StreamContext::reset() { } std::string StreamWorkerCommonLogic::init() { - if (mCommandMQ == nullptr) return "Command MQ is null"; - if (mReplyMQ == nullptr) return "Reply MQ is null"; - if (mDataMQ == nullptr) return "Data MQ is null"; - if (sizeof(DataBufferElement) != mDataMQ->getQuantumSize()) { - return "Unexpected Data MQ quantum size: " + std::to_string(mDataMQ->getQuantumSize()); + if (mContext->getCommandMQ() == nullptr) return "Command MQ is null"; + if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null"; + StreamContext::DataMQ* const dataMQ = mContext->getDataMQ(); + if (dataMQ == nullptr) return "Data MQ is null"; + if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) { + return "Unexpected Data MQ quantum size: " + std::to_string(dataMQ->getQuantumSize()); } - mDataBufferSize = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(); + mDataBufferSize = dataMQ->getQuantumCount() * dataMQ->getQuantumSize(); mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]); if (mDataBuffer == nullptr) { return "Failed to allocate data buffer for element count " + - std::to_string(mDataMQ->getQuantumCount()) + + std::to_string(dataMQ->getQuantumCount()) + ", size in bytes: " + std::to_string(mDataBufferSize); } if (::android::status_t status = mDriver->init(); status != STATUS_OK) { @@ -114,7 +115,7 @@ void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply, bool isConnected) const { reply->status = STATUS_OK; if (isConnected) { - reply->observable.frames = mFrameCount; + reply->observable.frames = mContext->getFrameCount(); reply->observable.timeNs = ::android::elapsedRealtimeNano(); if (auto status = mDriver->getPosition(&reply->observable); status == ::android::OK) { return; @@ -141,7 +142,7 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { // TODO: Add a delay for transitions of async operations when/if they added. StreamDescriptor::Command command{}; - if (!mCommandMQ->readBlocking(&command, 1)) { + if (!mContext->getCommandMQ()->readBlocking(&command, 1)) { LOG(ERROR) << __func__ << ": reading of command from MQ failed"; mState = StreamDescriptor::State::ERROR; return Status::ABORT; @@ -159,7 +160,7 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { switch (command.getTag()) { case Tag::halReservedExit: if (const int32_t cookie = command.get(); - cookie == mInternalCommandCookie) { + cookie == mContext->getInternalCommandCookie()) { mDriver->shutdown(); setClosed(); // This is an internal command, no need to reply. @@ -277,7 +278,7 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { } reply.state = mState; LOG(severity) << __func__ << ": writing reply " << reply.toString(); - if (!mReplyMQ->writeBlocking(&reply, 1)) { + if (!mContext->getReplyMQ()->writeBlocking(&reply, 1)) { LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed"; mState = StreamDescriptor::State::ERROR; return Status::ABORT; @@ -286,14 +287,16 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { } bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) { - const size_t byteCount = std::min({clientSize, mDataMQ->availableToWrite(), mDataBufferSize}); + StreamContext::DataMQ* const dataMQ = mContext->getDataMQ(); + const size_t byteCount = std::min({clientSize, dataMQ->availableToWrite(), mDataBufferSize}); const bool isConnected = mIsConnected; + const size_t frameSize = mContext->getFrameSize(); size_t actualFrameCount = 0; bool fatal = false; int32_t latency = Module::kLatencyMs; if (isConnected) { - if (::android::status_t status = mDriver->transfer( - mDataBuffer.get(), byteCount / mFrameSize, &actualFrameCount, &latency); + if (::android::status_t status = mDriver->transfer(mDataBuffer.get(), byteCount / frameSize, + &actualFrameCount, &latency); status != ::android::OK) { fatal = true; LOG(ERROR) << __func__ << ": read failed: " << status; @@ -301,17 +304,16 @@ bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply } else { usleep(3000); // Simulate blocking transfer delay. for (size_t i = 0; i < byteCount; ++i) mDataBuffer[i] = 0; - actualFrameCount = byteCount / mFrameSize; + actualFrameCount = byteCount / frameSize; } - const size_t actualByteCount = actualFrameCount * mFrameSize; - if (bool success = - actualByteCount > 0 ? mDataMQ->write(&mDataBuffer[0], actualByteCount) : true; + const size_t actualByteCount = actualFrameCount * frameSize; + if (bool success = actualByteCount > 0 ? dataMQ->write(&mDataBuffer[0], actualByteCount) : true; success) { LOG(VERBOSE) << __func__ << ": writing of " << actualByteCount << " bytes into data MQ" << " succeeded; connected? " << isConnected; // Frames are provided and counted regardless of connection status. reply->fmqByteCount += actualByteCount; - mFrameCount += actualFrameCount; + mContext->advanceFrameCount(actualFrameCount); populateReply(reply, isConnected); } else { LOG(WARNING) << __func__ << ": writing of " << actualByteCount @@ -330,7 +332,8 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { if (auto stateDurationMs = std::chrono::duration_cast( std::chrono::steady_clock::now() - mTransientStateStart); stateDurationMs >= mTransientStateDelayMs) { - if (mAsyncCallback == nullptr) { + std::shared_ptr asyncCallback = mContext->getAsyncCallback(); + if (asyncCallback == nullptr) { // In blocking mode, mState can only be DRAINING. mState = StreamDescriptor::State::IDLE; } else { @@ -338,13 +341,13 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { // drain or transfer completion. In the stub, we switch unconditionally. if (mState == StreamDescriptor::State::DRAINING) { mState = StreamDescriptor::State::IDLE; - ndk::ScopedAStatus status = mAsyncCallback->onDrainReady(); + ndk::ScopedAStatus status = asyncCallback->onDrainReady(); if (!status.isOk()) { LOG(ERROR) << __func__ << ": error from onDrainReady: " << status; } } else { mState = StreamDescriptor::State::ACTIVE; - ndk::ScopedAStatus status = mAsyncCallback->onTransferReady(); + ndk::ScopedAStatus status = asyncCallback->onTransferReady(); if (!status.isOk()) { LOG(ERROR) << __func__ << ": error from onTransferReady: " << status; } @@ -358,7 +361,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { } StreamDescriptor::Command command{}; - if (!mCommandMQ->readBlocking(&command, 1)) { + if (!mContext->getCommandMQ()->readBlocking(&command, 1)) { LOG(ERROR) << __func__ << ": reading of command from MQ failed"; mState = StreamDescriptor::State::ERROR; return Status::ABORT; @@ -377,7 +380,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { switch (command.getTag()) { case Tag::halReservedExit: if (const int32_t cookie = command.get(); - cookie == mInternalCommandCookie) { + cookie == mContext->getInternalCommandCookie()) { mDriver->shutdown(); setClosed(); // This is an internal command, no need to reply. @@ -432,10 +435,11 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { if (!write(fmqByteCount, &reply)) { mState = StreamDescriptor::State::ERROR; } + std::shared_ptr asyncCallback = mContext->getAsyncCallback(); if (mState == StreamDescriptor::State::STANDBY || mState == StreamDescriptor::State::DRAIN_PAUSED || mState == StreamDescriptor::State::PAUSED) { - if (mAsyncCallback == nullptr || + if (asyncCallback == nullptr || mState != StreamDescriptor::State::DRAIN_PAUSED) { mState = StreamDescriptor::State::PAUSED; } else { @@ -444,7 +448,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { } else if (mState == StreamDescriptor::State::IDLE || mState == StreamDescriptor::State::DRAINING || mState == StreamDescriptor::State::ACTIVE) { - if (mAsyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) { + if (asyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) { mState = StreamDescriptor::State::ACTIVE; } else { switchToTransientState(StreamDescriptor::State::TRANSFERRING); @@ -466,7 +470,8 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { if (::android::status_t status = mDriver->drain(mode); status == ::android::OK) { populateReply(&reply, mIsConnected); - if (mState == StreamDescriptor::State::ACTIVE && mForceSynchronousDrain) { + if (mState == StreamDescriptor::State::ACTIVE && + mContext->getForceSynchronousDrain()) { mState = StreamDescriptor::State::IDLE; } else { switchToTransientState(StreamDescriptor::State::DRAINING); @@ -541,7 +546,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { } reply.state = mState; LOG(severity) << __func__ << ": writing reply " << reply.toString(); - if (!mReplyMQ->writeBlocking(&reply, 1)) { + if (!mContext->getReplyMQ()->writeBlocking(&reply, 1)) { LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed"; mState = StreamDescriptor::State::ERROR; return Status::ABORT; @@ -550,38 +555,40 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { } bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) { - const size_t readByteCount = mDataMQ->availableToRead(); + StreamContext::DataMQ* const dataMQ = mContext->getDataMQ(); + const size_t readByteCount = dataMQ->availableToRead(); + const size_t frameSize = mContext->getFrameSize(); bool fatal = false; int32_t latency = Module::kLatencyMs; - if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) { + if (bool success = readByteCount > 0 ? dataMQ->read(&mDataBuffer[0], readByteCount) : true) { const bool isConnected = mIsConnected; LOG(VERBOSE) << __func__ << ": reading of " << readByteCount << " bytes from data MQ" << " succeeded; connected? " << isConnected; // Amount of data that the HAL module is going to actually use. size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize}); - if (byteCount >= mFrameSize && mForceTransientBurst) { + if (byteCount >= frameSize && mContext->getForceTransientBurst()) { // In order to prevent the state machine from going to ACTIVE state, // simulate partial write. - byteCount -= mFrameSize; + byteCount -= frameSize; } size_t actualFrameCount = 0; if (isConnected) { if (::android::status_t status = mDriver->transfer( - mDataBuffer.get(), byteCount / mFrameSize, &actualFrameCount, &latency); + mDataBuffer.get(), byteCount / frameSize, &actualFrameCount, &latency); status != ::android::OK) { fatal = true; LOG(ERROR) << __func__ << ": write failed: " << status; } } else { - if (mAsyncCallback == nullptr) { + if (mContext->getAsyncCallback() == nullptr) { usleep(3000); // Simulate blocking transfer delay. } - actualFrameCount = byteCount / mFrameSize; + actualFrameCount = byteCount / frameSize; } - const size_t actualByteCount = actualFrameCount * mFrameSize; + const size_t actualByteCount = actualFrameCount * frameSize; // Frames are consumed and counted regardless of the connection status. reply->fmqByteCount += actualByteCount; - mFrameCount += actualFrameCount; + mContext->advanceFrameCount(actualFrameCount); populateReply(reply, isConnected); } else { LOG(WARNING) << __func__ << ": reading of " << readByteCount diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp index c7fb02248a..00a7a8426b 100644 --- a/audio/aidl/default/alsa/StreamAlsa.cpp +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -27,7 +27,7 @@ namespace aidl::android::hardware::audio::core { -StreamAlsa::StreamAlsa(const StreamContext& context, const Metadata& metadata, int readWriteRetries) +StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries) : StreamCommonImpl(context, metadata), mFrameSizeBytes(getContext().getFrameSize()), mIsInput(isInput(metadata)), diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 355d3b4cb8..0970774263 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -113,7 +113,8 @@ class StreamContext { mDataMQ(std::move(other.mDataMQ)), mAsyncCallback(std::move(other.mAsyncCallback)), mOutEventCallback(std::move(other.mOutEventCallback)), - mDebugParameters(std::move(other.mDebugParameters)) {} + mDebugParameters(std::move(other.mDebugParameters)), + mFrameCount(other.mFrameCount) {} StreamContext& operator=(StreamContext&& other) { mCommandMQ = std::move(other.mCommandMQ); mInternalCommandCookie = other.mInternalCommandCookie; @@ -128,6 +129,7 @@ class StreamContext { mAsyncCallback = std::move(other.mAsyncCallback); mOutEventCallback = std::move(other.mOutEventCallback); mDebugParameters = std::move(other.mDebugParameters); + mFrameCount = other.mFrameCount; return *this; } @@ -156,7 +158,12 @@ class StreamContext { int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; } int getSampleRate() const { return mSampleRate; } bool isValid() const; + // 'reset' is called on a Binder thread when closing the stream. Does not use + // locking because it only cleans MQ pointers which were also set on the Binder thread. void reset(); + // 'advanceFrameCount' and 'getFrameCount' are only called on the worker thread. + long advanceFrameCount(size_t increase) { return mFrameCount += increase; } + long getFrameCount() const { return mFrameCount; } private: std::unique_ptr mCommandMQ; @@ -172,6 +179,7 @@ class StreamContext { std::shared_ptr mAsyncCallback; std::shared_ptr mOutEventCallback; // Only used by output streams DebugParameters mDebugParameters; + long mFrameCount = 0; }; // This interface provides operations of the stream which are executed on the worker thread. @@ -206,17 +214,10 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea protected: using DataBufferElement = int8_t; - StreamWorkerCommonLogic(const StreamContext& context, DriverInterface* driver) - : mDriver(driver), - mInternalCommandCookie(context.getInternalCommandCookie()), - mFrameSize(context.getFrameSize()), - mCommandMQ(context.getCommandMQ()), - mReplyMQ(context.getReplyMQ()), - mDataMQ(context.getDataMQ()), - mAsyncCallback(context.getAsyncCallback()), - mTransientStateDelayMs(context.getTransientStateDelayMs()), - mForceTransientBurst(context.getForceTransientBurst()), - mForceSynchronousDrain(context.getForceSynchronousDrain()) {} + StreamWorkerCommonLogic(StreamContext* context, DriverInterface* driver) + : mContext(context), + mDriver(driver), + mTransientStateDelayMs(context->getTransientStateDelayMs()) {} std::string init() override; void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const; void populateReplyWrongState(StreamDescriptor::Reply* reply, @@ -226,34 +227,28 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea mTransientStateStart = std::chrono::steady_clock::now(); } + // The context is only used for reading, except for updating the frame count, + // which happens on the worker thread only. + StreamContext* const mContext; DriverInterface* const mDriver; // Atomic fields are used both by the main and worker threads. std::atomic mIsConnected = false; static_assert(std::atomic::is_always_lock_free); std::atomic mState = StreamDescriptor::State::STANDBY; - // All fields are used on the worker thread only. - const int mInternalCommandCookie; - const size_t mFrameSize; - StreamContext::CommandMQ* const mCommandMQ; - StreamContext::ReplyMQ* const mReplyMQ; - StreamContext::DataMQ* const mDataMQ; - std::shared_ptr mAsyncCallback; + // All fields below are used on the worker thread only. const std::chrono::duration mTransientStateDelayMs; std::chrono::time_point mTransientStateStart; - const bool mForceTransientBurst; - const bool mForceSynchronousDrain; // We use an array and the "size" field instead of a vector to be able to detect // memory allocation issues. std::unique_ptr mDataBuffer; size_t mDataBufferSize; - long mFrameCount = 0; }; // This interface is used to decouple stream implementations from a concrete StreamWorker // implementation. struct StreamWorkerInterface { - using CreateInstance = std::function; + using CreateInstance = + std::function; virtual ~StreamWorkerInterface() = default; virtual bool isClosed() const = 0; virtual void setIsConnected(bool isConnected) = 0; @@ -268,7 +263,7 @@ class StreamWorkerImpl : public StreamWorkerInterface, using WorkerImpl = ::android::hardware::audio::common::StreamWorker; public: - StreamWorkerImpl(const StreamContext& context, DriverInterface* driver) + StreamWorkerImpl(StreamContext* context, DriverInterface* driver) : WorkerImpl(context, driver) {} bool isClosed() const override { return WorkerImpl::isClosed(); } void setIsConnected(bool isConnected) override { WorkerImpl::setIsConnected(isConnected); } @@ -282,7 +277,7 @@ class StreamWorkerImpl : public StreamWorkerInterface, class StreamInWorkerLogic : public StreamWorkerCommonLogic { public: static const std::string kThreadName; - StreamInWorkerLogic(const StreamContext& context, DriverInterface* driver) + StreamInWorkerLogic(StreamContext* context, DriverInterface* driver) : StreamWorkerCommonLogic(context, driver) {} protected: @@ -296,8 +291,9 @@ using StreamInWorker = StreamWorkerImpl; class StreamOutWorkerLogic : public StreamWorkerCommonLogic { public: static const std::string kThreadName; - StreamOutWorkerLogic(const StreamContext& context, DriverInterface* driver) - : StreamWorkerCommonLogic(context, driver), mEventCallback(context.getOutEventCallback()) {} + StreamOutWorkerLogic(StreamContext* context, DriverInterface* driver) + : StreamWorkerCommonLogic(context, driver), + mEventCallback(context->getOutEventCallback()) {} protected: Status cycle() override; @@ -416,10 +412,10 @@ class StreamCommonDelegator : public BnStreamCommon { // who must be owner of the context. class StreamCommonImpl : virtual public StreamCommonInterface, virtual public DriverInterface { public: - StreamCommonImpl(const StreamContext& context, const Metadata& metadata, + StreamCommonImpl(StreamContext* context, const Metadata& metadata, const StreamWorkerInterface::CreateInstance& createWorker) - : mContext(context), mMetadata(metadata), mWorker(createWorker(mContext, this)) {} - StreamCommonImpl(const StreamContext& context, const Metadata& metadata) + : mContext(*context), mMetadata(metadata), mWorker(createWorker(context, this)) {} + StreamCommonImpl(StreamContext* context, const Metadata& metadata) : StreamCommonImpl( context, metadata, isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {} @@ -453,12 +449,12 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr protected: static StreamWorkerInterface::CreateInstance getDefaultInWorkerCreator() { - return [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* { + return [](StreamContext* ctx, DriverInterface* driver) -> StreamWorkerInterface* { return new StreamInWorker(ctx, driver); }; } static StreamWorkerInterface::CreateInstance getDefaultOutWorkerCreator() { - return [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* { + return [](StreamContext* ctx, DriverInterface* driver) -> StreamWorkerInterface* { return new StreamOutWorker(ctx, driver); }; } diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h index 90d2e36df7..f98a922a5f 100644 --- a/audio/aidl/default/include/core-impl/StreamAlsa.h +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -31,7 +31,7 @@ namespace aidl::android::hardware::audio::core { // provide necessary overrides for all interface methods omitted here. class StreamAlsa : public StreamCommonImpl { public: - StreamAlsa(const StreamContext& context, const Metadata& metadata, int readWriteRetries); + StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries); // Methods of 'DriverInterface'. ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h index 4c984afff9..cc44a6e368 100644 --- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -29,7 +29,7 @@ using aidl::android::hardware::audio::core::r_submix::SubmixRoute; class StreamRemoteSubmix : public StreamCommonImpl { public: - StreamRemoteSubmix(const StreamContext& context, const Metadata& metadata); + StreamRemoteSubmix(StreamContext* context, const Metadata& metadata); ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index 2a92deb07c..d16318107c 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -22,7 +22,7 @@ namespace aidl::android::hardware::audio::core { class StreamStub : public StreamCommonImpl { public: - StreamStub(const StreamContext& context, const Metadata& metadata); + StreamStub(StreamContext* context, const Metadata& metadata); // Methods of 'DriverInterface'. ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 7dc7296399..4fcd0e48a2 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -28,7 +28,7 @@ namespace aidl::android::hardware::audio::core { class StreamUsb : public StreamAlsa { public: - StreamUsb(const StreamContext& context, const Metadata& metadata); + StreamUsb(StreamContext* context, const Metadata& metadata); // Methods of 'DriverInterface'. ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 53d4aa61ab..9537ebc56d 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -29,14 +29,14 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -StreamRemoteSubmix::StreamRemoteSubmix(const StreamContext& context, const Metadata& metadata) +StreamRemoteSubmix::StreamRemoteSubmix(StreamContext* context, const Metadata& metadata) : StreamCommonImpl(context, metadata), - mPortId(context.getPortId()), + mPortId(context->getPortId()), mIsInput(isInput(metadata)) { - mStreamConfig.frameSize = context.getFrameSize(); - mStreamConfig.format = context.getFormat(); - mStreamConfig.channelLayout = context.getChannelLayout(); - mStreamConfig.sampleRate = context.getSampleRate(); + mStreamConfig.frameSize = context->getFrameSize(); + mStreamConfig.format = context->getFormat(); + mStreamConfig.channelLayout = context->getChannelLayout(); + mStreamConfig.sampleRate = context->getSampleRate(); } std::mutex StreamRemoteSubmix::sSubmixRoutesLock; @@ -357,7 +357,7 @@ StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) : StreamIn(std::move(context), microphones), - StreamRemoteSubmix(StreamIn::mContext, sinkMetadata) {} + StreamRemoteSubmix(&(StreamIn::mContext), sinkMetadata) {} ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones( std::vector* _aidl_return) { @@ -370,6 +370,6 @@ StreamOutRemoteSubmix::StreamOutRemoteSubmix(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) : StreamOut(std::move(context), offloadInfo), - StreamRemoteSubmix(StreamOut::mContext, sourceMetadata) {} + StreamRemoteSubmix(&(StreamOut::mContext), sourceMetadata) {} } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp index e916fea0fd..66f46059a4 100644 --- a/audio/aidl/default/stub/StreamStub.cpp +++ b/audio/aidl/default/stub/StreamStub.cpp @@ -31,7 +31,7 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -StreamStub::StreamStub(const StreamContext& context, const Metadata& metadata) +StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) : StreamCommonImpl(context, metadata), mFrameSizeBytes(getContext().getFrameSize()), mSampleRate(getContext().getSampleRate()), @@ -120,10 +120,11 @@ void StreamStub::shutdown() { StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) - : StreamIn(std::move(context), microphones), StreamStub(StreamIn::mContext, sinkMetadata) {} + : StreamIn(std::move(context), microphones), StreamStub(&(StreamIn::mContext), sinkMetadata) {} StreamOutStub::StreamOutStub(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) - : StreamOut(std::move(context), offloadInfo), StreamStub(StreamOut::mContext, sourceMetadata) {} + : StreamOut(std::move(context), offloadInfo), + StreamStub(&(StreamOut::mContext), sourceMetadata) {} } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index def12e094c..9684a871df 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -35,7 +35,7 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -StreamUsb::StreamUsb(const StreamContext& context, const Metadata& metadata) +StreamUsb::StreamUsb(StreamContext* context, const Metadata& metadata) : StreamAlsa(context, metadata, 1 /*readWriteRetries*/) {} ndk::ScopedAStatus StreamUsb::setConnectedDevices( @@ -85,7 +85,7 @@ std::vector StreamUsb::getDeviceProfiles() { StreamInUsb::StreamInUsb(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) - : StreamIn(std::move(context), microphones), StreamUsb(StreamIn::mContext, sinkMetadata) {} + : StreamIn(std::move(context), microphones), StreamUsb(&(StreamIn::mContext), sinkMetadata) {} ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( std::vector* _aidl_return __unused) { @@ -96,7 +96,7 @@ ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) : StreamOut(std::move(context), offloadInfo), - StreamUsb(StreamOut::mContext, sourceMetadata), + StreamUsb(&(StreamOut::mContext), sourceMetadata), mChannelCount(getChannelCount(getContext().getChannelLayout())) {} ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { From 29fc7492779de1b8ac69b9ef71ebe0d95d42e750 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 24 Jul 2023 11:44:50 -0700 Subject: [PATCH 080/152] audio: Add a helper class to simplify legacy HALs migration Since in the C and HIDL APIs the method for opening a stream receives the device to connect to, some legacy HAL implementations took an advantage of that. In AIDL APIs device port connection process is more dynamic and independent of the stream creation. To simplify porting of legacy implementations to AIDL, a helper class StreamSwitcher is added. It emulates the legacy behavior by allowing to postpone the stream implementation creation until the connected device is known. Until that moment, it exposes to the client a stub implementation of the stream interface. Bug: 264712385 Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Change-Id: Ie8ae0338fd22f705e00a34e56a7fa235eda5ed9e (cherry picked from commit 43a85cfb2b7931a8a7f4affd1324e448a31a848d) Merged-In: Ie8ae0338fd22f705e00a34e56a7fa235eda5ed9e --- audio/aidl/default/Android.bp | 1 + audio/aidl/default/Stream.cpp | 3 +- audio/aidl/default/StreamSwitcher.cpp | 230 ++++++++++++++++++ audio/aidl/default/include/core-impl/Stream.h | 22 +- .../include/core-impl/StreamRemoteSubmix.h | 4 +- .../default/include/core-impl/StreamStub.h | 4 +- .../include/core-impl/StreamSwitcher.h | 191 +++++++++++++++ .../default/include/core-impl/StreamUsb.h | 4 +- 8 files changed, 444 insertions(+), 15 deletions(-) create mode 100644 audio/aidl/default/StreamSwitcher.cpp create mode 100644 audio/aidl/default/include/core-impl/StreamSwitcher.h diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 19b2397de6..4e583a4808 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -76,6 +76,7 @@ cc_library { "ModulePrimary.cpp", "SoundDose.cpp", "Stream.cpp", + "StreamSwitcher.cpp", "Telephony.cpp", "alsa/Mixer.cpp", "alsa/ModuleAlsa.cpp", diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 740788288a..d2be48c389 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -670,8 +670,7 @@ ndk::ScopedAStatus StreamCommonImpl::close() { LOG(DEBUG) << __func__ << ": joining the worker thread..."; mWorker->stop(); LOG(DEBUG) << __func__ << ": worker thread joined"; - onClose(); - mWorker->setClosed(); + onClose(mWorker->setClosed()); return ndk::ScopedAStatus::ok(); } else { LOG(ERROR) << __func__ << ": stream was already closed"; diff --git a/audio/aidl/default/StreamSwitcher.cpp b/audio/aidl/default/StreamSwitcher.cpp new file mode 100644 index 0000000000..956f4138ba --- /dev/null +++ b/audio/aidl/default/StreamSwitcher.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "AHAL_StreamSwitcher" + +#include +#include +#include + +#include "core-impl/StreamStub.h" +#include "core-impl/StreamSwitcher.h" + +using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::media::audio::common::AudioDevice; + +namespace aidl::android::hardware::audio::core { + +StreamSwitcher::StreamSwitcher(StreamContext* context, const Metadata& metadata) + : mMetadata(metadata), mStream(new InnerStreamWrapper(context, mMetadata)) {} + +ndk::ScopedAStatus StreamSwitcher::closeCurrentStream(bool validateStreamState) { + if (!mStream) return ndk::ScopedAStatus::ok(); + RETURN_STATUS_IF_ERROR(mStream->prepareToClose()); + RETURN_STATUS_IF_ERROR(mStream->close()); + if (validateStreamState && !isValidClosingStreamState(mStream->getStatePriorToClosing())) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + mStream.reset(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::close() { + if (mStream != nullptr) { + auto status = closeCurrentStream(false /*validateStreamState*/); + // The actual state is irrelevant since only StreamSwitcher cares about it. + onClose(StreamDescriptor::State::STANDBY); + return status; + } + LOG(ERROR) << __func__ << ": stream was already closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); +} + +ndk::ScopedAStatus StreamSwitcher::prepareToClose() { + if (mStream != nullptr) { + return mStream->prepareToClose(); + } + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); +} + +ndk::ScopedAStatus StreamSwitcher::updateHwAvSyncId(int32_t in_hwAvSyncId) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + RETURN_STATUS_IF_ERROR(mStream->updateHwAvSyncId(in_hwAvSyncId)); + mHwAvSyncId = in_hwAvSyncId; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::getVendorParameters(const std::vector& in_ids, + std::vector* _aidl_return) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (mIsStubStream) { + LOG(ERROR) << __func__ << ": the stream is not connected"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + return mStream->getVendorParameters(in_ids, _aidl_return); +} + +ndk::ScopedAStatus StreamSwitcher::setVendorParameters( + const std::vector& in_parameters, bool in_async) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (mIsStubStream) { + mMissedParameters.emplace_back(in_parameters, in_async); + return ndk::ScopedAStatus::ok(); + } + return mStream->setVendorParameters(in_parameters, in_async); +} + +ndk::ScopedAStatus StreamSwitcher::addEffect(const std::shared_ptr& in_effect) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (!mIsStubStream) { + RETURN_STATUS_IF_ERROR(mStream->addEffect(in_effect)); + } + mEffects.push_back(in_effect); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::removeEffect(const std::shared_ptr& in_effect) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + for (auto it = mEffects.begin(); it != mEffects.end();) { + if ((*it)->asBinder() == in_effect->asBinder()) { + it = mEffects.erase(it); + } else { + ++it; + } + } + return !mIsStubStream ? mStream->removeEffect(in_effect) : ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::getStreamCommonCommon( + std::shared_ptr* _aidl_return) { + if (!mCommon) { + LOG(FATAL) << __func__ << ": the common interface was not created"; + } + *_aidl_return = mCommon.getInstance(); + LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::updateMetadataCommon(const Metadata& metadata) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + mMetadata = metadata; + return !mIsStubStream ? mStream->updateMetadataCommon(metadata) : ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::initInstance( + const std::shared_ptr& delegate) { + mCommon = ndk::SharedRefBase::make(delegate); + // The delegate is null because StreamSwitcher handles IStreamCommon methods by itself. + return mStream->initInstance(nullptr); +} + +const StreamContext& StreamSwitcher::getContext() const { + return *mContext; +} + +bool StreamSwitcher::isClosed() const { + return mStream == nullptr || mStream->isClosed(); +} + +const StreamCommonInterface::ConnectedDevices& StreamSwitcher::getConnectedDevices() const { + return mStream->getConnectedDevices(); +} + +ndk::ScopedAStatus StreamSwitcher::setConnectedDevices(const std::vector& devices) { + LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(devices); + if (mStream->getConnectedDevices() == devices) return ndk::ScopedAStatus::ok(); + const DeviceSwitchBehavior behavior = switchCurrentStream(devices); + if (behavior == DeviceSwitchBehavior::UNSUPPORTED_DEVICES) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } else if (behavior == DeviceSwitchBehavior::SWITCH_TO_STUB_STREAM && !devices.empty()) { + // This is an error in the extending class. + LOG(FATAL) << __func__ + << ": switching to stub stream with connected devices is not allowed"; + } + if (behavior == USE_CURRENT_STREAM) { + mIsStubStream = false; + } else { + LOG(DEBUG) << __func__ << ": connected devices changed, switching stream"; + // Two streams can't be opened for the same context, thus we always need to close + // the current one before creating a new one. + RETURN_STATUS_IF_ERROR(closeCurrentStream(true /*validateStreamState*/)); + if (behavior == CREATE_NEW_STREAM) { + mStream = createNewStream(devices, mContext, mMetadata); + mIsStubStream = false; + } else { // SWITCH_TO_STUB_STREAM + mStream.reset(new InnerStreamWrapper(mContext, mMetadata)); + mIsStubStream = true; + } + // The delegate is null because StreamSwitcher handles IStreamCommon methods by itself. + if (ndk::ScopedAStatus status = mStream->initInstance(nullptr); !status.isOk()) { + // Need to close the current failed stream, and report an error. + // Since we can't operate without a stream implementation, put a stub in. + RETURN_STATUS_IF_ERROR(closeCurrentStream(false /*validateStreamState*/)); + mStream.reset(new InnerStreamWrapper(mContext, mMetadata)); + (void)mStream->initInstance(nullptr); + (void)mStream->setConnectedDevices(devices); + return status; + } + } + RETURN_STATUS_IF_ERROR(mStream->setConnectedDevices(devices)); + if (behavior == CREATE_NEW_STREAM) { + // These updates are less critical, only log warning on failure. + if (mHwAvSyncId.has_value()) { + if (auto status = mStream->updateHwAvSyncId(*mHwAvSyncId); !status.isOk()) { + LOG(WARNING) << __func__ << ": could not update HW AV Sync for a new stream: " + << status.getDescription(); + } + } + for (const auto& vndParam : mMissedParameters) { + if (auto status = mStream->setVendorParameters(vndParam.first, vndParam.second); + !status.isOk()) { + LOG(WARNING) << __func__ << ": error while setting parameters for a new stream: " + << status.getDescription(); + } + } + mMissedParameters.clear(); + for (const auto& effect : mEffects) { + if (auto status = mStream->addEffect(effect); !status.isOk()) { + LOG(WARNING) << __func__ << ": error while adding effect for a new stream: " + << status.getDescription(); + } + } + } + return ndk::ScopedAStatus::ok(); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 0970774263..fa2b760861 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -66,7 +66,8 @@ class StreamContext { DataMQ; // Ensure that this value is not used by any of StreamDescriptor.State enums - static constexpr int32_t STATE_CLOSED = -1; + static constexpr StreamDescriptor::State STATE_CLOSED = + static_cast(-1); struct DebugParameters { // An extra delay for transient states, in ms. @@ -205,10 +206,14 @@ struct DriverInterface { class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic { public: - bool isClosed() const { - return static_cast(mState.load()) == StreamContext::STATE_CLOSED; + bool isClosed() const { return mState == StreamContext::STATE_CLOSED; } + StreamDescriptor::State setClosed() { + auto prevState = mState.exchange(StreamContext::STATE_CLOSED); + if (prevState != StreamContext::STATE_CLOSED) { + mStatePriorToClosing = prevState; + } + return mStatePriorToClosing; } - void setClosed() { mState = static_cast(StreamContext::STATE_CLOSED); } void setIsConnected(bool connected) { mIsConnected = connected; } protected: @@ -231,6 +236,9 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea // which happens on the worker thread only. StreamContext* const mContext; DriverInterface* const mDriver; + // This is the state the stream was in before being closed. It is retrieved by the main + // thread after joining the worker thread. + StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY; // Atomic fields are used both by the main and worker threads. std::atomic mIsConnected = false; static_assert(std::atomic::is_always_lock_free); @@ -252,7 +260,7 @@ struct StreamWorkerInterface { virtual ~StreamWorkerInterface() = default; virtual bool isClosed() const = 0; virtual void setIsConnected(bool isConnected) = 0; - virtual void setClosed() = 0; + virtual StreamDescriptor::State setClosed() = 0; virtual bool start() = 0; virtual void stop() = 0; }; @@ -267,7 +275,7 @@ class StreamWorkerImpl : public StreamWorkerInterface, : WorkerImpl(context, driver) {} bool isClosed() const override { return WorkerImpl::isClosed(); } void setIsConnected(bool isConnected) override { WorkerImpl::setIsConnected(isConnected); } - void setClosed() override { WorkerImpl::setClosed(); } + StreamDescriptor::State setClosed() override { return WorkerImpl::setClosed(); } bool start() override { return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_AUDIO); } @@ -459,7 +467,7 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr }; } - virtual void onClose() = 0; + virtual void onClose(StreamDescriptor::State statePriorToClosing) = 0; void stopWorker(); const StreamContext& mContext; diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h index cc44a6e368..b39583ea8b 100644 --- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -81,7 +81,7 @@ class StreamInRemoteSubmix final : public StreamIn, public StreamRemoteSubmix { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; @@ -97,7 +97,7 @@ class StreamOutRemoteSubmix final : public StreamOut, public StreamRemoteSubmix offloadInfo); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index d16318107c..a8a3fc4961 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -52,7 +52,7 @@ class StreamInStub final : public StreamIn, public StreamStub { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } }; class StreamOutStub final : public StreamOut, public StreamStub { @@ -64,7 +64,7 @@ class StreamOutStub final : public StreamOut, public StreamStub { offloadInfo); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamSwitcher.h b/audio/aidl/default/include/core-impl/StreamSwitcher.h new file mode 100644 index 0000000000..e462481fc1 --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamSwitcher.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Stream.h" + +namespace aidl::android::hardware::audio::core { + +// 'StreamSwitcher' is implementation of 'StreamCommonInterface' which allows +// dynamically switching the underlying stream implementation based on currently +// connected devices. This is achieved by replacing inheritance from +// 'StreamCommonImpl' with owning an instance of it. StreamSwitcher must be +// extended in order to supply the logic for choosing the stream +// implementation. When there are no connected devices, for instance, upon the +// creation, the StreamSwitcher engages an instance of a stub stream in order to +// keep serving requests coming via 'StreamDescriptor'. +// +// StreamSwitcher implements the 'IStreamCommon' interface directly, with +// necessary delegation to the current stream implementation. While the stub +// stream is engaged, any requests made via 'IStreamCommon' (parameters, effects +// setting, etc) are postponed and only delivered on device connection change +// to the "real" stream implementation provided by the extending class. This is why +// the behavior of StreamSwitcher in the "stub" state is not identical to behavior +// of 'StreamStub'. It can become a full substitute for 'StreamStub' once +// device connection change event occurs and the extending class returns +// 'LEAVE_CURRENT_STREAM' from 'switchCurrentStream' method. +// +// There is a natural limitation that the current stream implementation may only +// be switched when the stream is in the 'STANDBY' state. Thus, when the event +// to switch the stream occurs, the current stream is stopped and joined, and +// its last state is validated. Since the change of the set of connected devices +// normally occurs on patch updates, if the stream was not in standby, this is +// reported to the caller of 'IModule.setAudioPatch' as the 'EX_ILLEGAL_STATE' +// error. +// +// The simplest use case, when the implementor just needs to emulate the legacy HAL API +// behavior of receiving the connected devices upon stream creation, the implementation +// of the extending class can look as follows. We assume that 'StreamLegacy' implementation +// is the one requiring to know connected devices on creation: +// +// class StreamLegacy : public StreamCommonImpl { +// public: +// StreamLegacy(StreamContext* context, const Metadata& metadata, +// const std::vector& devices); +// }; +// +// class StreamOutLegacy final : public StreamOut, public StreamSwitcher { +// public: +// StreamOutLegacy(StreamContext&& context, metatadata etc.) +// private: +// DeviceSwitchBehavior switchCurrentStream(const std::vector&) override { +// // This implementation effectively postpones stream creation until +// // receiving the first call to 'setConnectedDevices' with a non-empty list. +// return isStubStream() ? DeviceSwitchBehavior::CREATE_NEW_STREAM : +// DeviceSwitchBehavior::USE_CURRENT_STREAM; +// } +// std::unique_ptr createNewStream( +// const std::vector& devices, +// StreamContext* context, const Metadata& metadata) override { +// return std::unique_ptr(new InnerStreamWrapper( +// context, metadata, devices)); +// } +// void onClose(StreamDescriptor::State) override { defaultOnClose(); } +// } +// + +class StreamCommonInterfaceEx : virtual public StreamCommonInterface { + public: + virtual StreamDescriptor::State getStatePriorToClosing() const = 0; +}; + +template +class InnerStreamWrapper : public T, public StreamCommonInterfaceEx { + public: + InnerStreamWrapper(StreamContext* context, const Metadata& metadata) : T(context, metadata) {} + StreamDescriptor::State getStatePriorToClosing() const override { return mStatePriorToClosing; } + + private: + // Do not need to do anything on close notification from the inner stream + // because StreamSwitcher handles IStreamCommon::close by itself. + void onClose(StreamDescriptor::State statePriorToClosing) override { + mStatePriorToClosing = statePriorToClosing; + } + + StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY; +}; + +class StreamSwitcher : virtual public StreamCommonInterface { + public: + StreamSwitcher(StreamContext* context, const Metadata& metadata); + + ndk::ScopedAStatus close() override; + ndk::ScopedAStatus prepareToClose() override; + ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override; + ndk::ScopedAStatus getVendorParameters(const std::vector& in_ids, + std::vector* _aidl_return) override; + ndk::ScopedAStatus setVendorParameters(const std::vector& in_parameters, + bool in_async) override; + ndk::ScopedAStatus addEffect( + const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) + override; + ndk::ScopedAStatus removeEffect( + const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) + override; + + ndk::ScopedAStatus getStreamCommonCommon(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override; + + ndk::ScopedAStatus initInstance( + const std::shared_ptr& delegate) override; + const StreamContext& getContext() const override; + bool isClosed() const override; + const ConnectedDevices& getConnectedDevices() const override; + ndk::ScopedAStatus setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; + + protected: + // Since switching a stream requires closing down the current stream, StreamSwitcher + // asks the extending class its intent on the connected devices change. + enum DeviceSwitchBehavior { + // Continue using the current stream implementation. If it's the stub implementation, + // StreamSwitcher starts treating the stub stream as a "real" implementation, + // without effectively closing it and starting again. + USE_CURRENT_STREAM, + // This is the normal case when the extending class provides a "real" implementation + // which is not a stub implementation. + CREATE_NEW_STREAM, + // This is the case when the extending class wants to revert back to the initial + // condition of using a stub stream provided by the StreamSwitcher. This behavior + // is only allowed when the list of connected devices is empty. + SWITCH_TO_STUB_STREAM, + // Use when the set of devices is not supported by the extending class. This returns + // 'EX_UNSUPPORTED_OPERATION' from 'setConnectedDevices'. + UNSUPPORTED_DEVICES, + }; + // StreamSwitcher will call these methods from 'setConnectedDevices'. If the switch behavior + // is 'CREATE_NEW_STREAM', the 'createwNewStream' function will be called (with the same + // device vector) for obtaining a new stream implementation, assuming that closing + // the current stream was a success. + virtual DeviceSwitchBehavior switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0; + virtual std::unique_ptr createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) = 0; + virtual void onClose(StreamDescriptor::State streamPriorToClosing) = 0; + + bool isStubStream() const { return mIsStubStream; } + StreamCommonInterfaceEx* getCurrentStream() const { return mStream.get(); } + + private: + using VndParam = std::pair, bool /*isAsync*/>; + + static constexpr bool isValidClosingStreamState(StreamDescriptor::State state) { + return state == StreamDescriptor::State::STANDBY || state == StreamDescriptor::State::ERROR; + } + + ndk::ScopedAStatus closeCurrentStream(bool validateStreamState); + + // StreamSwitcher does not own the context. + StreamContext* mContext; + Metadata mMetadata; + ChildInterface mCommon; + // The current stream. + std::unique_ptr mStream; + // Indicates whether 'mCurrentStream' is a stub stream implementation + // maintained by StreamSwitcher until the extending class provides a "real" + // implementation. The invariant of this state is that there are no connected + // devices. + bool mIsStubStream = true; + // Storage for the data from commands received via 'IStreamCommon'. + std::optional mHwAvSyncId; + std::vector mMissedParameters; + std::vector> mEffects; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 4fcd0e48a2..74e30ff97b 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -53,7 +53,7 @@ class StreamInUsb final : public StreamIn, public StreamUsb { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; @@ -68,7 +68,7 @@ class StreamOutUsb final : public StreamOut, public StreamUsb { offloadInfo); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; From 2267cd4350c2e1b3356067d299c1057573e5ccff Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Fri, 28 Jul 2023 12:55:25 +0000 Subject: [PATCH 081/152] Audio : Fix a few minor issues with stream switcher class 1. Constructor should forward variable arguments 2. mContext initialization was missing 3. Add nullptr check for addEffect and removeEffect methods Bug: 264712385 Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Change-Id: I4037292bf497be186b26508bd16846886fa4fe55 (cherry picked from commit 035beba20344d267d7e48e414b952c8fe3aaa14e) Merged-In: I4037292bf497be186b26508bd16846886fa4fe55 --- audio/aidl/default/StreamSwitcher.cpp | 12 +++++++++++- .../aidl/default/include/core-impl/StreamSwitcher.h | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/audio/aidl/default/StreamSwitcher.cpp b/audio/aidl/default/StreamSwitcher.cpp index 956f4138ba..e00c34b50f 100644 --- a/audio/aidl/default/StreamSwitcher.cpp +++ b/audio/aidl/default/StreamSwitcher.cpp @@ -31,7 +31,9 @@ using aidl::android::media::audio::common::AudioDevice; namespace aidl::android::hardware::audio::core { StreamSwitcher::StreamSwitcher(StreamContext* context, const Metadata& metadata) - : mMetadata(metadata), mStream(new InnerStreamWrapper(context, mMetadata)) {} + : mContext(context), + mMetadata(metadata), + mStream(new InnerStreamWrapper(context, mMetadata)) {} ndk::ScopedAStatus StreamSwitcher::closeCurrentStream(bool validateStreamState) { if (!mStream) return ndk::ScopedAStatus::ok(); @@ -100,6 +102,10 @@ ndk::ScopedAStatus StreamSwitcher::setVendorParameters( } ndk::ScopedAStatus StreamSwitcher::addEffect(const std::shared_ptr& in_effect) { + if (in_effect == nullptr) { + LOG(DEBUG) << __func__ << ": null effect"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } if (mStream == nullptr) { LOG(ERROR) << __func__ << ": stream was closed"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); @@ -112,6 +118,10 @@ ndk::ScopedAStatus StreamSwitcher::addEffect(const std::shared_ptr& in_ } ndk::ScopedAStatus StreamSwitcher::removeEffect(const std::shared_ptr& in_effect) { + if (in_effect == nullptr) { + LOG(DEBUG) << __func__ << ": null effect"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } if (mStream == nullptr) { LOG(ERROR) << __func__ << ": stream was closed"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); diff --git a/audio/aidl/default/include/core-impl/StreamSwitcher.h b/audio/aidl/default/include/core-impl/StreamSwitcher.h index e462481fc1..2cb847080c 100644 --- a/audio/aidl/default/include/core-impl/StreamSwitcher.h +++ b/audio/aidl/default/include/core-impl/StreamSwitcher.h @@ -86,7 +86,8 @@ class StreamCommonInterfaceEx : virtual public StreamCommonInterface { template class InnerStreamWrapper : public T, public StreamCommonInterfaceEx { public: - InnerStreamWrapper(StreamContext* context, const Metadata& metadata) : T(context, metadata) {} + template + InnerStreamWrapper(Args&&... args) : T(std::forward(args)...) {} StreamDescriptor::State getStatePriorToClosing() const override { return mStatePriorToClosing; } private: From 18d823f2bbdc400e18b7207993b1159b62be9cf1 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Wed, 26 Jul 2023 16:12:21 +0000 Subject: [PATCH 082/152] Audio r_submix : Replace usage of portId by device address Use stream switcher to obtain device address for creation of a remote submix stream. Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Change-Id: I8dde3d59e488c9621dce78ffd5249254ecfc0b1a (cherry picked from commit 2e460345a267388794f53516acb700f9ce3a221e) Merged-In: I8dde3d59e488c9621dce78ffd5249254ecfc0b1a --- .../include/core-impl/StreamRemoteSubmix.h | 35 +++++--- .../default/r_submix/StreamRemoteSubmix.cpp | 83 ++++++++++++++++--- 2 files changed, 96 insertions(+), 22 deletions(-) diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h index b39583ea8b..74854c6037 100644 --- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -20,16 +20,16 @@ #include #include "core-impl/Stream.h" +#include "core-impl/StreamSwitcher.h" #include "r_submix/SubmixRoute.h" namespace aidl::android::hardware::audio::core { -using aidl::android::hardware::audio::core::r_submix::AudioConfig; -using aidl::android::hardware::audio::core::r_submix::SubmixRoute; - class StreamRemoteSubmix : public StreamCommonImpl { public: - StreamRemoteSubmix(StreamContext* context, const Metadata& metadata); + StreamRemoteSubmix( + StreamContext* context, const Metadata& metadata, + const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress); ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; @@ -51,16 +51,17 @@ class StreamRemoteSubmix : public StreamCommonImpl { ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount); ::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount); - const int mPortId; + const ::aidl::android::media::audio::common::AudioDeviceAddress mDeviceAddress; const bool mIsInput; - AudioConfig mStreamConfig; - std::shared_ptr mCurrentRoute = nullptr; + r_submix::AudioConfig mStreamConfig; + std::shared_ptr mCurrentRoute = nullptr; // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex // locks and none of the mutex locks should be taken together. static std::mutex sSubmixRoutesLock; - static std::map> sSubmixRoutes - GUARDED_BY(sSubmixRoutesLock); + static std::map<::aidl::android::media::audio::common::AudioDeviceAddress, + std::shared_ptr> + sSubmixRoutes GUARDED_BY(sSubmixRoutesLock); // limit for number of read error log entries to avoid spamming the logs static constexpr int kMaxReadErrorLogs = 5; @@ -72,7 +73,7 @@ class StreamRemoteSubmix : public StreamCommonImpl { static constexpr int kReadAttemptSleepUs = 5000; }; -class StreamInRemoteSubmix final : public StreamIn, public StreamRemoteSubmix { +class StreamInRemoteSubmix final : public StreamIn, public StreamSwitcher { public: friend class ndk::SharedRefBase; StreamInRemoteSubmix( @@ -81,13 +82,19 @@ class StreamInRemoteSubmix final : public StreamIn, public StreamRemoteSubmix { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: + DeviceSwitchBehavior switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; + std::unique_ptr createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) override; void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; }; -class StreamOutRemoteSubmix final : public StreamOut, public StreamRemoteSubmix { +class StreamOutRemoteSubmix final : public StreamOut, public StreamSwitcher { public: friend class ndk::SharedRefBase; StreamOutRemoteSubmix( @@ -97,6 +104,12 @@ class StreamOutRemoteSubmix final : public StreamOut, public StreamRemoteSubmix offloadInfo); private: + DeviceSwitchBehavior switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; + std::unique_ptr createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) override; void onClose(StreamDescriptor::State) override { defaultOnClose(); } }; diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 9537ebc56d..74dea53b3e 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -23,15 +23,18 @@ using aidl::android::hardware::audio::common::SinkMetadata; using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::hardware::audio::core::r_submix::SubmixRoute; +using aidl::android::media::audio::common::AudioDeviceAddress; using aidl::android::media::audio::common::AudioOffloadInfo; using aidl::android::media::audio::common::MicrophoneDynamicInfo; using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -StreamRemoteSubmix::StreamRemoteSubmix(StreamContext* context, const Metadata& metadata) +StreamRemoteSubmix::StreamRemoteSubmix(StreamContext* context, const Metadata& metadata, + const AudioDeviceAddress& deviceAddress) : StreamCommonImpl(context, metadata), - mPortId(context->getPortId()), + mDeviceAddress(deviceAddress), mIsInput(isInput(metadata)) { mStreamConfig.frameSize = context->getFrameSize(); mStreamConfig.format = context->getFormat(); @@ -40,13 +43,14 @@ StreamRemoteSubmix::StreamRemoteSubmix(StreamContext* context, const Metadata& m } std::mutex StreamRemoteSubmix::sSubmixRoutesLock; -std::map> StreamRemoteSubmix::sSubmixRoutes; +std::map> StreamRemoteSubmix::sSubmixRoutes; ::android::status_t StreamRemoteSubmix::init() { { std::lock_guard guard(sSubmixRoutesLock); - if (sSubmixRoutes.find(mPortId) != sSubmixRoutes.end()) { - mCurrentRoute = sSubmixRoutes[mPortId]; + auto routeItr = sSubmixRoutes.find(mDeviceAddress); + if (routeItr != sSubmixRoutes.end()) { + mCurrentRoute = routeItr->second; } } // If route is not available for this port, add it. @@ -59,7 +63,7 @@ std::map> StreamRemoteSubmix::sSubmixRoute } { std::lock_guard guard(sSubmixRoutesLock); - sSubmixRoutes.emplace(mPortId, mCurrentRoute); + sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute); } } else { if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) { @@ -116,8 +120,9 @@ ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() { std::shared_ptr route = nullptr; { std::lock_guard guard(sSubmixRoutesLock); - if (sSubmixRoutes.find(mPortId) != sSubmixRoutes.end()) { - route = sSubmixRoutes[mPortId]; + auto routeItr = sSubmixRoutes.find(mDeviceAddress); + if (routeItr != sSubmixRoutes.end()) { + route = routeItr->second; } } if (route != nullptr) { @@ -146,7 +151,7 @@ void StreamRemoteSubmix::shutdown() { LOG(DEBUG) << __func__ << ": pipe destroyed"; std::lock_guard guard(sSubmixRoutesLock); - sSubmixRoutes.erase(mPortId); + sSubmixRoutes.erase(mDeviceAddress); } mCurrentRoute.reset(); } @@ -357,7 +362,7 @@ StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) : StreamIn(std::move(context), microphones), - StreamRemoteSubmix(&(StreamIn::mContext), sinkMetadata) {} + StreamSwitcher(&(StreamIn::mContext), sinkMetadata) {} ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones( std::vector* _aidl_return) { @@ -366,10 +371,66 @@ ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones( return ndk::ScopedAStatus::ok(); } +StreamSwitcher::DeviceSwitchBehavior StreamInRemoteSubmix::switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { + // This implementation effectively postpones stream creation until + // receiving the first call to 'setConnectedDevices' with a non-empty list. + if (isStubStream()) { + if (devices.size() == 1) { + auto deviceDesc = devices.front().type; + if (deviceDesc.type == + ::aidl::android::media::audio::common::AudioDeviceType::IN_SUBMIX) { + return DeviceSwitchBehavior::CREATE_NEW_STREAM; + } + LOG(ERROR) << __func__ << ": Device type " << toString(deviceDesc.type) + << " not supported"; + } else { + LOG(ERROR) << __func__ << ": Only single device supported."; + } + return DeviceSwitchBehavior::UNSUPPORTED_DEVICES; + } + return DeviceSwitchBehavior::USE_CURRENT_STREAM; +} + +std::unique_ptr StreamInRemoteSubmix::createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) { + return std::unique_ptr( + new InnerStreamWrapper(context, metadata, devices.front().address)); +} + StreamOutRemoteSubmix::StreamOutRemoteSubmix(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) : StreamOut(std::move(context), offloadInfo), - StreamRemoteSubmix(&(StreamOut::mContext), sourceMetadata) {} + StreamSwitcher(&(StreamOut::mContext), sourceMetadata) {} + +StreamSwitcher::DeviceSwitchBehavior StreamOutRemoteSubmix::switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { + // This implementation effectively postpones stream creation until + // receiving the first call to 'setConnectedDevices' with a non-empty list. + if (isStubStream()) { + if (devices.size() == 1) { + auto deviceDesc = devices.front().type; + if (deviceDesc.type == + ::aidl::android::media::audio::common::AudioDeviceType::OUT_SUBMIX) { + return DeviceSwitchBehavior::CREATE_NEW_STREAM; + } + LOG(ERROR) << __func__ << ": Device type " << toString(deviceDesc.type) + << " not supported"; + } else { + LOG(ERROR) << __func__ << ": Only single device supported."; + } + return DeviceSwitchBehavior::UNSUPPORTED_DEVICES; + } + return DeviceSwitchBehavior::USE_CURRENT_STREAM; +} + +std::unique_ptr StreamOutRemoteSubmix::createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) { + return std::unique_ptr( + new InnerStreamWrapper(context, metadata, devices.front().address)); +} } // namespace aidl::android::hardware::audio::core From 36c440a4b3a50302445c0c21ea67be709bcaba60 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 1 Aug 2023 16:34:47 -0700 Subject: [PATCH 083/152] threadnetwork: declare in V matrix. ... instead of specifying in fcm_exclude.cpp. Test: TH Bug: 255383566 Change-Id: I5aa1f654ef8cdfd37737f045854a87d33c36b70b --- compatibility_matrices/compatibility_matrix.9.xml | 8 ++++++++ compatibility_matrices/exclude/fcm_exclude.cpp | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml index 92c870269e..10091fe1ec 100644 --- a/compatibility_matrices/compatibility_matrix.9.xml +++ b/compatibility_matrices/compatibility_matrix.9.xml @@ -573,6 +573,14 @@ default + + android.hardware.threadnetwork + 1 + + IThreadChip + chip0 + + android.hardware.tv.hdmi.cec 1 diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp index fc3a8b368d..ccce449387 100644 --- a/compatibility_matrices/exclude/fcm_exclude.cpp +++ b/compatibility_matrices/exclude/fcm_exclude.cpp @@ -65,7 +65,6 @@ bool ShouldCheckMissingHalsInFcm(const std::string& package) { "android.hardware.keymaster", "android.hardware.media.bufferpool2", "android.hardware.radio", - "android.hardware.threadnetwork", "android.hardware.uwb.fira_android", // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework From ba1c37e79bbcae50084808ff5a57f21d732e046b Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 3 Aug 2023 02:03:51 -0700 Subject: [PATCH 084/152] VTS setGetAllowedNetworkTypesBitmap allow reset If the test fails, the allowed network type bitmap will not be reset to the previous value. Instead of using ASSERT_EQ, change to EXPECT_EQ to allow the test to continue to the reset. Test: atest VtsHalRadioTargetTest Bug: 264913330 Change-Id: I719afa2e0d9ebc41a329f38f3eca597c9381f2f9 --- radio/aidl/vts/radio_network_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp index 2beb249674..253ef82d9f 100644 --- a/radio/aidl/vts/radio_network_test.cpp +++ b/radio/aidl/vts/radio_network_test.cpp @@ -106,7 +106,7 @@ TEST_P(RadioNetworkTest, setGetAllowedNetworkTypesBitmap) { RadioError::REQUEST_NOT_SUPPORTED, RadioError::NO_RESOURCES})); if (radioRsp_network->rspInfo.error == RadioError::NONE) { // verify we get the value we set - ASSERT_EQ(radioRsp_network->networkTypeBitmapResponse, allowedNetworkTypesBitmap); + EXPECT_EQ(radioRsp_network->networkTypeBitmapResponse, allowedNetworkTypesBitmap); } } From a7d3a0dc06c1ebc7fa9021dded444793b5cdf43e Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Thu, 29 Jun 2023 08:36:31 +0530 Subject: [PATCH 085/152] bluetooth: Fix dependency on android.hardware.audio.common Make android.hardware.bluetooth.audio-V3 and VtsHalBluetoothAudioTargetTest to depend on android.hardware.audio.common-V2. This is needed so that the audio HAL service can depend on android.hardware.bluetooth.audio-V3. Bug: 228804498 Test: m Change-Id: Ic001e651de4cc6ef6920f1d6d80ab272c45aefe2 Merged-In: Ic001e651de4cc6ef6920f1d6d80ab272c45aefe2 (cherry picked from commit f6497dd78c6667e8635f97f7cb30e95d5f219f78) --- bluetooth/audio/aidl/Android.bp | 4 ++-- bluetooth/audio/aidl/vts/Android.bp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp index 32f8cca7d2..16b22fef36 100644 --- a/bluetooth/audio/aidl/Android.bp +++ b/bluetooth/audio/aidl/Android.bp @@ -29,7 +29,7 @@ aidl_interface { imports: [ "android.hardware.common-V2", "android.hardware.common.fmq-V1", - "android.hardware.audio.common-V1", + "android.hardware.audio.common-V2", ], backend: { cpp: { @@ -69,7 +69,7 @@ aidl_interface { imports: [ "android.hardware.common-V2", "android.hardware.common.fmq-V1", - "android.hardware.audio.common-V1", + "android.hardware.audio.common-V2", ], }, diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp index 5a604a1960..fe297e02b1 100644 --- a/bluetooth/audio/aidl/vts/Android.bp +++ b/bluetooth/audio/aidl/vts/Android.bp @@ -16,7 +16,7 @@ cc_test { tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"], srcs: ["VtsHalBluetoothAudioTargetTest.cpp"], static_libs: [ - "android.hardware.audio.common-V1-ndk", + "android.hardware.audio.common-V2-ndk", "android.hardware.bluetooth.audio-V3-ndk", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", From 4bb14a9cdf86c7f73b1dce6624256c84acf2120b Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 26 Jul 2023 17:26:02 -0700 Subject: [PATCH 086/152] bluetooth: Add AudioSession/Control methods for AIDL track metadata Add overloads for UpdateSink/SourceMetadata that accept android.hardware.audio.common.Sink/SourceMetadata types. Move include of hardware/audio.h to BluetoothAudioSession.cpp. This allows to use this code from "pure AIDL" modules. Bug: 228804498 Test: m Change-Id: Ib0b8c6d1c7db9b846a508d6d4001f67feb2111c6 (cherry picked from commit d5f0d13ef00ee8c230e319c53b539893789459b3) Merged-In: Ib0b8c6d1c7db9b846a508d6d4001f67feb2111c6 --- .../aidl_session/BluetoothAudioSession.cpp | 81 +++++++++++-------- .../aidl_session/BluetoothAudioSession.h | 8 +- .../BluetoothAudioSessionControl.h | 20 +++++ 3 files changed, 74 insertions(+), 35 deletions(-) diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp index ee5527e62d..c99478f78f 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "BluetoothAudioSession.h" @@ -476,23 +477,9 @@ bool BluetoothAudioSession::GetPresentationPosition( void BluetoothAudioSession::UpdateSourceMetadata( const struct source_metadata& source_metadata) { - std::lock_guard guard(mutex_); - if (!IsSessionReady()) { - LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) - << " has NO session"; - return; - } - ssize_t track_count = source_metadata.track_count; LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << "," << track_count << " track(s)"; - if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || - session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || - session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || - session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { - return; - } - SourceMetadata hal_source_metadata; hal_source_metadata.tracks.resize(track_count); for (int i = 0; i < track_count; i++) { @@ -509,33 +496,14 @@ void BluetoothAudioSession::UpdateSourceMetadata( << toString(hal_source_metadata.tracks[i].contentType) << ", gain=" << hal_source_metadata.tracks[i].gain; } - - auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata); - if (!hal_retval.isOk()) { - LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" - << toString(session_type_) << " failed"; - } + UpdateSourceMetadata(hal_source_metadata); } void BluetoothAudioSession::UpdateSinkMetadata( const struct sink_metadata& sink_metadata) { - std::lock_guard guard(mutex_); - if (!IsSessionReady()) { - LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) - << " has NO session"; - return; - } - ssize_t track_count = sink_metadata.track_count; LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << "," << track_count << " track(s)"; - if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || - session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || - session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || - session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { - return; - } - SinkMetadata hal_sink_metadata; hal_sink_metadata.tracks.resize(track_count); for (int i = 0; i < track_count; i++) { @@ -550,12 +518,57 @@ void BluetoothAudioSession::UpdateSinkMetadata( << ", dest_device_address=" << sink_metadata.tracks[i].dest_device_address; } + UpdateSinkMetadata(hal_sink_metadata); +} + +bool BluetoothAudioSession::UpdateSourceMetadata( + const SourceMetadata& hal_source_metadata) { + std::lock_guard guard(mutex_); + if (!IsSessionReady()) { + LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + return false; + } + + if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { + return false; + } + + auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata); + if (!hal_retval.isOk()) { + LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" + << toString(session_type_) << " failed"; + return false; + } + return true; +} + +bool BluetoothAudioSession::UpdateSinkMetadata( + const SinkMetadata& hal_sink_metadata) { + std::lock_guard guard(mutex_); + if (!IsSessionReady()) { + LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_) + << " has NO session"; + return false; + } + + if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || + session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { + return false; + } auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata); if (!hal_retval.isOk()) { LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType=" << toString(session_type_) << " failed"; + return false; } + return true; } std::vector BluetoothAudioSession::GetSupportedLatencyModes() { diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h index 5bf17bd3d2..103a9ea61b 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h @@ -23,12 +23,15 @@ #include #include #include -#include #include #include #include +// To avoid inclusion of hardware/audio.h +struct sink_metadata; +struct source_metadata; + namespace aidl { namespace android { namespace hardware { @@ -183,6 +186,9 @@ class BluetoothAudioSession { bool GetPresentationPosition(PresentationPosition& presentation_position); void UpdateSourceMetadata(const struct source_metadata& source_metadata); void UpdateSinkMetadata(const struct sink_metadata& sink_metadata); + // New versions for AIDL-only clients. + bool UpdateSourceMetadata(const SourceMetadata& hal_source_metadata); + bool UpdateSinkMetadata(const SinkMetadata& hal_sink_metadata); std::vector GetSupportedLatencyModes(); void SetLatencyMode(const LatencyMode& latency_mode); diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h index 0782c824e1..7ae0353641 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h @@ -156,6 +156,26 @@ class BluetoothAudioSessionControl { } } + static bool UpdateSourceMetadata(const SessionType& session_type, + const SourceMetadata& source_metadata) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->UpdateSourceMetadata(source_metadata); + } + return false; + } + + static bool UpdateSinkMetadata(const SessionType& session_type, + const SinkMetadata& sink_metadata) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->UpdateSinkMetadata(sink_metadata); + } + return false; + } + static std::vector GetSupportedLatencyModes( const SessionType& session_type) { std::shared_ptr session_ptr = From 59df2f67e4baaed947727db6cb2036652c154754 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 26 Jul 2023 13:13:35 -0700 Subject: [PATCH 087/152] aosp aidl bluetooth audio hal implementation Bug: 228804498 Test: atest VtsHalAudioCoreTargetTest Change-Id: Id5fb60fe53ead9f5d2e6ecbb9988a23835cf2509 (cherry picked from commit b03b5c4a06f74ce5d3afa57ad6f640cc23377992) Merged-In: Id5fb60fe53ead9f5d2e6ecbb9988a23835cf2509 --- audio/aidl/default/Android.bp | 7 + audio/aidl/default/Configuration.cpp | 82 +++ audio/aidl/default/Module.cpp | 9 + .../android.hardware.audio.service-aidl.xml | 5 + .../default/bluetooth/DevicePortProxy.cpp | 562 ++++++++++++++++++ .../default/bluetooth/ModuleBluetooth.cpp | 65 ++ .../default/bluetooth/StreamBluetooth.cpp | 298 ++++++++++ .../default/include/core-impl/Configuration.h | 1 + .../include/core-impl/DevicePortProxy.h | 233 ++++++++ audio/aidl/default/include/core-impl/Module.h | 2 +- .../include/core-impl/ModuleBluetooth.h | 46 ++ .../include/core-impl/StreamBluetooth.h | 97 +++ audio/aidl/default/main.cpp | 3 +- 13 files changed, 1408 insertions(+), 2 deletions(-) create mode 100644 audio/aidl/default/bluetooth/DevicePortProxy.cpp create mode 100644 audio/aidl/default/bluetooth/ModuleBluetooth.cpp create mode 100644 audio/aidl/default/bluetooth/StreamBluetooth.cpp create mode 100644 audio/aidl/default/include/core-impl/DevicePortProxy.h create mode 100644 audio/aidl/default/include/core-impl/ModuleBluetooth.h create mode 100644 audio/aidl/default/include/core-impl/StreamBluetooth.h diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 4e583a4808..b6cfc1329c 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -82,6 +82,9 @@ cc_library { "alsa/ModuleAlsa.cpp", "alsa/StreamAlsa.cpp", "alsa/Utils.cpp", + "bluetooth/DevicePortProxy.cpp", + "bluetooth/ModuleBluetooth.cpp", + "bluetooth/StreamBluetooth.cpp", "r_submix/ModuleRemoteSubmix.cpp", "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", @@ -105,7 +108,9 @@ cc_library { "audio_policy_engine_configuration_aidl_default", ], shared_libs: [ + "android.hardware.bluetooth.audio-V3-ndk", "libaudio_aidl_conversion_common_ndk", + "libbluetooth_audio_session_aidl", "libmedia_helper", "libstagefright_foundation", ], @@ -136,7 +141,9 @@ cc_binary { "libaudioserviceexampleimpl", ], shared_libs: [ + "android.hardware.bluetooth.audio-V3-ndk", "libaudio_aidl_conversion_common_ndk", + "libbluetooth_audio_session_aidl", "libmedia_helper", "libstagefright_foundation", ], diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index a71c6ea734..385ffbf9fc 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -561,4 +561,86 @@ std::unique_ptr getStubConfiguration() { return std::make_unique(configuration); } +// Bluetooth configuration: +// +// Device ports: +// * "BT A2DP Out", OUT_DEVICE, CONNECTION_BT_A2DP +// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 +// * "BT A2DP Headphones", OUT_HEADSET, CONNECTION_BT_A2DP +// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 +// * "BT A2DP Speaker", OUT_SPEAKER, CONNECTION_BT_A2DP +// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 +// * "BT Hearing Aid Out", OUT_HEARING_AID, CONNECTION_WIRELESS +// - no profiles specified +// +// Mix ports: +// * "a2dp output", 1 max open, 1 max active stream +// - no profiles specified +// * "hearing aid output", 1 max open, 1 max active stream +// - profile PCM 16-bit; STEREO; 16000, 24000 +// +// Routes: +// "a2dp output" -> "BT A2DP Out" +// "a2dp output" -> "BT A2DP Headphones" +// "a2dp output" -> "BT A2DP Speaker" +// "hearing aid output" -> "BT Hearing Aid Out" +// +std::unique_ptr getBluetoothConfiguration() { + static const Configuration configuration = []() { + const std::vector standardPcmAudioProfiles = { + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, + {44100, 48000, 88200, 96000})}; + Configuration c; + + // Device ports + AudioPort btOutDevice = + createPort(c.nextPortId++, "BT A2DP Out", 0, false, + createDeviceExt(AudioDeviceType::OUT_DEVICE, 0, + AudioDeviceDescription::CONNECTION_BT_A2DP)); + c.ports.push_back(btOutDevice); + c.connectedProfiles[btOutDevice.id] = standardPcmAudioProfiles; + + AudioPort btOutHeadphone = + createPort(c.nextPortId++, "BT A2DP Headphones", 0, false, + createDeviceExt(AudioDeviceType::OUT_HEADSET, 0, + AudioDeviceDescription::CONNECTION_BT_A2DP)); + c.ports.push_back(btOutHeadphone); + c.connectedProfiles[btOutHeadphone.id] = standardPcmAudioProfiles; + + AudioPort btOutSpeaker = + createPort(c.nextPortId++, "BT A2DP Speaker", 0, false, + createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0, + AudioDeviceDescription::CONNECTION_BT_A2DP)); + c.ports.push_back(btOutSpeaker); + c.connectedProfiles[btOutSpeaker.id] = standardPcmAudioProfiles; + + AudioPort btOutHearingAid = + createPort(c.nextPortId++, "BT Hearing Aid Out", 0, false, + createDeviceExt(AudioDeviceType::OUT_HEARING_AID, 0, + AudioDeviceDescription::CONNECTION_WIRELESS)); + c.ports.push_back(btOutHearingAid); + c.connectedProfiles[btOutHearingAid.id] = std::vector( + {createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})}); + + // Mix ports + AudioPort btInMix = + createPort(c.nextPortId++, "a2dp output", 0, true, createPortMixExt(1, 1)); + c.ports.push_back(btInMix); + + AudioPort btHeadsetInMix = + createPort(c.nextPortId++, "hearing aid output", 0, true, createPortMixExt(1, 1)); + btHeadsetInMix.profiles.push_back(createProfile( + PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000})); + c.ports.push_back(btHeadsetInMix); + + c.routes.push_back(createRoute({btInMix}, btOutDevice)); + c.routes.push_back(createRoute({btInMix}, btOutHeadphone)); + c.routes.push_back(createRoute({btInMix}, btOutSpeaker)); + c.routes.push_back(createRoute({btHeadsetInMix}, btOutHearingAid)); + + return c; + }(); + return std::make_unique(configuration); +} + } // namespace aidl::android::hardware::audio::core::internal diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index b59bd7c081..5625a44400 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -26,6 +26,7 @@ #include #include "core-impl/Module.h" +#include "core-impl/ModuleBluetooth.h" #include "core-impl/ModulePrimary.h" #include "core-impl/ModuleRemoteSubmix.h" #include "core-impl/ModuleStub.h" @@ -117,6 +118,8 @@ std::shared_ptr Module::createInstance(Type type) { return ndk::SharedRefBase::make(); case Type::USB: return ndk::SharedRefBase::make(); + case Type::BLUETOOTH: + return ndk::SharedRefBase::make(); } } @@ -134,6 +137,9 @@ std::ostream& operator<<(std::ostream& os, Module::Type t) { case Module::Type::USB: os << "usb"; break; + case Module::Type::BLUETOOTH: + os << "bluetooth"; + break; } return os; } @@ -301,6 +307,9 @@ std::unique_ptr Module::initializeConfig() { case Type::USB: config = std::move(internal::getUsbConfiguration()); break; + case Type::BLUETOOTH: + config = std::move(internal::getBluetoothConfiguration()); + break; } return config; } diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml index c9d6314e32..9db606157a 100644 --- a/audio/aidl/default/android.hardware.audio.service-aidl.xml +++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml @@ -19,6 +19,11 @@ 1 IModule/usb + + android.hardware.audio.core + 1 + IModule/bluetooth + android.hardware.audio.core 1 diff --git a/audio/aidl/default/bluetooth/DevicePortProxy.cpp b/audio/aidl/default/bluetooth/DevicePortProxy.cpp new file mode 100644 index 0000000000..aabf60fac3 --- /dev/null +++ b/audio/aidl/default/bluetooth/DevicePortProxy.cpp @@ -0,0 +1,562 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_BluetoothPortProxy" + +#include +#include +#include +#include +#include + +#include "core-impl/DevicePortProxy.h" + +namespace android::bluetooth::audio::aidl { + +namespace { + +// The maximum time to wait in std::condition_variable::wait_for() +constexpr unsigned int kMaxWaitingTimeMs = 4500; + +} // namespace + +using ::aidl::android::hardware::audio::common::SinkMetadata; +using ::aidl::android::hardware::audio::common::SourceMetadata; +using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration; +using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl; +using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus; +using ::aidl::android::hardware::bluetooth::audio::ChannelMode; +using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; +using ::aidl::android::hardware::bluetooth::audio::PortStatusCallbacks; +using ::aidl::android::hardware::bluetooth::audio::PresentationPosition; +using ::aidl::android::hardware::bluetooth::audio::SessionType; +using ::aidl::android::media::audio::common::AudioDeviceDescription; +using ::aidl::android::media::audio::common::AudioDeviceType; +using ::android::base::StringPrintf; + +std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) { + switch (state) { + case BluetoothStreamState::DISABLED: + return os << "DISABLED"; + case BluetoothStreamState::STANDBY: + return os << "STANDBY"; + case BluetoothStreamState::STARTING: + return os << "STARTING"; + case BluetoothStreamState::STARTED: + return os << "STARTED"; + case BluetoothStreamState::SUSPENDING: + return os << "SUSPENDING"; + case BluetoothStreamState::UNKNOWN: + return os << "UNKNOWN"; + default: + return os << android::base::StringPrintf("%#hhx", state); + } +} + +BluetoothAudioPortAidl::BluetoothAudioPortAidl() + : mCookie(::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined), + mState(BluetoothStreamState::DISABLED), + mSessionType(SessionType::UNKNOWN) {} + +BluetoothAudioPortAidl::~BluetoothAudioPortAidl() { + unregisterPort(); +} + +bool BluetoothAudioPortAidl::registerPort(const AudioDeviceDescription& description) { + if (inUse()) { + LOG(ERROR) << __func__ << debugMessage() << " already in use"; + return false; + } + + if (!initSessionType(description)) return false; + + auto control_result_cb = [port = this](uint16_t cookie, bool start_resp, + const BluetoothAudioStatus& status) { + (void)start_resp; + port->controlResultHandler(cookie, status); + }; + auto session_changed_cb = [port = this](uint16_t cookie) { + port->sessionChangedHandler(cookie); + }; + // TODO: Add audio_config_changed_cb + PortStatusCallbacks cbacks = { + .control_result_cb_ = control_result_cb, + .session_changed_cb_ = session_changed_cb, + }; + mCookie = BluetoothAudioSessionControl::RegisterControlResultCback(mSessionType, cbacks); + auto isOk = (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined); + if (isOk) { + std::lock_guard guard(mCvMutex); + mState = BluetoothStreamState::STANDBY; + } + LOG(DEBUG) << __func__ << debugMessage(); + return isOk; +} + +bool BluetoothAudioPortAidl::initSessionType(const AudioDeviceDescription& description) { + if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP && + (description.type == AudioDeviceType::OUT_DEVICE || + description.type == AudioDeviceType::OUT_HEADPHONE || + description.type == AudioDeviceType::OUT_SPEAKER)) { + LOG(VERBOSE) << __func__ + << ": device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) (" + << description.toString() << ")"; + mSessionType = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH; + } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS && + description.type == AudioDeviceType::OUT_HEARING_AID) { + LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) (" + << description.toString() << ")"; + mSessionType = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH; + } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && + description.type == AudioDeviceType::OUT_HEADSET) { + LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_HEADSET (MEDIA/VOICE) (" + << description.toString() << ")"; + mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH; + } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && + description.type == AudioDeviceType::OUT_SPEAKER) { + LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_SPEAKER (MEDIA) (" + << description.toString() << ")"; + mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH; + } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && + description.type == AudioDeviceType::IN_HEADSET) { + LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_IN_BLE_HEADSET (VOICE) (" + << description.toString() << ")"; + mSessionType = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH; + } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE && + description.type == AudioDeviceType::OUT_BROADCAST) { + LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_BROADCAST (MEDIA) (" + << description.toString() << ")"; + mSessionType = SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH; + } else { + LOG(ERROR) << __func__ << ": unknown device=" << description.toString(); + return false; + } + + if (!BluetoothAudioSessionControl::IsSessionReady(mSessionType)) { + LOG(ERROR) << __func__ << ": device=" << description.toString() + << ", session_type=" << toString(mSessionType) << " is not ready"; + return false; + } + return true; +} + +void BluetoothAudioPortAidl::unregisterPort() { + if (!inUse()) { + LOG(WARNING) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return; + } + BluetoothAudioSessionControl::UnregisterControlResultCback(mSessionType, mCookie); + mCookie = ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined; + LOG(VERBOSE) << __func__ << debugMessage() << " port unregistered"; +} + +void BluetoothAudioPortAidl::controlResultHandler(uint16_t cookie, + const BluetoothAudioStatus& status) { + std::lock_guard guard(mCvMutex); + if (!inUse()) { + LOG(ERROR) << "control_result_cb: BluetoothAudioPortAidl is not in use"; + return; + } + if (mCookie != cookie) { + LOG(ERROR) << "control_result_cb: proxy of device port (cookie=" + << StringPrintf("%#hx", cookie) << ") is corrupted"; + return; + } + BluetoothStreamState previous_state = mState; + LOG(INFO) << "control_result_cb:" << debugMessage() << ", previous_state=" << previous_state + << ", status=" << toString(status); + + switch (previous_state) { + case BluetoothStreamState::STARTED: + /* Only Suspend signal can be send in STARTED state*/ + if (status == BluetoothAudioStatus::RECONFIGURATION || + status == BluetoothAudioStatus::SUCCESS) { + mState = BluetoothStreamState::STANDBY; + } else { + LOG(WARNING) << StringPrintf( + "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " + "previous_state=%#hhx", + toString(status).c_str(), toString(mSessionType).c_str(), mCookie, + previous_state); + } + break; + case BluetoothStreamState::STARTING: + if (status == BluetoothAudioStatus::SUCCESS) { + mState = BluetoothStreamState::STARTED; + } else { + // Set to standby since the stack may be busy switching between outputs + LOG(WARNING) << StringPrintf( + "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " + "previous_state=%#hhx", + toString(status).c_str(), toString(mSessionType).c_str(), mCookie, + previous_state); + mState = BluetoothStreamState::STANDBY; + } + break; + case BluetoothStreamState::SUSPENDING: + if (status == BluetoothAudioStatus::SUCCESS) { + mState = BluetoothStreamState::STANDBY; + } else { + // It will be failed if the headset is disconnecting, and set to disable + // to wait for re-init again + LOG(WARNING) << StringPrintf( + "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, " + "previous_state=%#hhx", + toString(status).c_str(), toString(mSessionType).c_str(), mCookie, + previous_state); + mState = BluetoothStreamState::DISABLED; + } + break; + default: + LOG(ERROR) << "control_result_cb: unexpected previous_state=" + << StringPrintf( + "control_result_cb: status=%s failure for session_type= %s, " + "cookie=%#hx, previous_state=%#hhx", + toString(status).c_str(), toString(mSessionType).c_str(), mCookie, + previous_state); + return; + } + mInternalCv.notify_all(); +} + +void BluetoothAudioPortAidl::sessionChangedHandler(uint16_t cookie) { + std::lock_guard guard(mCvMutex); + if (!inUse()) { + LOG(ERROR) << "session_changed_cb: BluetoothAudioPortAidl is not in use"; + return; + } + if (mCookie != cookie) { + LOG(ERROR) << "session_changed_cb: proxy of device port (cookie=" + << StringPrintf("%#hx", cookie) << ") is corrupted"; + return; + } + BluetoothStreamState previous_state = mState; + LOG(VERBOSE) << "session_changed_cb:" << debugMessage() + << ", previous_state=" << previous_state; + mState = BluetoothStreamState::DISABLED; + mInternalCv.notify_all(); +} + +bool BluetoothAudioPortAidl::inUse() const { + return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined); +} + +bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const { + if (!interval_us) { + LOG(ERROR) << __func__ << ": bad input arg"; + return false; + } + + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + + const AudioConfiguration& hal_audio_cfg = + BluetoothAudioSessionControl::GetAudioConfig(mSessionType); + if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) { + LOG(ERROR) << __func__ << ": unsupported audio cfg tag"; + return false; + } + + *interval_us = hal_audio_cfg.get().dataIntervalUs; + return true; +} + +bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const { + if (!audio_cfg) { + LOG(ERROR) << __func__ << ": bad input arg"; + return false; + } + + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + + const AudioConfiguration& hal_audio_cfg = + BluetoothAudioSessionControl::GetAudioConfig(mSessionType); + if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) { + LOG(ERROR) << __func__ << ": unsupported audio cfg tag"; + return false; + } + *audio_cfg = hal_audio_cfg.get(); + LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=[" + << audio_cfg->toString() << "]"; + if (audio_cfg->channelMode == ChannelMode::UNKNOWN) { + return false; + } + return true; +} + +bool BluetoothAudioPortAidl::condWaitState(BluetoothStreamState state) { + const auto waitTime = std::chrono::milliseconds(kMaxWaitingTimeMs); + std::unique_lock lock(mCvMutex); + base::ScopedLockAssertion lock_assertion(mCvMutex); + switch (state) { + case BluetoothStreamState::STARTING: { + LOG(VERBOSE) << __func__ << debugMessage() << " waiting for STARTED"; + mInternalCv.wait_for(lock, waitTime, [this] { + base::ScopedLockAssertion lock_assertion(mCvMutex); + return mState != BluetoothStreamState::STARTING; + }); + return mState == BluetoothStreamState::STARTED; + } + case BluetoothStreamState::SUSPENDING: { + LOG(VERBOSE) << __func__ << debugMessage() << " waiting for SUSPENDED"; + mInternalCv.wait_for(lock, waitTime, [this] { + base::ScopedLockAssertion lock_assertion(mCvMutex); + return mState != BluetoothStreamState::SUSPENDING; + }); + return mState == BluetoothStreamState::STANDBY; + } + default: + LOG(WARNING) << __func__ << debugMessage() << " waiting for KNOWN"; + return false; + } + return false; +} + +bool BluetoothAudioPortAidl::start() { + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() + << ", mono=" << (mIsStereoToMono ? "true" : "false") << " request"; + + { + std::unique_lock lock(mCvMutex); + base::ScopedLockAssertion lock_assertion(mCvMutex); + if (mState == BluetoothStreamState::STARTED) { + return true; // nop, return + } else if (mState == BluetoothStreamState::SUSPENDING || + mState == BluetoothStreamState::STARTING) { + /* If port is in transient state, give some time to respond */ + auto state_ = mState; + lock.unlock(); + if (!condWaitState(state_)) { + LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; + return false; + } + } + } + + bool retval = false; + { + std::unique_lock lock(mCvMutex); + base::ScopedLockAssertion lock_assertion(mCvMutex); + if (mState == BluetoothStreamState::STARTED) { + retval = true; + } else if (mState == BluetoothStreamState::STANDBY) { + mState = BluetoothStreamState::STARTING; + lock.unlock(); + if (BluetoothAudioSessionControl::StartStream(mSessionType)) { + retval = condWaitState(BluetoothStreamState::STARTING); + } else { + LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() + << " Hal fails"; + } + } + } + + if (retval) { + LOG(INFO) << __func__ << debugMessage() << ", state=" << getState() + << ", mono=" << (mIsStereoToMono ? "true" : "false") << " done"; + } else { + LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; + } + + return retval; // false if any failure like timeout +} + +bool BluetoothAudioPortAidl::suspend() { + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; + + { + std::unique_lock lock(mCvMutex); + base::ScopedLockAssertion lock_assertion(mCvMutex); + if (mState == BluetoothStreamState::STANDBY) { + return true; // nop, return + } else if (mState == BluetoothStreamState::SUSPENDING || + mState == BluetoothStreamState::STARTING) { + /* If port is in transient state, give some time to respond */ + auto state_ = mState; + lock.unlock(); + if (!condWaitState(state_)) { + LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; + return false; + } + } + } + + bool retval = false; + { + std::unique_lock lock(mCvMutex); + base::ScopedLockAssertion lock_assertion(mCvMutex); + if (mState == BluetoothStreamState::STANDBY) { + retval = true; + } else if (mState == BluetoothStreamState::STARTED) { + mState = BluetoothStreamState::SUSPENDING; + lock.unlock(); + if (BluetoothAudioSessionControl::SuspendStream(mSessionType)) { + retval = condWaitState(BluetoothStreamState::SUSPENDING); + } else { + LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() + << " Hal fails"; + } + } + } + + if (retval) { + LOG(INFO) << __func__ << debugMessage() << ", state=" << getState() << " done"; + } else { + LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure"; + } + + return retval; // false if any failure like timeout +} + +void BluetoothAudioPortAidl::stop() { + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return; + } + std::lock_guard guard(mCvMutex); + LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; + if (mState != BluetoothStreamState::DISABLED) { + BluetoothAudioSessionControl::StopStream(mSessionType); + mState = BluetoothStreamState::DISABLED; + } + LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done"; +} + +size_t BluetoothAudioPortAidlOut::writeData(const void* buffer, size_t bytes) const { + if (!buffer) { + LOG(ERROR) << __func__ << ": bad input arg"; + return 0; + } + + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return 0; + } + + if (!mIsStereoToMono) { + return BluetoothAudioSessionControl::OutWritePcmData(mSessionType, buffer, bytes); + } + + // WAR to mix the stereo into Mono (16 bits per sample) + const size_t write_frames = bytes >> 2; + if (write_frames == 0) return 0; + auto src = static_cast(buffer); + std::unique_ptr dst{new int16_t[write_frames]}; + downmix_to_mono_i16_from_stereo_i16(dst.get(), src, write_frames); + // a frame is 16 bits, and the size of a mono frame is equal to half a stereo. + auto totalWrite = BluetoothAudioSessionControl::OutWritePcmData(mSessionType, dst.get(), + write_frames * 2); + return totalWrite * 2; +} + +size_t BluetoothAudioPortAidlIn::readData(void* buffer, size_t bytes) const { + if (!buffer) { + LOG(ERROR) << __func__ << ": bad input arg"; + return 0; + } + + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return 0; + } + + return BluetoothAudioSessionControl::InReadPcmData(mSessionType, buffer, bytes); +} + +bool BluetoothAudioPortAidl::getPresentationPosition( + PresentationPosition& presentation_position) const { + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + bool retval = BluetoothAudioSessionControl::GetPresentationPosition(mSessionType, + presentation_position); + LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() + << presentation_position.toString(); + + return retval; +} + +bool BluetoothAudioPortAidl::updateSourceMetadata(const SourceMetadata& source_metadata) const { + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", " + << source_metadata.tracks.size() << " track(s)"; + if (source_metadata.tracks.size() == 0) return true; + return BluetoothAudioSessionControl::UpdateSourceMetadata(mSessionType, source_metadata); +} + +bool BluetoothAudioPortAidl::updateSinkMetadata(const SinkMetadata& sink_metadata) const { + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", " + << sink_metadata.tracks.size() << " track(s)"; + if (sink_metadata.tracks.size() == 0) return true; + return BluetoothAudioSessionControl::UpdateSinkMetadata(mSessionType, sink_metadata); +} + +BluetoothStreamState BluetoothAudioPortAidl::getState() const { + return mState; +} + +bool BluetoothAudioPortAidl::setState(BluetoothStreamState state) { + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + std::lock_guard guard(mCvMutex); + LOG(DEBUG) << __func__ << ": BluetoothAudioPortAidl old state = " << mState + << " new state = " << state; + mState = state; + return true; +} + +bool BluetoothAudioPortAidl::isA2dp() const { + return mSessionType == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || + mSessionType == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH; +} + +bool BluetoothAudioPortAidl::isLeAudio() const { + return mSessionType == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH || + mSessionType == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH || + mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || + mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH || + mSessionType == SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH || + mSessionType == SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH; +} + +std::string BluetoothAudioPortAidl::debugMessage() const { + return StringPrintf(": session_type=%s, cookie=%#hx", toString(mSessionType).c_str(), mCookie); +} + +} // namespace android::bluetooth::audio::aidl diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp new file mode 100644 index 0000000000..bb11f0ae85 --- /dev/null +++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_ModuleBluetooth" + +#include + +#include "core-impl/ModuleBluetooth.h" +#include "core-impl/StreamBluetooth.h" + +namespace aidl::android::hardware::audio::core { + +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::media::audio::common::AudioOffloadInfo; +using aidl::android::media::audio::common::MicrophoneInfo; + +ndk::ScopedAStatus ModuleBluetooth::getMicMute(bool* _aidl_return __unused) { + LOG(DEBUG) << __func__ << ": is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus ModuleBluetooth::setMicMute(bool in_mute __unused) { + LOG(DEBUG) << __func__ << ": is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus ModuleBluetooth::createInputStream( + StreamContext&& context, const SinkMetadata& sinkMetadata, + const std::vector& microphones, std::shared_ptr* result) { + return createStreamInstance(result, std::move(context), sinkMetadata, + microphones); +} + +ndk::ScopedAStatus ModuleBluetooth::createOutputStream( + StreamContext&& context, const SourceMetadata& sourceMetadata, + const std::optional& offloadInfo, std::shared_ptr* result) { + return createStreamInstance(result, std::move(context), sourceMetadata, + offloadInfo); +} + +ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) { + LOG(DEBUG) << __func__ << ": is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus ModuleBluetooth::onMasterVolumeChanged(float) { + LOG(DEBUG) << __func__ << ": is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp new file mode 100644 index 0000000000..dfccb0eec5 --- /dev/null +++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_StreamBluetooth" + +#include +#include +#include + +#include "BluetoothAudioSessionControl.h" +#include "core-impl/StreamBluetooth.h" + +namespace aidl::android::hardware::audio::core { + +using ::aidl::android::hardware::audio::common::SinkMetadata; +using ::aidl::android::hardware::audio::common::SourceMetadata; +using ::aidl::android::hardware::audio::core::VendorParameter; +using ::aidl::android::hardware::bluetooth::audio::ChannelMode; +using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration; +using ::aidl::android::hardware::bluetooth::audio::PresentationPosition; +using ::aidl::android::media::audio::common::AudioChannelLayout; +using ::aidl::android::media::audio::common::AudioDevice; +using ::aidl::android::media::audio::common::AudioDeviceAddress; +using ::aidl::android::media::audio::common::AudioFormatDescription; +using ::aidl::android::media::audio::common::AudioFormatType; +using ::aidl::android::media::audio::common::AudioOffloadInfo; +using ::aidl::android::media::audio::common::MicrophoneDynamicInfo; +using ::aidl::android::media::audio::common::MicrophoneInfo; +using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl; +using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn; +using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut; +using ::android::bluetooth::audio::aidl::BluetoothStreamState; + +constexpr int kBluetoothDefaultInputBufferMs = 20; +constexpr int kBluetoothDefaultOutputBufferMs = 10; +// constexpr int kBluetoothSpatializerOutputBufferMs = 10; + +size_t getFrameCount(uint64_t durationUs, uint32_t sampleRate) { + return (durationUs * sampleRate) / 1000000; +} + +// pcm configuration params are not really used by the module +StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata) + : StreamCommonImpl(context, metadata), + mSampleRate(getContext().getSampleRate()), + mChannelLayout(getContext().getChannelLayout()), + mFormat(getContext().getFormat()), + mFrameSizeBytes(getContext().getFrameSize()), + mIsInput(isInput(metadata)) { + mPreferredDataIntervalUs = + mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs; + mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate); + mIsInitialized = false; + mIsReadyToClose = false; +} + +::android::status_t StreamBluetooth::init() { + return ::android::OK; // defering this till we get AudioDeviceDescription +} + +const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const { + std::lock_guard guard(mLock); + return StreamCommonImpl::getConnectedDevices(); +} + +ndk::ScopedAStatus StreamBluetooth::setConnectedDevices( + const std::vector& connectedDevices) { + if (mIsInput && connectedDevices.size() > 1) { + LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size() + << ") for input stream"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + for (const auto& connectedDevice : connectedDevices) { + if (connectedDevice.address.getTag() != AudioDeviceAddress::mac) { + LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + } + std::lock_guard guard(mLock); + RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices)); + mIsInitialized = false; // updated connected device list, need initialization + return ndk::ScopedAStatus::ok(); +} + +::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) { + usleep(1000); + return ::android::OK; +} + +::android::status_t StreamBluetooth::flush() { + usleep(1000); + return ::android::OK; +} + +::android::status_t StreamBluetooth::pause() { + return standby(); +} + +::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount, + size_t* actualFrameCount, int32_t* latencyMs) { + std::lock_guard guard(mLock); + if (!mIsInitialized || mIsReadyToClose) { + // 'setConnectedDevices' has been called or stream is ready to close, so no transfers + *actualFrameCount = 0; + *latencyMs = StreamDescriptor::LATENCY_UNKNOWN; + return ::android::OK; + } + *actualFrameCount = 0; + *latencyMs = 0; + for (auto proxy : mBtDeviceProxies) { + if (!proxy->start()) { + LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to start "; + return -EIO; + } + const size_t fc = std::min(frameCount, mPreferredFrameCount); + const size_t bytesToTransfer = fc * mFrameSizeBytes; + if (mIsInput) { + const size_t totalRead = proxy->readData(buffer, bytesToTransfer); + *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes); + } else { + const size_t totalWrite = proxy->writeData(buffer, bytesToTransfer); + *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes); + } + PresentationPosition presentation_position; + if (!proxy->getPresentationPosition(presentation_position)) { + LOG(ERROR) << __func__ << ": getPresentationPosition returned error "; + return ::android::UNKNOWN_ERROR; + } + *latencyMs = + std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos / + NANOS_PER_MILLISECOND)); + } + return ::android::OK; +} + +::android::status_t StreamBluetooth::initialize() { + if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) { + LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory service not available"; + return ::android::UNKNOWN_ERROR; + } + if (StreamCommonImpl::getConnectedDevices().empty()) { + LOG(ERROR) << __func__ << ", has no connected devices"; + return ::android::NO_INIT; + } + // unregister older proxies (if any) + for (auto proxy : mBtDeviceProxies) { + proxy->stop(); + proxy->unregisterPort(); + } + mBtDeviceProxies.clear(); + for (auto it = StreamCommonImpl::getConnectedDevices().begin(); + it != StreamCommonImpl::getConnectedDevices().end(); ++it) { + std::shared_ptr proxy = + mIsInput ? std::shared_ptr( + std::make_shared()) + : std::shared_ptr( + std::make_shared()); + if (proxy->registerPort(it->type)) { + LOG(ERROR) << __func__ << ": cannot init HAL"; + return ::android::UNKNOWN_ERROR; + } + PcmConfiguration config; + if (!proxy->loadAudioConfig(&config)) { + LOG(ERROR) << __func__ << ": state=" << proxy->getState() + << " failed to get audio config"; + return ::android::UNKNOWN_ERROR; + } + // TODO: Ensure minimum duration for spatialized output? + // WAR to support Mono / 16 bits per sample as the Bluetooth stack required + if (!mIsInput && config.channelMode == ChannelMode::MONO && config.bitsPerSample == 16) { + proxy->forcePcmStereoToMono(true); + config.channelMode = ChannelMode::STEREO; + LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO"; + } + if (!checkConfigParams(config)) { + LOG(ERROR) << __func__ << " checkConfigParams failed"; + return ::android::UNKNOWN_ERROR; + } + mBtDeviceProxies.push_back(std::move(proxy)); + } + mIsInitialized = true; + return ::android::OK; +} + +bool StreamBluetooth::checkConfigParams( + ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config) { + if ((int)mSampleRate != config.sampleRateHz) { + LOG(ERROR) << __func__ << ": Sample Rate mismatch, stream val = " << mSampleRate + << " hal val = " << config.sampleRateHz; + return false; + } + auto channelCount = aidl::android::hardware::audio::common::getChannelCount(mChannelLayout); + if ((config.channelMode == ChannelMode::MONO && channelCount != 1) || + (config.channelMode == ChannelMode::STEREO && channelCount != 2)) { + LOG(ERROR) << __func__ << ": Channel count mismatch, stream val = " << channelCount + << " hal val = " << toString(config.channelMode); + return false; + } + if (mFormat.type != AudioFormatType::PCM) { + LOG(ERROR) << __func__ << ": unexpected format type " + << aidl::android::media::audio::common::toString(mFormat.type); + return false; + } + int8_t bps = aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(mFormat.pcm) * 8; + if (bps != config.bitsPerSample) { + LOG(ERROR) << __func__ << ": bits per sample mismatch, stream val = " << bps + << " hal val = " << config.bitsPerSample; + return false; + } + if (config.dataIntervalUs > 0) { + mPreferredDataIntervalUs = + std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs); + mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate); + } + return true; +} + +ndk::ScopedAStatus StreamBluetooth::prepareToClose() { + std::lock_guard guard(mLock); + mIsReadyToClose = true; + return ndk::ScopedAStatus::ok(); +} + +::android::status_t StreamBluetooth::standby() { + std::lock_guard guard(mLock); + if (!mIsInitialized) { + if (auto status = initialize(); status != ::android::OK) return status; + } + for (auto proxy : mBtDeviceProxies) { + if (!proxy->suspend()) { + LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to stand by "; + return -EIO; + } + } + return ::android::OK; +} + +::android::status_t StreamBluetooth::start() { + std::lock_guard guard(mLock); + if (!mIsInitialized) return initialize(); + return ::android::OK; +} + +void StreamBluetooth::shutdown() { + std::lock_guard guard(mLock); + for (auto proxy : mBtDeviceProxies) { + proxy->stop(); + proxy->unregisterPort(); + } + mBtDeviceProxies.clear(); +} + +ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) { + std::lock_guard guard(mLock); + if (!mIsInitialized) return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + bool isOk = true; + if (isInput(metadata)) { + isOk = mBtDeviceProxies[0]->updateSinkMetadata(std::get(metadata)); + } else { + for (auto proxy : mBtDeviceProxies) { + if (!proxy->updateSourceMetadata(std::get(metadata))) isOk = false; + } + } + return isOk ? ndk::ScopedAStatus::ok() + : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata, + const std::vector& microphones) + : StreamIn(std::move(context), microphones), + StreamBluetooth(&(StreamIn::mContext), sinkMetadata) {} + +ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones( + std::vector* _aidl_return __unused) { + LOG(DEBUG) << __func__ << ": not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context, + const SourceMetadata& sourceMetadata, + const std::optional& offloadInfo) + : StreamOut(std::move(context), offloadInfo), + StreamBluetooth(&(StreamOut::mContext), sourceMetadata) {} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h index 25bf7afa81..6277c38db2 100644 --- a/audio/aidl/default/include/core-impl/Configuration.h +++ b/audio/aidl/default/include/core-impl/Configuration.h @@ -47,5 +47,6 @@ std::unique_ptr getPrimaryConfiguration(); std::unique_ptr getRSubmixConfiguration(); std::unique_ptr getStubConfiguration(); std::unique_ptr getUsbConfiguration(); +std::unique_ptr getBluetoothConfiguration(); } // namespace aidl::android::hardware::audio::core::internal diff --git a/audio/aidl/default/include/core-impl/DevicePortProxy.h b/audio/aidl/default/include/core-impl/DevicePortProxy.h new file mode 100644 index 0000000000..72ffaadafc --- /dev/null +++ b/audio/aidl/default/include/core-impl/DevicePortProxy.h @@ -0,0 +1,233 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "BluetoothAudioSessionControl.h" + +namespace android::bluetooth::audio::aidl { + +enum class BluetoothStreamState : uint8_t { + DISABLED = 0, // This stream is closing or Bluetooth profiles (A2DP/LE) is disabled + STANDBY, + STARTING, + STARTED, + SUSPENDING, + UNKNOWN, +}; + +std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state); + +/** + * Proxy for Bluetooth Audio HW Module to communicate with Bluetooth Audio + * Session Control. All methods are not thread safe, so users must acquire a + * lock. Note: currently, getState() of DevicePortProxy is only used for + * verbose logging, it is not locked, so the state may not be synchronized. + */ +class BluetoothAudioPort { + public: + BluetoothAudioPort() = default; + virtual ~BluetoothAudioPort() = default; + + /** + * Fetch output control / data path of BluetoothAudioPort and setup + * callbacks into BluetoothAudioProvider. If registerPort() returns false, the audio + * HAL must delete this BluetoothAudioPort and return EINVAL to caller + */ + virtual bool registerPort( + const ::aidl::android::media::audio::common::AudioDeviceDescription&) = 0; + + /** + * Unregister this BluetoothAudioPort from BluetoothAudioSessionControl. + * Audio HAL must delete this BluetoothAudioPort after calling this. + */ + virtual void unregisterPort() = 0; + + /** + * When the Audio framework / HAL tries to query audio config about format, + * channel mask and sample rate, it uses this function to fetch from the + * Bluetooth stack + */ + virtual bool loadAudioConfig( + ::aidl::android::hardware::bluetooth::audio::PcmConfiguration*) const = 0; + + /** + * WAR to support Mono mode / 16 bits per sample + */ + virtual void forcePcmStereoToMono(bool) = 0; + + /** + * When the Audio framework / HAL wants to change the stream state, it invokes + * these 3 functions to control the Bluetooth stack (Audio Control Path). + * Note: Both start() and suspend() will return true when there are no errors. + * Called by Audio framework / HAL to start the stream + */ + virtual bool start() = 0; + + /** + * Called by Audio framework / HAL to suspend the stream + */ + virtual bool suspend() = 0; + + /** + * Called by Audio framework / HAL to stop the stream + */ + virtual void stop() = 0; + + /** + * Called by the Audio framework / HAL to fetch information about audio frames + * presented to an external sink, or frames presented fror an internal sink + */ + virtual bool getPresentationPosition( + ::aidl::android::hardware::bluetooth::audio::PresentationPosition&) const = 0; + + /** + * Called by the Audio framework / HAL when the metadata of the stream's + * source has been changed. + */ + virtual bool updateSourceMetadata( + const ::aidl::android::hardware::audio::common::SourceMetadata&) const { + return false; + } + + /** + * Called by the Audio framework / HAL when the metadata of the stream's + * sink has been changed. + */ + virtual bool updateSinkMetadata( + const ::aidl::android::hardware::audio::common::SinkMetadata&) const { + return false; + } + + /** + * Return the current BluetoothStreamState + */ + virtual BluetoothStreamState getState() const = 0; + + /** + * Set the current BluetoothStreamState + */ + virtual bool setState(BluetoothStreamState) = 0; + + virtual bool isA2dp() const = 0; + + virtual bool isLeAudio() const = 0; + + virtual bool getPreferredDataIntervalUs(size_t*) const = 0; + + virtual size_t writeData(const void*, size_t) const { return 0; } + + virtual size_t readData(void*, size_t) const { return 0; } +}; + +class BluetoothAudioPortAidl : public BluetoothAudioPort { + public: + BluetoothAudioPortAidl(); + virtual ~BluetoothAudioPortAidl(); + + bool registerPort(const ::aidl::android::media::audio::common::AudioDeviceDescription& + description) override; + + void unregisterPort() override; + + bool loadAudioConfig(::aidl::android::hardware::bluetooth::audio::PcmConfiguration* audio_cfg) + const override; + + void forcePcmStereoToMono(bool force) override { mIsStereoToMono = force; } + + bool start() override; + bool suspend() override; + void stop() override; + + bool getPresentationPosition(::aidl::android::hardware::bluetooth::audio::PresentationPosition& + presentation_position) const override; + + bool updateSourceMetadata(const ::aidl::android::hardware::audio::common::SourceMetadata& + sourceMetadata) const override; + + bool updateSinkMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata& + sinkMetadata) const override; + + /** + * Return the current BluetoothStreamState + * Note: This method is used for logging, does not lock, so value returned may not be latest + */ + BluetoothStreamState getState() const override NO_THREAD_SAFETY_ANALYSIS; + + bool setState(BluetoothStreamState state) override; + + bool isA2dp() const override; + + bool isLeAudio() const override; + + bool getPreferredDataIntervalUs(size_t* interval_us) const override; + + protected: + uint16_t mCookie; + BluetoothStreamState mState GUARDED_BY(mCvMutex); + ::aidl::android::hardware::bluetooth::audio::SessionType mSessionType; + // WR to support Mono: True if fetching Stereo and mixing into Mono + bool mIsStereoToMono = false; + + bool inUse() const; + + std::string debugMessage() const; + + private: + // start()/suspend() report state change status via callback. Wait until kMaxWaitingTimeMs or a + // state change after a call to start()/suspend() and analyse the returned status. Below mutex, + // conditional variable serves this purpose. + mutable std::mutex mCvMutex; + std::condition_variable mInternalCv GUARDED_BY(mCvMutex); + + // Check and initialize session type for |devices| If failed, this + // BluetoothAudioPortAidl is not initialized and must be deleted. + bool initSessionType( + const ::aidl::android::media::audio::common::AudioDeviceDescription& description); + + bool condWaitState(BluetoothStreamState state); + + void controlResultHandler( + uint16_t cookie, + const ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus& status); + void sessionChangedHandler(uint16_t cookie); +}; + +class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl { + public: + // The audio data path to the Bluetooth stack (Software encoding) + size_t writeData(const void* buffer, size_t bytes) const override; +}; + +class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl { + public: + // The audio data path from the Bluetooth stack (Software decoded) + size_t readData(void* buffer, size_t bytes) const override; +}; + +} // namespace android::bluetooth::audio::aidl \ No newline at end of file diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index 539221d5d2..e52940eeb1 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -33,7 +33,7 @@ class Module : public BnModule { public: // This value is used for all AudioPatches and reported by all streams. static constexpr int32_t kLatencyMs = 10; - enum Type : int { DEFAULT, R_SUBMIX, STUB, USB }; + enum Type : int { DEFAULT, R_SUBMIX, STUB, USB, BLUETOOTH }; static std::shared_ptr createInstance(Type type); diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h new file mode 100644 index 0000000000..e20f7a3d25 --- /dev/null +++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "core-impl/Module.h" + +namespace aidl::android::hardware::audio::core { + +class ModuleBluetooth final : public Module { + public: + ModuleBluetooth() : Module(Type::BLUETOOTH) {} + + private: + ndk::ScopedAStatus getMicMute(bool* _aidl_return) override; + ndk::ScopedAStatus setMicMute(bool in_mute) override; + + ndk::ScopedAStatus createInputStream( + StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, + std::shared_ptr* result) override; + ndk::ScopedAStatus createOutputStream( + StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo, + std::shared_ptr* result) override; + ndk::ScopedAStatus onMasterMuteChanged(bool mute) override; + ndk::ScopedAStatus onMasterVolumeChanged(float volume) override; +}; + +} // namespace aidl::android::hardware::audio::core \ No newline at end of file diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h new file mode 100644 index 0000000000..b9c5ea9bbd --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "core-impl/DevicePortProxy.h" +#include "core-impl/Stream.h" + +namespace aidl::android::hardware::audio::core { + +class StreamBluetooth : public StreamCommonImpl { + public: + StreamBluetooth(StreamContext* context, const Metadata& metadata); + + // Methods of 'DriverInterface'. + ::android::status_t init() override; + ::android::status_t drain(StreamDescriptor::DrainMode) override; + ::android::status_t flush() override; + ::android::status_t pause() override; + ::android::status_t standby() override; + ::android::status_t start() override; + ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, + int32_t* latencyMs) override; + void shutdown() override; + + // Overridden methods of 'StreamCommonImpl', called on a Binder thread. + ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override; + ndk::ScopedAStatus prepareToClose() override; + const ConnectedDevices& getConnectedDevices() const override; + ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override; + + private: + // Audio Pcm Config + const uint32_t mSampleRate; + const ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout; + const ::aidl::android::media::audio::common::AudioFormatDescription mFormat; + const size_t mFrameSizeBytes; + const bool mIsInput; + + size_t mPreferredDataIntervalUs; + size_t mPreferredFrameCount; + + mutable std::mutex mLock; + bool mIsInitialized GUARDED_BY(mLock); + bool mIsReadyToClose GUARDED_BY(mLock); + std::vector> + mBtDeviceProxies GUARDED_BY(mLock); + + ::android::status_t initialize() REQUIRES(mLock); + bool checkConfigParams(::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config); +}; + +class StreamInBluetooth final : public StreamIn, public StreamBluetooth { + public: + friend class ndk::SharedRefBase; + StreamInBluetooth( + StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + + private: + void onClose(StreamDescriptor::State) override { defaultOnClose(); } + ndk::ScopedAStatus getActiveMicrophones( + std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) + override; +}; + +class StreamOutBluetooth final : public StreamOut, public StreamBluetooth { + public: + friend class ndk::SharedRefBase; + StreamOutBluetooth( + StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo); + + private: + void onClose(StreamDescriptor::State) override { defaultOnClose(); } +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp index 93fb36607e..a0c0fab40a 100644 --- a/audio/aidl/default/main.cpp +++ b/audio/aidl/default/main.cpp @@ -65,7 +65,8 @@ int main() { return std::make_pair(module, moduleBinder); }; auto modules = {createModule(Module::Type::DEFAULT), createModule(Module::Type::R_SUBMIX), - createModule(Module::Type::USB), createModule(Module::Type::STUB)}; + createModule(Module::Type::USB), createModule(Module::Type::STUB), + createModule(Module::Type::BLUETOOTH)}; (void)modules; ABinderProcess_joinThreadPool(); From e77db7030852f6de53b7163a9acd57c00c1035ae Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Sat, 1 Jul 2023 00:47:09 +0530 Subject: [PATCH 088/152] aosp aidl bluetooth parameter support Bug: 228804498 Test: atest VtsHalAudioCoreTargetTest Change-Id: If1820018d5a6750eed0d0b486e15fc7c717aa11c (cherry picked from commit 18f0d5121af3701decc0b2b306fbe5e8a2db7265) Merged-In: If1820018d5a6750eed0d0b486e15fc7c717aa11c --- audio/aidl/default/Bluetooth.cpp | 15 +++--- audio/aidl/default/Module.cpp | 9 ++++ audio/aidl/default/Stream.cpp | 5 ++ audio/aidl/default/StreamSwitcher.cpp | 20 +++++++ .../default/bluetooth/DevicePortProxy.cpp | 15 ++++++ .../default/bluetooth/ModuleBluetooth.cpp | 32 +++++++++++- .../default/bluetooth/StreamBluetooth.cpp | 52 ++++++++++++++++--- .../default/include/core-impl/Bluetooth.h | 13 ++++- .../include/core-impl/DevicePortProxy.h | 13 ++++- audio/aidl/default/include/core-impl/Module.h | 7 +++ .../include/core-impl/ModuleBluetooth.h | 8 +++ audio/aidl/default/include/core-impl/Stream.h | 15 ++++++ .../include/core-impl/StreamBluetooth.h | 19 +++++-- .../include/core-impl/StreamSwitcher.h | 2 + 14 files changed, 199 insertions(+), 26 deletions(-) diff --git a/audio/aidl/default/Bluetooth.cpp b/audio/aidl/default/Bluetooth.cpp index c32b538ecc..072b89fefb 100644 --- a/audio/aidl/default/Bluetooth.cpp +++ b/audio/aidl/default/Bluetooth.cpp @@ -82,19 +82,18 @@ ndk::ScopedAStatus Bluetooth::setHfpConfig(const HfpConfig& in_config, HfpConfig ndk::ScopedAStatus BluetoothA2dp::isEnabled(bool* _aidl_return) { *_aidl_return = mEnabled; - LOG(DEBUG) << __func__ << ": returning " << *_aidl_return; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus BluetoothA2dp::setEnabled(bool in_enabled) { mEnabled = in_enabled; LOG(DEBUG) << __func__ << ": " << mEnabled; + if (mHandler) return mHandler(); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus BluetoothA2dp::supportsOffloadReconfiguration(bool* _aidl_return) { - *_aidl_return = true; - LOG(DEBUG) << __func__ << ": returning " << *_aidl_return; + *_aidl_return = false; return ndk::ScopedAStatus::ok(); } @@ -102,24 +101,22 @@ ndk::ScopedAStatus BluetoothA2dp::reconfigureOffload( const std::vector<::aidl::android::hardware::audio::core::VendorParameter>& in_parameters __unused) { LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(in_parameters); - return ndk::ScopedAStatus::ok(); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ndk::ScopedAStatus BluetoothLe::isEnabled(bool* _aidl_return) { *_aidl_return = mEnabled; - LOG(DEBUG) << __func__ << ": returning " << *_aidl_return; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus BluetoothLe::setEnabled(bool in_enabled) { mEnabled = in_enabled; - LOG(DEBUG) << __func__ << ": " << mEnabled; + if (mHandler) return mHandler(); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus BluetoothLe::supportsOffloadReconfiguration(bool* _aidl_return) { - *_aidl_return = true; - LOG(DEBUG) << __func__ << ": returning " << *_aidl_return; + *_aidl_return = false; return ndk::ScopedAStatus::ok(); } @@ -127,7 +124,7 @@ ndk::ScopedAStatus BluetoothLe::reconfigureOffload( const std::vector<::aidl::android::hardware::audio::core::VendorParameter>& in_parameters __unused) { LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(in_parameters); - return ndk::ScopedAStatus::ok(); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 5625a44400..f81095e02c 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -1371,4 +1371,13 @@ ndk::ScopedAStatus Module::onMasterVolumeChanged(float volume __unused) { return ndk::ScopedAStatus::ok(); } +Module::BtProfileHandles Module::getBtProfileManagerHandles() { + return std::make_tuple(std::weak_ptr(), std::weak_ptr(), + std::weak_ptr()); +} + +ndk::ScopedAStatus Module::bluetoothParametersUpdated() { + return mStreams.bluetoothParametersUpdated(); +} + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index d2be48c389..c5b25d6047 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -723,6 +723,11 @@ ndk::ScopedAStatus StreamCommonImpl::setConnectedDevices( return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus StreamCommonImpl::bluetoothParametersUpdated() { + LOG(DEBUG) << __func__; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + namespace { static std::map transformMicrophones( const std::vector& microphones) { diff --git a/audio/aidl/default/StreamSwitcher.cpp b/audio/aidl/default/StreamSwitcher.cpp index e00c34b50f..ed4cc8afb2 100644 --- a/audio/aidl/default/StreamSwitcher.cpp +++ b/audio/aidl/default/StreamSwitcher.cpp @@ -233,8 +233,28 @@ ndk::ScopedAStatus StreamSwitcher::setConnectedDevices(const std::vectorbluetoothParametersUpdated(); !status.isOk()) { + LOG(WARNING) << __func__ + << ": error while updating BT parameters for a new stream: " + << status.getDescription(); + } + } + mBluetoothParametersUpdated = false; } return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus StreamSwitcher::bluetoothParametersUpdated() { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (mIsStubStream) { + mBluetoothParametersUpdated = true; + return ndk::ScopedAStatus::ok(); + } + return mStream->bluetoothParametersUpdated(); +} + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/bluetooth/DevicePortProxy.cpp b/audio/aidl/default/bluetooth/DevicePortProxy.cpp index aabf60fac3..12e204a076 100644 --- a/audio/aidl/default/bluetooth/DevicePortProxy.cpp +++ b/audio/aidl/default/bluetooth/DevicePortProxy.cpp @@ -302,6 +302,21 @@ bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const return true; } +bool BluetoothAudioPortAidl::standby() { + if (!inUse()) { + LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use"; + return false; + } + std::lock_guard guard(mCvMutex); + LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request"; + if (mState == BluetoothStreamState::DISABLED) { + mState = BluetoothStreamState::STANDBY; + LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done"; + return true; + } + return false; +} + bool BluetoothAudioPortAidl::condWaitState(BluetoothStreamState state) { const auto waitTime = std::chrono::milliseconds(kMaxWaitingTimeMs); std::unique_lock lock(mCvMutex); diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp index bb11f0ae85..bfe7ca0384 100644 --- a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp +++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp @@ -28,6 +28,34 @@ using aidl::android::hardware::audio::common::SourceMetadata; using aidl::android::media::audio::common::AudioOffloadInfo; using aidl::android::media::audio::common::MicrophoneInfo; +ndk::ScopedAStatus ModuleBluetooth::getBluetoothA2dp( + std::shared_ptr* _aidl_return) { + if (!mBluetoothA2dp) { + auto handle = ndk::SharedRefBase::make(); + handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this)); + mBluetoothA2dp = handle; + } + *_aidl_return = mBluetoothA2dp.getInstance(); + LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModuleBluetooth::getBluetoothLe(std::shared_ptr* _aidl_return) { + if (!mBluetoothLe) { + auto handle = ndk::SharedRefBase::make(); + handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this)); + mBluetoothLe = handle; + } + *_aidl_return = mBluetoothLe.getInstance(); + LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get(); + return ndk::ScopedAStatus::ok(); +} + +Module::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() { + return std::make_tuple(std::weak_ptr(), mBluetoothA2dp.getInstance(), + mBluetoothLe.getInstance()); +} + ndk::ScopedAStatus ModuleBluetooth::getMicMute(bool* _aidl_return __unused) { LOG(DEBUG) << __func__ << ": is not supported"; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); @@ -42,14 +70,14 @@ ndk::ScopedAStatus ModuleBluetooth::createInputStream( StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones, std::shared_ptr* result) { return createStreamInstance(result, std::move(context), sinkMetadata, - microphones); + microphones, getBtProfileManagerHandles()); } ndk::ScopedAStatus ModuleBluetooth::createOutputStream( StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo, std::shared_ptr* result) { return createStreamInstance(result, std::move(context), sourceMetadata, - offloadInfo); + offloadInfo, getBtProfileManagerHandles()); } ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) { diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp index dfccb0eec5..8cb93e3cea 100644 --- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp +++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp @@ -53,13 +53,16 @@ size_t getFrameCount(uint64_t durationUs, uint32_t sampleRate) { } // pcm configuration params are not really used by the module -StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata) +StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata, + Module::BtProfileHandles&& btHandles) : StreamCommonImpl(context, metadata), mSampleRate(getContext().getSampleRate()), mChannelLayout(getContext().getChannelLayout()), mFormat(getContext().getFormat()), mFrameSizeBytes(getContext().getFrameSize()), - mIsInput(isInput(metadata)) { + mIsInput(isInput(metadata)), + mBluetoothA2dp(std::move(std::get(btHandles))), + mBluetoothLe(std::move(std::get(btHandles))) { mPreferredDataIntervalUs = mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs; mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate); @@ -278,10 +281,46 @@ ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadat : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } +ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() { + if (mIsInput) { + LOG(WARNING) << __func__ << ": not handled"; + return ndk::ScopedAStatus::ok(); + } + auto applyParam = [](const std::shared_ptr& proxy, + bool isEnabled) -> bool { + if (!isEnabled) { + if (proxy->suspend()) return proxy->setState(BluetoothStreamState::DISABLED); + return false; + } + return proxy->standby(); + }; + bool hasA2dpParam, enableA2dp; + auto btA2dp = mBluetoothA2dp.lock(); + hasA2dpParam = btA2dp != nullptr && btA2dp->isEnabled(&enableA2dp).isOk(); + bool hasLeParam, enableLe; + auto btLe = mBluetoothLe.lock(); + hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk(); + std::unique_lock lock(mLock); + ::android::base::ScopedLockAssertion lock_assertion(mLock); + if (!mIsInitialized) { + LOG(WARNING) << __func__ << ": init not done"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + for (auto proxy : mBtDeviceProxies) { + if ((hasA2dpParam && proxy->isA2dp() && !applyParam(proxy, enableA2dp)) || + (hasLeParam && proxy->isLeAudio() && !applyParam(proxy, enableLe))) { + LOG(DEBUG) << __func__ << ": applyParam failed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + } + return ndk::ScopedAStatus::ok(); +} + StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata, - const std::vector& microphones) + const std::vector& microphones, + Module::BtProfileHandles&& btProfileHandles) : StreamIn(std::move(context), microphones), - StreamBluetooth(&(StreamIn::mContext), sinkMetadata) {} + StreamBluetooth(&(StreamIn::mContext), sinkMetadata, std::move(btProfileHandles)) {} ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones( std::vector* _aidl_return __unused) { @@ -291,8 +330,9 @@ ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones( StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context, const SourceMetadata& sourceMetadata, - const std::optional& offloadInfo) + const std::optional& offloadInfo, + Module::BtProfileHandles&& btProfileHandles) : StreamOut(std::move(context), offloadInfo), - StreamBluetooth(&(StreamOut::mContext), sourceMetadata) {} + StreamBluetooth(&(StreamOut::mContext), sourceMetadata, std::move(btProfileHandles)) {} } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Bluetooth.h b/audio/aidl/default/include/core-impl/Bluetooth.h index 10e9045042..44899bcee2 100644 --- a/audio/aidl/default/include/core-impl/Bluetooth.h +++ b/audio/aidl/default/include/core-impl/Bluetooth.h @@ -22,6 +22,15 @@ namespace aidl::android::hardware::audio::core { +class ParamChangeHandler { + public: + ParamChangeHandler() = default; + void registerHandler(std::function handler) { mHandler = handler; } + + protected: + std::function mHandler = nullptr; +}; + class Bluetooth : public BnBluetooth { public: Bluetooth(); @@ -34,7 +43,7 @@ class Bluetooth : public BnBluetooth { HfpConfig mHfpConfig; }; -class BluetoothA2dp : public BnBluetoothA2dp { +class BluetoothA2dp : public BnBluetoothA2dp, public ParamChangeHandler { public: BluetoothA2dp() = default; @@ -49,7 +58,7 @@ class BluetoothA2dp : public BnBluetoothA2dp { bool mEnabled = false; }; -class BluetoothLe : public BnBluetoothLe { +class BluetoothLe : public BnBluetoothLe, public ParamChangeHandler { public: BluetoothLe() = default; diff --git a/audio/aidl/default/include/core-impl/DevicePortProxy.h b/audio/aidl/default/include/core-impl/DevicePortProxy.h index 72ffaadafc..13b8c9136e 100644 --- a/audio/aidl/default/include/core-impl/DevicePortProxy.h +++ b/audio/aidl/default/include/core-impl/DevicePortProxy.h @@ -83,8 +83,16 @@ class BluetoothAudioPort { /** * When the Audio framework / HAL wants to change the stream state, it invokes - * these 3 functions to control the Bluetooth stack (Audio Control Path). - * Note: Both start() and suspend() will return true when there are no errors. + * these 4 functions to control the Bluetooth stack (Audio Control Path). + * Note: standby(), start() and suspend() will return true when there are no errors. + + * Called by Audio framework / HAL to change the state to stand by. When A2DP/LE profile is + * disabled, the port is first set to STANDBY by calling suspend and then mState is set to + * DISABLED. To reset the state back to STANDBY this method is called. + */ + virtual bool standby() = 0; + + /** * Called by Audio framework / HAL to start the stream */ virtual bool start() = 0; @@ -160,6 +168,7 @@ class BluetoothAudioPortAidl : public BluetoothAudioPort { void forcePcmStereoToMono(bool force) override { mIsStereoToMono = force; } + bool standby() override; bool start() override; bool suspend() override; void stop() override; diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index e52940eeb1..fb3eef214f 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -34,11 +34,16 @@ class Module : public BnModule { // This value is used for all AudioPatches and reported by all streams. static constexpr int32_t kLatencyMs = 10; enum Type : int { DEFAULT, R_SUBMIX, STUB, USB, BLUETOOTH }; + enum BtInterface : int { BTCONF, BTA2DP, BTLE }; static std::shared_ptr createInstance(Type type); explicit Module(Type type) : mType(type) {} + typedef std::tuple, std::weak_ptr, + std::weak_ptr> + BtProfileHandles; + protected: // The vendor extension done via inheritance can override interface methods and augment // a call to the base implementation. @@ -185,6 +190,7 @@ class Module : public BnModule { virtual std::unique_ptr initializeConfig(); // Utility and helper functions accessible to subclasses. + ndk::ScopedAStatus bluetoothParametersUpdated(); void cleanUpPatch(int32_t patchId); ndk::ScopedAStatus createStreamContext( int32_t in_portConfigId, int64_t in_bufferSizeFrames, @@ -196,6 +202,7 @@ class Module : public BnModule { std::set findConnectedPortConfigIds(int32_t portConfigId); ndk::ScopedAStatus findPortIdForNewStream( int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port); + virtual BtProfileHandles getBtProfileManagerHandles(); internal::Configuration& getConfig(); const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; } bool getMasterMute() const { return mMasterMute; } diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h index e20f7a3d25..68b4e6b058 100644 --- a/audio/aidl/default/include/core-impl/ModuleBluetooth.h +++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h @@ -16,6 +16,7 @@ #pragma once +#include "core-impl/Bluetooth.h" #include "core-impl/Module.h" namespace aidl::android::hardware::audio::core { @@ -25,6 +26,10 @@ class ModuleBluetooth final : public Module { ModuleBluetooth() : Module(Type::BLUETOOTH) {} private: + BtProfileHandles getBtProfileManagerHandles() override; + + ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getBluetoothLe(std::shared_ptr* _aidl_return) override; ndk::ScopedAStatus getMicMute(bool* _aidl_return) override; ndk::ScopedAStatus setMicMute(bool in_mute) override; @@ -41,6 +46,9 @@ class ModuleBluetooth final : public Module { std::shared_ptr* result) override; ndk::ScopedAStatus onMasterMuteChanged(bool mute) override; ndk::ScopedAStatus onMasterVolumeChanged(float volume) override; + + ChildInterface mBluetoothA2dp; + ChildInterface mBluetoothLe; }; } // namespace aidl::android::hardware::audio::core \ No newline at end of file diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index fa2b760861..1ba35200d0 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -354,6 +354,7 @@ struct StreamCommonInterface { virtual const ConnectedDevices& getConnectedDevices() const = 0; virtual ndk::ScopedAStatus setConnectedDevices( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0; + virtual ndk::ScopedAStatus bluetoothParametersUpdated() = 0; }; // This is equivalent to automatically generated 'IStreamCommonDelegator' but uses @@ -454,6 +455,7 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr ndk::ScopedAStatus setConnectedDevices( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) override; + ndk::ScopedAStatus bluetoothParametersUpdated() override; protected: static StreamWorkerInterface::CreateInstance getDefaultInWorkerCreator() { @@ -584,6 +586,11 @@ class StreamWrapper { if (s) return s->setConnectedDevices(devices); return ndk::ScopedAStatus::ok(); } + ndk::ScopedAStatus bluetoothParametersUpdated() { + auto s = mStream.lock(); + if (s) return s->bluetoothParametersUpdated(); + return ndk::ScopedAStatus::ok(); + } private: std::weak_ptr mStream; @@ -612,6 +619,14 @@ class Streams { } return ndk::ScopedAStatus::ok(); } + ndk::ScopedAStatus bluetoothParametersUpdated() { + bool isOk = true; + for (auto& it : mStreams) { + if (!it.second.bluetoothParametersUpdated().isOk()) isOk = false; + } + return isOk ? ndk::ScopedAStatus::ok() + : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } private: // Maps port ids and port config ids to streams. Multimap because a port diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h index b9c5ea9bbd..c2f8c1d75b 100644 --- a/audio/aidl/default/include/core-impl/StreamBluetooth.h +++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h @@ -19,15 +19,20 @@ #include #include +#include +#include +#include + #include "core-impl/DevicePortProxy.h" +#include "core-impl/Module.h" #include "core-impl/Stream.h" namespace aidl::android::hardware::audio::core { class StreamBluetooth : public StreamCommonImpl { public: - StreamBluetooth(StreamContext* context, const Metadata& metadata); - + StreamBluetooth(StreamContext* context, const Metadata& metadata, + Module::BtProfileHandles&& btHandles); // Methods of 'DriverInterface'. ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; @@ -44,6 +49,7 @@ class StreamBluetooth : public StreamCommonImpl { ndk::ScopedAStatus prepareToClose() override; const ConnectedDevices& getConnectedDevices() const override; ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override; + ndk::ScopedAStatus bluetoothParametersUpdated() override; private: // Audio Pcm Config @@ -52,7 +58,8 @@ class StreamBluetooth : public StreamCommonImpl { const ::aidl::android::media::audio::common::AudioFormatDescription mFormat; const size_t mFrameSizeBytes; const bool mIsInput; - + const std::weak_ptr mBluetoothA2dp; + const std::weak_ptr mBluetoothLe; size_t mPreferredDataIntervalUs; size_t mPreferredFrameCount; @@ -72,7 +79,8 @@ class StreamInBluetooth final : public StreamIn, public StreamBluetooth { StreamInBluetooth( StreamContext&& context, const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, - const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones, + Module::BtProfileHandles&& btHandles); private: void onClose(StreamDescriptor::State) override { defaultOnClose(); } @@ -88,7 +96,8 @@ class StreamOutBluetooth final : public StreamOut, public StreamBluetooth { StreamContext&& context, const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& - offloadInfo); + offloadInfo, + Module::BtProfileHandles&& btHandles); private: void onClose(StreamDescriptor::State) override { defaultOnClose(); } diff --git a/audio/aidl/default/include/core-impl/StreamSwitcher.h b/audio/aidl/default/include/core-impl/StreamSwitcher.h index 2cb847080c..3086ef98ae 100644 --- a/audio/aidl/default/include/core-impl/StreamSwitcher.h +++ b/audio/aidl/default/include/core-impl/StreamSwitcher.h @@ -129,6 +129,7 @@ class StreamSwitcher : virtual public StreamCommonInterface { ndk::ScopedAStatus setConnectedDevices( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) override; + ndk::ScopedAStatus bluetoothParametersUpdated() override; protected: // Since switching a stream requires closing down the current stream, StreamSwitcher @@ -187,6 +188,7 @@ class StreamSwitcher : virtual public StreamCommonInterface { std::optional mHwAvSyncId; std::vector mMissedParameters; std::vector> mEffects; + bool mBluetoothParametersUpdated = false; }; } // namespace aidl::android::hardware::audio::core From 827f2eb02b9b5d6f46408db7a9251ba7e88b1352 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Fri, 28 Jul 2023 16:53:43 +0000 Subject: [PATCH 089/152] Audio r_submix : Handle the usecase when no data is available to read. Bug: 290116295 Test: atest VtsHalAudioCoreTargetTest Change-Id: Ifd6706d593f890dd8ae148523a37177774c8ffd4 (cherry picked from commit 675cce24d6f117c730ad949eea76389c4a9922dd) Merged-In: Ifd6706d593f890dd8ae148523a37177774c8ffd4 --- .../default/r_submix/StreamRemoteSubmix.cpp | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 74dea53b3e..12839add2d 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -280,14 +280,18 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { size_t* actualFrameCount) { // about to read from audio source sp source = mCurrentRoute->getSource(); - if (source == nullptr) { - int readErrorCount = mCurrentRoute->notifyReadError(); - if (readErrorCount < kMaxReadErrorLogs) { - LOG(ERROR) - << __func__ - << ": no audio pipe yet we're trying to read! (not all errors will be logged)"; + if (source == nullptr || source->availableToRead() == 0) { + if (source == nullptr) { + int readErrorCount = mCurrentRoute->notifyReadError(); + if (readErrorCount < kMaxReadErrorLogs) { + LOG(ERROR) << __func__ + << ": no audio pipe yet we're trying to read! (not all errors will be " + "logged)"; + } else { + LOG(ERROR) << __func__ << ": Read errors " << readErrorCount; + } } else { - LOG(ERROR) << __func__ << ": Read errors " << readErrorCount; + LOG(INFO) << __func__ << ": no data to read yet, providing empty data"; } const size_t delayUs = static_cast( std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate)); @@ -344,11 +348,9 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { // recording (including this call): it's converted to usec and compared to how long we've been // recording for, which gives us how long we must wait to sync the projected recording time, and // the observed recording time. - static constexpr float kScaleFactor = .8f; - const size_t projectedVsObservedOffsetUs = - kScaleFactor * (static_cast(std::roundf((readCounterFrames * MICROS_PER_SECOND / - mStreamConfig.sampleRate) - - recordDurationUs.count()))); + const size_t projectedVsObservedOffsetUs = static_cast( + std::roundf((readCounterFrames * MICROS_PER_SECOND / mStreamConfig.sampleRate) - + recordDurationUs.count())); LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count() << " microseconds, will wait: " << projectedVsObservedOffsetUs << " microseconds"; From aa449835dc6c17cff588241026fd1d266e4eb8a1 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 2 Aug 2023 12:24:15 -0700 Subject: [PATCH 090/152] audio: Address comments from an internal review Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Change-Id: I2f636c77f67fdd8eeac70dd304848bf7f76db4e5 (cherry picked from commit 0faf3394254467f71d27dffc6cdba29a0bdf3e3e) Merged-In: I2f636c77f67fdd8eeac70dd304848bf7f76db4e5 --- audio/aidl/default/StreamSwitcher.cpp | 11 +++++++---- audio/aidl/default/alsa/Mixer.h | 2 +- audio/aidl/default/include/core-impl/StreamSwitcher.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/audio/aidl/default/StreamSwitcher.cpp b/audio/aidl/default/StreamSwitcher.cpp index ed4cc8afb2..8ba15a83e6 100644 --- a/audio/aidl/default/StreamSwitcher.cpp +++ b/audio/aidl/default/StreamSwitcher.cpp @@ -126,11 +126,10 @@ ndk::ScopedAStatus StreamSwitcher::removeEffect(const std::shared_ptr& LOG(ERROR) << __func__ << ": stream was closed"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } - for (auto it = mEffects.begin(); it != mEffects.end();) { + for (auto it = mEffects.begin(); it != mEffects.end(); ++it) { if ((*it)->asBinder() == in_effect->asBinder()) { - it = mEffects.erase(it); - } else { - ++it; + mEffects.erase(it); + break; } } return !mIsStubStream ? mStream->removeEffect(in_effect) : ndk::ScopedAStatus::ok(); @@ -201,6 +200,10 @@ ndk::ScopedAStatus StreamSwitcher::setConnectedDevices(const std::vectorinitInstance(nullptr); !status.isOk()) { + if (mIsStubStream) { + LOG(FATAL) << __func__ + << ": failed to initialize stub stream: " << status.getDescription(); + } // Need to close the current failed stream, and report an error. // Since we can't operate without a stream implementation, put a stub in. RETURN_STATUS_IF_ERROR(closeCurrentStream(false /*validateStreamState*/)); diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h index 78728c296e..8fba1e0753 100644 --- a/audio/aidl/default/alsa/Mixer.h +++ b/audio/aidl/default/alsa/Mixer.h @@ -72,7 +72,7 @@ class Mixer { std::mutex mMixerAccess; // The mixer object is owned by ALSA and will be released when the mixer is closed. struct mixer* const mMixer; - // `mMixerControls` will only be initialized in constructor. After that, it wil only be + // `mMixerControls` will only be initialized in constructor. After that, it will only be // read but not be modified. Each mixer_ctl object is owned by ALSA, it's life span is // the same as of the mixer itself. const Controls mMixerControls; diff --git a/audio/aidl/default/include/core-impl/StreamSwitcher.h b/audio/aidl/default/include/core-impl/StreamSwitcher.h index 3086ef98ae..5764ad6018 100644 --- a/audio/aidl/default/include/core-impl/StreamSwitcher.h +++ b/audio/aidl/default/include/core-impl/StreamSwitcher.h @@ -20,7 +20,7 @@ namespace aidl::android::hardware::audio::core { -// 'StreamSwitcher' is implementation of 'StreamCommonInterface' which allows +// 'StreamSwitcher' is an implementation of 'StreamCommonInterface' which allows // dynamically switching the underlying stream implementation based on currently // connected devices. This is achieved by replacing inheritance from // 'StreamCommonImpl' with owning an instance of it. StreamSwitcher must be From c6f2146a2e98e66f5e0935688bfd888377cf9836 Mon Sep 17 00:00:00 2001 From: Jeff Pu Date: Fri, 4 Aug 2023 13:41:37 +0000 Subject: [PATCH 091/152] Added temporary-lockout timer support Bug: 294096426 Test: Manual Change-Id: I7d11b28697021ee21abae7c01ff393e4154ee9a4 --- .../aidl/default/FakeFingerprintEngine.cpp | 26 +++++++++++++++++++ .../default/FakeFingerprintEngineSide.cpp | 4 +++ .../default/include/FakeFingerprintEngine.h | 12 +++++++++ .../include/FakeFingerprintEngineSide.h | 2 +- .../tests/FakeFingerprintEngineTest.cpp | 15 ++++++++++- 5 files changed, 57 insertions(+), 2 deletions(-) diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp index ec28846a6a..54076c88e3 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp @@ -385,6 +385,11 @@ void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb, cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */); return; } + clearLockout(cb); + isLockoutTimerAborted = true; +} + +void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) { FingerprintHalProperties::lockout(false); cb->onLockoutCleared(); mLockoutTracker.reset(); @@ -574,13 +579,34 @@ bool FakeFingerprintEngine::checkSensorLockout(ISessionCallback* cb) { if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) { LOG(ERROR) << "Fail: lockout permanent"; cb->onLockoutPermanent(); + isLockoutTimerAborted = true; return true; } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) { int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft(); LOG(ERROR) << "Fail: lockout timed " << timeLeft; cb->onLockoutTimed(timeLeft); + if (isLockoutTimerSupported && !isLockoutTimerStarted) startLockoutTimer(timeLeft, cb); return true; } return false; } + +void FakeFingerprintEngine::startLockoutTimer(int64_t timeout, ISessionCallback* cb) { + BEGIN_OP(0); + std::function action = + std::bind(&FakeFingerprintEngine::lockoutTimerExpired, this, std::placeholders::_1); + std::thread([timeout, action, cb]() { + std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); + action(cb); + }).detach(); + + isLockoutTimerStarted = true; +} +void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) { + if (!isLockoutTimerAborted) { + clearLockout(cb); + } + isLockoutTimerStarted = false; + isLockoutTimerAborted = false; +} } // namespace aidl::android::hardware::biometrics::fingerprint diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp index 6982072dc4..a78cdcdbce 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp @@ -27,6 +27,10 @@ using namespace ::android::fingerprint::virt; namespace aidl::android::hardware::biometrics::fingerprint { +FakeFingerprintEngineSide::FakeFingerprintEngineSide() : FakeFingerprintEngine() { + isLockoutTimerSupported = true; +} + SensorLocation FakeFingerprintEngineSide::defaultSensorLocation() { return SensorLocation{.sensorLocationX = defaultSensorLocationX, .sensorLocationY = defaultSensorLocationY, diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h index a06b786acd..2450115aaf 100644 --- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h +++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h @@ -114,8 +114,20 @@ class FakeFingerprintEngine { std::vector>& res); int32_t getRandomInRange(int32_t bound1, int32_t bound2); bool checkSensorLockout(ISessionCallback*); + void clearLockout(ISessionCallback* cb); FakeLockoutTracker mLockoutTracker; + + protected: + // lockout timer + void lockoutTimerExpired(ISessionCallback* cb); + bool isLockoutTimerSupported; + bool isLockoutTimerStarted; + bool isLockoutTimerAborted; + + public: + void startLockoutTimer(int64_t timeout, ISessionCallback* cb); + bool getLockoutTimerStarted() { return isLockoutTimerStarted; } }; } // namespace aidl::android::hardware::biometrics::fingerprint diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h index c2fc005ffc..67a3ebc467 100644 --- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h +++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h @@ -28,7 +28,7 @@ class FakeFingerprintEngineSide : public FakeFingerprintEngine { static constexpr int32_t defaultSensorLocationY = 600; static constexpr int32_t defaultSensorRadius = 150; - FakeFingerprintEngineSide() : FakeFingerprintEngine() {} + FakeFingerprintEngineSide(); ~FakeFingerprintEngineSide() {} virtual SensorLocation defaultSensorLocation() override; diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp index bc235a6c65..fe405f4110 100644 --- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp +++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp @@ -93,9 +93,13 @@ class TestSessionCallback : public BnSessionCallback { return ndk::ScopedAStatus::ok(); }; ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override { + mLockoutTimed = true; + return ndk::ScopedAStatus::ok(); + } + ndk::ScopedAStatus onLockoutCleared() override { + mLockoutCleared = true; return ndk::ScopedAStatus::ok(); } - ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); } Error mError = Error::UNKNOWN; @@ -110,6 +114,8 @@ class TestSessionCallback : public BnSessionCallback { bool mAuthenticateFailed = false; bool mAuthenticatorIdInvalidated = false; bool mLockoutPermanent = false; + bool mLockoutTimed = false; + bool mLockoutCleared = false; int mInteractionDetectedCount = 0; int32_t mLastAcquiredInfo = -1; int32_t mLastAcquiredVendorCode = -1; @@ -499,6 +505,13 @@ TEST_F(FakeFingerprintEngineTest, randomLatency) { ASSERT_TRUE(latencySet.size() > 95); } +TEST_F(FakeFingerprintEngineTest, lockoutTimer) { + mEngine.startLockoutTimer(200, mCallback.get()); + ASSERT_TRUE(mEngine.getLockoutTimerStarted()); + std::this_thread::sleep_for(std::chrono::milliseconds(210)); + ASSERT_FALSE(mEngine.getLockoutTimerStarted()); + ASSERT_TRUE(mCallback->mLockoutCleared); +} } // namespace aidl::android::hardware::biometrics::fingerprint int main(int argc, char** argv) { From 7ed9ce53397e6a280cb0998fccb6b694c395f877 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 3 Aug 2023 10:26:21 -0700 Subject: [PATCH 092/152] audio: Make renamings suggested by reviewers Rename DriverInterface::getPosition -> refinePosition. This reflects the fact that the driver may provide more precise position, however this is an optional operation. Rename StreamIn/Out::mContext -> mContextInstance. This is to emphasize that StreamIn/Out actually own the context and they hold the real context instance, not just a reference/pointer to it, like other classes involved in the inheritance chain. Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Change-Id: Id7159f9bf3ee020dc7cf594ec35f5d59d23d7e31 (cherry picked from commit 459b7331e9145ee7cd8d35b621996fb66412a2a9) Merged-In: Id7159f9bf3ee020dc7cf594ec35f5d59d23d7e31 --- audio/aidl/default/Stream.cpp | 10 +++++----- audio/aidl/default/alsa/StreamAlsa.cpp | 2 +- audio/aidl/default/bluetooth/StreamBluetooth.cpp | 4 ++-- audio/aidl/default/include/core-impl/Stream.h | 8 ++++---- audio/aidl/default/include/core-impl/StreamAlsa.h | 2 +- .../default/include/core-impl/StreamRemoteSubmix.h | 2 +- audio/aidl/default/r_submix/StreamRemoteSubmix.cpp | 7 +++---- audio/aidl/default/stub/StreamStub.cpp | 5 ++--- audio/aidl/default/usb/StreamUsb.cpp | 4 ++-- 9 files changed, 21 insertions(+), 23 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index c5b25d6047..7a617c9f9a 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -117,7 +117,7 @@ void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply, if (isConnected) { reply->observable.frames = mContext->getFrameCount(); reply->observable.timeNs = ::android::elapsedRealtimeNano(); - if (auto status = mDriver->getPosition(&reply->observable); status == ::android::OK) { + if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) { return; } } @@ -739,12 +739,12 @@ static std::map transformMicrophones( } // namespace StreamIn::StreamIn(StreamContext&& context, const std::vector& microphones) - : mContext(std::move(context)), mMicrophones(transformMicrophones(microphones)) { + : mContextInstance(std::move(context)), mMicrophones(transformMicrophones(microphones)) { LOG(DEBUG) << __func__; } void StreamIn::defaultOnClose() { - mContext.reset(); + mContextInstance.reset(); } ndk::ScopedAStatus StreamIn::getActiveMicrophones( @@ -800,12 +800,12 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector& in_channelGains } StreamOut::StreamOut(StreamContext&& context, const std::optional& offloadInfo) - : mContext(std::move(context)), mOffloadInfo(offloadInfo) { + : mContextInstance(std::move(context)), mOffloadInfo(offloadInfo) { LOG(DEBUG) << __func__; } void StreamOut::defaultOnClose() { - mContext.reset(); + mContextInstance.reset(); } ndk::ScopedAStatus StreamOut::updateOffloadMetadata( diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp index 00a7a8426b..1d22a607e5 100644 --- a/audio/aidl/default/alsa/StreamAlsa.cpp +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -108,7 +108,7 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea return ::android::OK; } -::android::status_t StreamAlsa::getPosition(StreamDescriptor::Position* position) { +::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) { if (mAlsaDeviceProxies.empty()) { LOG(FATAL) << __func__ << ": no input devices"; return ::android::NO_INIT; diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp index 8cb93e3cea..91a33c2f5d 100644 --- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp +++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp @@ -320,7 +320,7 @@ StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata const std::vector& microphones, Module::BtProfileHandles&& btProfileHandles) : StreamIn(std::move(context), microphones), - StreamBluetooth(&(StreamIn::mContext), sinkMetadata, std::move(btProfileHandles)) {} + StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {} ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones( std::vector* _aidl_return __unused) { @@ -333,6 +333,6 @@ StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context, const std::optional& offloadInfo, Module::BtProfileHandles&& btProfileHandles) : StreamOut(std::move(context), offloadInfo), - StreamBluetooth(&(StreamOut::mContext), sourceMetadata, std::move(btProfileHandles)) {} + StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {} } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 1ba35200d0..a2edb6f937 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -195,10 +195,10 @@ struct DriverInterface { virtual ::android::status_t start() = 0; virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) = 0; - // No need to implement 'getPosition' unless the driver can provide more precise + // No need to implement 'refinePosition' unless the driver can provide more precise // data than just total frame count. For example, the driver may correctly account // for any intermediate buffers. - virtual ::android::status_t getPosition(StreamDescriptor::Position* /*position*/) { + virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) { return ::android::OK; } virtual void shutdown() = 0; // This function is only called once. @@ -507,7 +507,7 @@ class StreamIn : virtual public StreamCommonInterface, public BnStreamIn { StreamIn(StreamContext&& context, const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); - StreamContext mContext; + StreamContext mContextInstance; const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones; }; @@ -552,7 +552,7 @@ class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& offloadInfo); - StreamContext mContext; + StreamContext mContextInstance; const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo; std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata; }; diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h index f98a922a5f..555b27a772 100644 --- a/audio/aidl/default/include/core-impl/StreamAlsa.h +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -41,7 +41,7 @@ class StreamAlsa : public StreamCommonImpl { ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; - ::android::status_t getPosition(StreamDescriptor::Position* position) override; + ::android::status_t refinePosition(StreamDescriptor::Position* position) override; void shutdown() override; protected: diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h index 74854c6037..94404a1c7e 100644 --- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -39,7 +39,7 @@ class StreamRemoteSubmix : public StreamCommonImpl { ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; - ::android::status_t getPosition(StreamDescriptor::Position* position) override; + ::android::status_t refinePosition(StreamDescriptor::Position* position) override; void shutdown() override; // Overridden methods of 'StreamCommonImpl', called on a Binder thread. diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 12839add2d..11838f8d95 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -184,7 +184,7 @@ void StreamRemoteSubmix::shutdown() { : outWrite(buffer, frameCount, actualFrameCount)); } -::android::status_t StreamRemoteSubmix::getPosition(StreamDescriptor::Position* position) { +::android::status_t StreamRemoteSubmix::refinePosition(StreamDescriptor::Position* position) { sp source = mCurrentRoute->getSource(); if (source == nullptr) { return ::android::NO_INIT; @@ -363,8 +363,7 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) - : StreamIn(std::move(context), microphones), - StreamSwitcher(&(StreamIn::mContext), sinkMetadata) {} + : StreamIn(std::move(context), microphones), StreamSwitcher(&mContextInstance, sinkMetadata) {} ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones( std::vector* _aidl_return) { @@ -405,7 +404,7 @@ StreamOutRemoteSubmix::StreamOutRemoteSubmix(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) : StreamOut(std::move(context), offloadInfo), - StreamSwitcher(&(StreamOut::mContext), sourceMetadata) {} + StreamSwitcher(&mContextInstance, sourceMetadata) {} StreamSwitcher::DeviceSwitchBehavior StreamOutRemoteSubmix::switchCurrentStream( const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp index 66f46059a4..9b6a759c65 100644 --- a/audio/aidl/default/stub/StreamStub.cpp +++ b/audio/aidl/default/stub/StreamStub.cpp @@ -120,11 +120,10 @@ void StreamStub::shutdown() { StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) - : StreamIn(std::move(context), microphones), StreamStub(&(StreamIn::mContext), sinkMetadata) {} + : StreamIn(std::move(context), microphones), StreamStub(&mContextInstance, sinkMetadata) {} StreamOutStub::StreamOutStub(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) - : StreamOut(std::move(context), offloadInfo), - StreamStub(&(StreamOut::mContext), sourceMetadata) {} + : StreamOut(std::move(context), offloadInfo), StreamStub(&mContextInstance, sourceMetadata) {} } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index 9684a871df..4efe0d8b42 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -85,7 +85,7 @@ std::vector StreamUsb::getDeviceProfiles() { StreamInUsb::StreamInUsb(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones) - : StreamIn(std::move(context), microphones), StreamUsb(&(StreamIn::mContext), sinkMetadata) {} + : StreamIn(std::move(context), microphones), StreamUsb(&mContextInstance, sinkMetadata) {} ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( std::vector* _aidl_return __unused) { @@ -96,7 +96,7 @@ ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo) : StreamOut(std::move(context), offloadInfo), - StreamUsb(&(StreamOut::mContext), sourceMetadata), + StreamUsb(&mContextInstance, sourceMetadata), mChannelCount(getChannelCount(getContext().getChannelLayout())) {} ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { From 4f339476d34e0179a52f8c34e502033d36342954 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 24 Jul 2023 14:51:36 -0700 Subject: [PATCH 093/152] audio: Implement the major functionality of the primary CF HAL Core HAL changes: 1. Add StreamPrimary implemented via StreamAlsa. 2. Align the configuration with the HIDL HAL. 3. Fix position retrieval vs. standby call. 4. Fix sleeps in StreamAlsa. VTS changes: 1. Use several bursts for stream I/O test scenarios that check observable position increase. This is because the position may not be available until a couple of transfers have been made. 2. Do not require position increase for the scenarios that do not make several bursts. As specified above, the position may not have been increased for the ALSA case. Whereas, using multiple bursts in all scenarios will increase test time, and make the state machine transitions graph more complicated. 3. Hook up the test config file to shut down audioserver during VTS tests, fix the test config file. Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest Test: compare APM dumps for AIDL vs. HIDL Change-Id: I85271564c664fa40008d60e82b32eaa66a99c68f (cherry picked from commit cf824f65c807c4dd2ae0a278e97b2e9fe0ee29fd) Merged-In: I85271564c664fa40008d60e82b32eaa66a99c68f --- audio/aidl/default/Android.bp | 2 + audio/aidl/default/Configuration.cpp | 139 ++++++------- audio/aidl/default/ModulePrimary.cpp | 10 +- audio/aidl/default/Stream.cpp | 57 +++++- audio/aidl/default/alsa/StreamAlsa.cpp | 32 ++- audio/aidl/default/alsa/Utils.cpp | 10 +- audio/aidl/default/alsa/Utils.h | 1 + audio/aidl/default/include/core-impl/Stream.h | 22 +++ .../default/include/core-impl/StreamAlsa.h | 2 + .../default/include/core-impl/StreamPrimary.h | 84 ++++++++ .../default/include/core-impl/StreamStub.h | 1 + .../default/include/core-impl/StreamUsb.h | 5 +- audio/aidl/default/primary/PrimaryMixer.cpp | 29 +++ audio/aidl/default/primary/PrimaryMixer.h | 42 ++++ audio/aidl/default/primary/StreamPrimary.cpp | 186 ++++++++++++++++++ audio/aidl/default/stub/StreamStub.cpp | 15 +- audio/aidl/default/usb/StreamUsb.cpp | 12 +- audio/aidl/vts/Android.bp | 1 + .../vts/VtsHalAudioCoreModuleTargetTest.cpp | 154 +++++++++------ audio/aidl/vts/VtsHalAudioCoreTargetTest.xml | 5 + 20 files changed, 637 insertions(+), 172 deletions(-) create mode 100644 audio/aidl/default/include/core-impl/StreamPrimary.h create mode 100644 audio/aidl/default/primary/PrimaryMixer.cpp create mode 100644 audio/aidl/default/primary/PrimaryMixer.h create mode 100644 audio/aidl/default/primary/StreamPrimary.cpp diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index b6cfc1329c..8596466738 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -85,6 +85,8 @@ cc_library { "bluetooth/DevicePortProxy.cpp", "bluetooth/ModuleBluetooth.cpp", "bluetooth/StreamBluetooth.cpp", + "primary/PrimaryMixer.cpp", + "primary/StreamPrimary.cpp", "r_submix/ModuleRemoteSubmix.cpp", "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index 385ffbf9fc..d05d214557 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -136,7 +136,7 @@ static AudioRoute createRoute(const std::vector& sources, const Audio // Device ports: // * "Speaker", OUT_SPEAKER, default // - no profiles specified -// * "Built-in Mic", IN_MICROPHONE, default +// * "Built-In Mic", IN_MICROPHONE, default // - no profiles specified // * "Telephony Tx", OUT_TELEPHONY_TX // - no profiles specified @@ -148,45 +148,34 @@ static AudioRoute createRoute(const std::vector& sources, const Audio // Mix ports: // * "primary output", PRIMARY, 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream -// - profile MP3; MONO, STEREO; 44100, 48000 -// * "primary input", 2 max open, 2 max active streams -// - profile PCM 16-bit; MONO, STEREO, FRONT_BACK; -// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK; -// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +// * "primary input", 1 max open, 1 max active stream +// - profile PCM 16-bit; MONO, STEREO; +// 8000, 11025, 16000, 32000, 44100, 48000 // * "telephony_tx", 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 // * "telephony_rx", 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 // * "fm_tuner", 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 -// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 // // Routes: -// "primary out", "compressed offload" -> "Speaker" -// "Built-in Mic" -> "primary input" -// "telephony_tx" -> "Telephony Tx" +// "primary out" -> "Speaker" +// "Built-In Mic" -> "primary input" // "Telephony Rx" -> "telephony_rx" +// "telephony_tx" -> "Telephony Tx" // "FM Tuner" -> "fm_tuner" // // Initial port configs: -// * "Speaker" device port: PCM 24-bit; STEREO; 48000 -// * "Built-in Mic" device port: PCM 24-bit; MONO; 48000 -// * "Telephony Tx" device port: PCM 24-bit; MONO; 48000 -// * "Telephony Rx" device port: PCM 24-bit; MONO; 48000 -// * "FM Tuner" device port: PCM 24-bit; STEREO; 48000 +// * "Speaker" device port: PCM 16-bit; STEREO; 48000 +// * "Built-In Mic" device port: PCM 16-bit; MONO; 48000 +// * "Telephony Tx" device port: PCM 16-bit; MONO; 48000 +// * "Telephony Rx" device port: PCM 16-bit; MONO; 48000 +// * "FM Tuner" device port: PCM 16-bit; STEREO; 48000 // std::unique_ptr getPrimaryConfiguration() { static const Configuration configuration = []() { const std::vector standardPcmAudioProfiles = { createProfile(PcmType::INT_16_BIT, - {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, - {8000, 11025, 16000, 32000, 44100, 48000}), - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, {8000, 11025, 16000, 32000, 44100, 48000})}; Configuration c; @@ -199,17 +188,17 @@ std::unique_ptr getPrimaryConfiguration() { 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE)); c.ports.push_back(speakerOutDevice); c.initialConfigs.push_back( - createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_24_BIT, + createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false, createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0))); AudioPort micInDevice = - createPort(c.nextPortId++, "Built-in Mic", 0, true, + createPort(c.nextPortId++, "Built-In Mic", 0, true, createDeviceExt(AudioDeviceType::IN_MICROPHONE, 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE)); c.ports.push_back(micInDevice); c.initialConfigs.push_back( - createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_24_BIT, + createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, true, createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0))); @@ -219,7 +208,7 @@ std::unique_ptr getPrimaryConfiguration() { c.ports.push_back(telephonyTxOutDevice); c.initialConfigs.push_back( createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id, - PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, + PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0))); AudioPort telephonyRxInDevice = @@ -228,14 +217,14 @@ std::unique_ptr getPrimaryConfiguration() { c.ports.push_back(telephonyRxInDevice); c.initialConfigs.push_back( createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id, - PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, + PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0, true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0))); AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true, createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)); c.ports.push_back(fmTunerInDevice); c.initialConfigs.push_back( - createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_24_BIT, + createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true, createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0))); @@ -249,30 +238,12 @@ std::unique_ptr getPrimaryConfiguration() { standardPcmAudioProfiles.end()); c.ports.push_back(primaryOutMix); - AudioPort compressedOffloadOutMix = - createPort(c.nextPortId++, "compressed offload", - makeBitPositionFlagMask({AudioOutputFlags::DIRECT, - AudioOutputFlags::COMPRESS_OFFLOAD, - AudioOutputFlags::NON_BLOCKING}), - false, createPortMixExt(1, 1)); - compressedOffloadOutMix.profiles.push_back( - createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG, - {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, - {44100, 48000})); - c.ports.push_back(compressedOffloadOutMix); - AudioPort primaryInMix = - createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2)); + createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(1, 1)); primaryInMix.profiles.push_back( createProfile(PcmType::INT_16_BIT, - {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, - AudioChannelLayout::LAYOUT_FRONT_BACK}, - {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); - primaryInMix.profiles.push_back( - createProfile(PcmType::INT_24_BIT, - {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, - AudioChannelLayout::LAYOUT_FRONT_BACK}, - {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {8000, 11025, 16000, 32000, 44100, 48000})); c.ports.push_back(primaryInMix); AudioPort telephonyTxOutMix = @@ -296,10 +267,10 @@ std::unique_ptr getPrimaryConfiguration() { standardPcmAudioProfiles.end()); c.ports.push_back(fmTunerInMix); - c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, speakerOutDevice)); + c.routes.push_back(createRoute({primaryOutMix}, speakerOutDevice)); c.routes.push_back(createRoute({micInDevice}, primaryInMix)); - c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice)); c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix)); + c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice)); c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix)); c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end()); @@ -320,15 +291,15 @@ std::unique_ptr getPrimaryConfiguration() { // // Device ports: // * "Remote Submix Out", OUT_SUBMIX -// - profile PCM 24-bit; STEREO; 48000 +// - profile PCM 16-bit; STEREO; 48000 // * "Remote Submix In", IN_SUBMIX -// - profile PCM 24-bit; STEREO; 48000 +// - profile PCM 16-bit; STEREO; 48000 // // Mix ports: -// * "r_submix output", stream count unlimited -// - profile PCM 24-bit; STEREO; 48000 -// * "r_submix input", stream count unlimited -// - profile PCM 24-bit; STEREO; 48000 +// * "r_submix output", 1 max open, 1 max active stream +// - profile PCM 16-bit; STEREO; 48000 +// * "r_submix input", 1 max open, 1 max active stream +// - profile PCM 16-bit; STEREO; 48000 // // Routes: // "r_submix output" -> "Remote Submix Out" @@ -345,27 +316,27 @@ std::unique_ptr getRSubmixConfiguration() { createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0, AudioDeviceDescription::CONNECTION_VIRTUAL)); rsubmixOutDevice.profiles.push_back( - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixOutDevice); AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true, createDeviceExt(AudioDeviceType::IN_SUBMIX, 0)); rsubmixInDevice.profiles.push_back( - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixInDevice); // Mix ports AudioPort rsubmixOutMix = - createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0)); + createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(1, 1)); rsubmixOutMix.profiles.push_back( - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixOutMix); AudioPort rsubmixInMix = - createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0)); + createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(1, 1)); rsubmixInMix.profiles.push_back( - createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixInMix); c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice)); @@ -483,7 +454,7 @@ std::unique_ptr getUsbConfiguration() { // - profile MP3; MONO, STEREO; 44100, 48000 // * "test input", 2 max open, 2 max active streams // - profile PCM 24-bit; MONO, STEREO, FRONT_BACK; -// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +// 8000, 11025, 16000, 22050, 32000, 44100, 48000 // // Routes: // "test output", "compressed offload" -> "Test Out" @@ -543,12 +514,12 @@ std::unique_ptr getStubConfiguration() { createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, AudioChannelLayout::LAYOUT_FRONT_BACK}, - {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); + {8000, 11025, 16000, 22050, 32000, 44100, 48000})); testInMIx.profiles.push_back( createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO, AudioChannelLayout::LAYOUT_FRONT_BACK}, - {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000})); + {8000, 11025, 16000, 22050, 32000, 44100, 48000})); c.ports.push_back(testInMIx); c.routes.push_back(createRoute({testOutMix, compressedOffloadOutMix}, testOutDevice)); @@ -566,7 +537,7 @@ std::unique_ptr getStubConfiguration() { // Device ports: // * "BT A2DP Out", OUT_DEVICE, CONNECTION_BT_A2DP // - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 -// * "BT A2DP Headphones", OUT_HEADSET, CONNECTION_BT_A2DP +// * "BT A2DP Headphones", OUT_HEADPHONE, CONNECTION_BT_A2DP // - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 // * "BT A2DP Speaker", OUT_SPEAKER, CONNECTION_BT_A2DP // - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000 @@ -597,13 +568,18 @@ std::unique_ptr getBluetoothConfiguration() { createPort(c.nextPortId++, "BT A2DP Out", 0, false, createDeviceExt(AudioDeviceType::OUT_DEVICE, 0, AudioDeviceDescription::CONNECTION_BT_A2DP)); + btOutDevice.profiles.insert(btOutDevice.profiles.begin(), standardPcmAudioProfiles.begin(), + standardPcmAudioProfiles.end()); c.ports.push_back(btOutDevice); c.connectedProfiles[btOutDevice.id] = standardPcmAudioProfiles; AudioPort btOutHeadphone = createPort(c.nextPortId++, "BT A2DP Headphones", 0, false, - createDeviceExt(AudioDeviceType::OUT_HEADSET, 0, + createDeviceExt(AudioDeviceType::OUT_HEADPHONE, 0, AudioDeviceDescription::CONNECTION_BT_A2DP)); + btOutHeadphone.profiles.insert(btOutHeadphone.profiles.begin(), + standardPcmAudioProfiles.begin(), + standardPcmAudioProfiles.end()); c.ports.push_back(btOutHeadphone); c.connectedProfiles[btOutHeadphone.id] = standardPcmAudioProfiles; @@ -611,6 +587,9 @@ std::unique_ptr getBluetoothConfiguration() { createPort(c.nextPortId++, "BT A2DP Speaker", 0, false, createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0, AudioDeviceDescription::CONNECTION_BT_A2DP)); + btOutSpeaker.profiles.insert(btOutSpeaker.profiles.begin(), + standardPcmAudioProfiles.begin(), + standardPcmAudioProfiles.end()); c.ports.push_back(btOutSpeaker); c.connectedProfiles[btOutSpeaker.id] = standardPcmAudioProfiles; @@ -623,20 +602,20 @@ std::unique_ptr getBluetoothConfiguration() { {createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})}); // Mix ports - AudioPort btInMix = - createPort(c.nextPortId++, "a2dp output", 0, true, createPortMixExt(1, 1)); - c.ports.push_back(btInMix); + AudioPort btOutMix = + createPort(c.nextPortId++, "a2dp output", 0, false, createPortMixExt(1, 1)); + c.ports.push_back(btOutMix); - AudioPort btHeadsetInMix = - createPort(c.nextPortId++, "hearing aid output", 0, true, createPortMixExt(1, 1)); - btHeadsetInMix.profiles.push_back(createProfile( + AudioPort btHearingOutMix = + createPort(c.nextPortId++, "hearing aid output", 0, false, createPortMixExt(1, 1)); + btHearingOutMix.profiles.push_back(createProfile( PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000})); - c.ports.push_back(btHeadsetInMix); + c.ports.push_back(btHearingOutMix); - c.routes.push_back(createRoute({btInMix}, btOutDevice)); - c.routes.push_back(createRoute({btInMix}, btOutHeadphone)); - c.routes.push_back(createRoute({btInMix}, btOutSpeaker)); - c.routes.push_back(createRoute({btHeadsetInMix}, btOutHearingAid)); + c.routes.push_back(createRoute({btOutMix}, btOutDevice)); + c.routes.push_back(createRoute({btOutMix}, btOutHeadphone)); + c.routes.push_back(createRoute({btOutMix}, btOutSpeaker)); + c.routes.push_back(createRoute({btHearingOutMix}, btOutHearingAid)); return c; }(); diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp index 29e81264ac..9919c7f6cc 100644 --- a/audio/aidl/default/ModulePrimary.cpp +++ b/audio/aidl/default/ModulePrimary.cpp @@ -21,7 +21,7 @@ #include #include "core-impl/ModulePrimary.h" -#include "core-impl/StreamStub.h" +#include "core-impl/StreamPrimary.h" #include "core-impl/Telephony.h" using aidl::android::hardware::audio::common::SinkMetadata; @@ -47,15 +47,15 @@ ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context, const SinkMetadata& sinkMetadata, const std::vector& microphones, std::shared_ptr* result) { - return createStreamInstance(result, std::move(context), sinkMetadata, - microphones); + return createStreamInstance(result, std::move(context), sinkMetadata, + microphones); } ndk::ScopedAStatus ModulePrimary::createOutputStream( StreamContext&& context, const SourceMetadata& sourceMetadata, const std::optional& offloadInfo, std::shared_ptr* result) { - return createStreamInstance(result, std::move(context), sourceMetadata, - offloadInfo); + return createStreamInstance(result, std::move(context), sourceMetadata, + offloadInfo); } } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 7a617c9f9a..196ab2ff7a 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -238,8 +238,8 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { break; case Tag::standby: if (mState == StreamDescriptor::State::IDLE) { + populateReply(&reply, mIsConnected); if (::android::status_t status = mDriver->standby(); status == ::android::OK) { - populateReply(&reply, mIsConnected); mState = StreamDescriptor::State::STANDBY; } else { LOG(ERROR) << __func__ << ": standby failed: " << status; @@ -492,8 +492,8 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { break; case Tag::standby: if (mState == StreamDescriptor::State::IDLE) { + populateReply(&reply, mIsConnected); if (::android::status_t status = mDriver->standby(); status == ::android::OK) { - populateReply(&reply, mIsConnected); mState = StreamDescriptor::State::STANDBY; } else { LOG(ERROR) << __func__ << ": standby failed: " << status; @@ -799,6 +799,32 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector& in_channelGains return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } +StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context) + : mChannelCount(getChannelCount(context->getChannelLayout())) {} + +ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector* _aidl_return) { + *_aidl_return = mHwGains; + LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamInHwGainHelper::setHwGainImpl(const std::vector& in_channelGains) { + LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains); + if (in_channelGains.size() != mChannelCount) { + LOG(ERROR) << __func__ + << ": channel count does not match stream channel count: " << mChannelCount; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + for (float gain : in_channelGains) { + if (gain < StreamIn::HW_GAIN_MIN || gain > StreamIn::HW_GAIN_MAX) { + LOG(ERROR) << __func__ << ": gain value out of range: " << gain; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + } + mHwGains = in_channelGains; + return ndk::ScopedAStatus::ok(); +} + StreamOut::StreamOut(StreamContext&& context, const std::optional& offloadInfo) : mContextInstance(std::move(context)), mOffloadInfo(offloadInfo) { LOG(DEBUG) << __func__; @@ -904,4 +930,31 @@ ndk::ScopedAStatus StreamOut::selectPresentation(int32_t in_presentationId, int3 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } +StreamOutHwVolumeHelper::StreamOutHwVolumeHelper(const StreamContext* context) + : mChannelCount(getChannelCount(context->getChannelLayout())) {} + +ndk::ScopedAStatus StreamOutHwVolumeHelper::getHwVolumeImpl(std::vector* _aidl_return) { + *_aidl_return = mHwVolumes; + LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamOutHwVolumeHelper::setHwVolumeImpl( + const std::vector& in_channelVolumes) { + LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes); + if (in_channelVolumes.size() != mChannelCount) { + LOG(ERROR) << __func__ + << ": channel count does not match stream channel count: " << mChannelCount; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + for (float volume : in_channelVolumes) { + if (volume < StreamOut::HW_VOLUME_MIN || volume > StreamOut::HW_VOLUME_MAX) { + LOG(ERROR) << __func__ << ": volume value out of range: " << volume; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + } + mHwVolumes = in_channelVolumes; + return ndk::ScopedAStatus::ok(); +} + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp index 1d22a607e5..0605d6f464 100644 --- a/audio/aidl/default/alsa/StreamAlsa.cpp +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #define LOG_TAG "AHAL_StreamAlsa" @@ -29,7 +30,9 @@ namespace aidl::android::hardware::audio::core { StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries) : StreamCommonImpl(context, metadata), + mBufferSizeFrames(getContext().getBufferSizeInFrames()), mFrameSizeBytes(getContext().getFrameSize()), + mSampleRate(getContext().getSampleRate()), mIsInput(isInput(metadata)), mConfig(alsa::getPcmConfig(getContext(), mIsInput)), mReadWriteRetries(readWriteRetries) {} @@ -39,17 +42,20 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea } ::android::status_t StreamAlsa::drain(StreamDescriptor::DrainMode) { - usleep(1000); + if (!mIsInput) { + static constexpr float kMicrosPerSecond = MICROS_PER_SECOND; + const size_t delayUs = static_cast( + std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate)); + usleep(delayUs); + } return ::android::OK; } ::android::status_t StreamAlsa::flush() { - usleep(1000); return ::android::OK; } ::android::status_t StreamAlsa::pause() { - usleep(1000); return ::android::OK; } @@ -59,6 +65,10 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea } ::android::status_t StreamAlsa::start() { + if (!mAlsaDeviceProxies.empty()) { + // This is a resume after a pause. + return ::android::OK; + } decltype(mAlsaDeviceProxies) alsaDeviceProxies; for (const auto& device : getDeviceProfiles()) { alsa::DeviceProxy proxy; @@ -71,8 +81,7 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea true /*require_exact_match*/); } else { proxy = alsa::openProxyForAttachedDevice( - device, const_cast(&mConfig.value()), - getContext().getBufferSizeInFrames()); + device, const_cast(&mConfig.value()), mBufferSizeFrames); } if (!proxy) { return ::android::NO_INIT; @@ -85,13 +94,13 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea ::android::status_t StreamAlsa::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) { + if (mAlsaDeviceProxies.empty()) { + LOG(FATAL) << __func__ << ": no opened devices"; + return ::android::NO_INIT; + } const size_t bytesToTransfer = frameCount * mFrameSizeBytes; unsigned maxLatency = 0; if (mIsInput) { - if (mAlsaDeviceProxies.empty()) { - LOG(FATAL) << __func__ << ": no input devices"; - return ::android::NO_INIT; - } // For input case, only support single device. proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer, mReadWriteRetries); @@ -110,9 +119,12 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea ::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) { if (mAlsaDeviceProxies.empty()) { - LOG(FATAL) << __func__ << ": no input devices"; + LOG(FATAL) << __func__ << ": no opened devices"; return ::android::NO_INIT; } + // Since the proxy can only count transferred frames since its creation, + // we override its counter value with ours and let it to correct for buffered frames. + alsa::resetTransferredFrames(mAlsaDeviceProxies[0], position->frames); if (mIsInput) { if (int ret = proxy_get_capture_position(mAlsaDeviceProxies[0].get(), &position->frames, &position->timeNs); diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp index 20f77978fd..9dcd024d1c 100644 --- a/audio/aidl/default/alsa/Utils.cpp +++ b/audio/aidl/default/alsa/Utils.cpp @@ -262,12 +262,14 @@ std::vector getSampleRatesFromProfile(const alsa_device_profile* profile) { } DeviceProxy makeDeviceProxy() { - return DeviceProxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) { + DeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) { if (proxy != nullptr) { proxy_close(proxy); delete proxy; } }); + memset(proxy.get(), 0, sizeof(alsa_device_proxy)); + return proxy; } DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile, @@ -334,6 +336,12 @@ std::optional readAlsaDeviceInfo(const DeviceProfile& devic return profile; } +void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) { + if (proxy != nullptr) { + proxy->transferred = frames; + } +} + AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) { return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription()); } diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h index 615e657064..37414b3d75 100644 --- a/audio/aidl/default/alsa/Utils.h +++ b/audio/aidl/default/alsa/Utils.h @@ -66,6 +66,7 @@ DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile, DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile, struct pcm_config* pcmConfig, bool requireExactMatch); std::optional readAlsaDeviceInfo(const DeviceProfile& deviceProfile); +void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames); ::aidl::android::media::audio::common::AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy); diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index a2edb6f937..e9fd6dfcc4 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -511,6 +511,17 @@ class StreamIn : virtual public StreamCommonInterface, public BnStreamIn { const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones; }; +class StreamInHwGainHelper { + protected: + explicit StreamInHwGainHelper(const StreamContext* context); + + ndk::ScopedAStatus getHwGainImpl(std::vector* _aidl_return); + ndk::ScopedAStatus setHwGainImpl(const std::vector& in_channelGains); + + const size_t mChannelCount; + std::vector mHwGains; +}; + class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { protected: void defaultOnClose(); @@ -557,6 +568,17 @@ class StreamOut : virtual public StreamCommonInterface, public BnStreamOut { std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata; }; +class StreamOutHwVolumeHelper { + protected: + explicit StreamOutHwVolumeHelper(const StreamContext* context); + + ndk::ScopedAStatus getHwVolumeImpl(std::vector* _aidl_return); + ndk::ScopedAStatus setHwVolumeImpl(const std::vector& in_channelVolumes); + + const size_t mChannelCount; + std::vector mHwVolumes; +}; + // The recommended way to create a stream instance. // 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or // 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'. diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h index 555b27a772..2c3b284448 100644 --- a/audio/aidl/default/include/core-impl/StreamAlsa.h +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -48,7 +48,9 @@ class StreamAlsa : public StreamCommonImpl { // Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty. virtual std::vector getDeviceProfiles() = 0; + const size_t mBufferSizeFrames; const size_t mFrameSizeBytes; + const int mSampleRate; const bool mIsInput; const std::optional mConfig; const int mReadWriteRetries; diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h new file mode 100644 index 0000000000..b3ddd0bd53 --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamPrimary.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "StreamAlsa.h" +#include "StreamSwitcher.h" + +namespace aidl::android::hardware::audio::core { + +class StreamPrimary : public StreamAlsa { + public: + StreamPrimary(StreamContext* context, const Metadata& metadata); + + protected: + std::vector getDeviceProfiles() override; + + const bool mIsInput; +}; + +class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper { + public: + friend class ndk::SharedRefBase; + StreamInPrimary( + StreamContext&& context, + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); + + private: + static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device); + + DeviceSwitchBehavior switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; + std::unique_ptr createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) override; + void onClose(StreamDescriptor::State) override { defaultOnClose(); } + + ndk::ScopedAStatus getHwGain(std::vector* _aidl_return) override; + ndk::ScopedAStatus setHwGain(const std::vector& in_channelGains) override; +}; + +class StreamOutPrimary final : public StreamOut, + public StreamSwitcher, + public StreamOutHwVolumeHelper { + public: + friend class ndk::SharedRefBase; + StreamOutPrimary(StreamContext&& context, + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo); + + private: + static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device); + + DeviceSwitchBehavior switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; + std::unique_ptr createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) override; + void onClose(StreamDescriptor::State) override { defaultOnClose(); } + + ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; + ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index a8a3fc4961..3857e0e75e 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -35,6 +35,7 @@ class StreamStub : public StreamCommonImpl { void shutdown() override; private: + const size_t mBufferSizeFrames; const size_t mFrameSizeBytes; const int mSampleRate; const bool mIsAsynchronous; diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 74e30ff97b..608f27d410 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -59,7 +59,7 @@ class StreamInUsb final : public StreamIn, public StreamUsb { override; }; -class StreamOutUsb final : public StreamOut, public StreamUsb { +class StreamOutUsb final : public StreamOut, public StreamUsb, public StreamOutHwVolumeHelper { public: friend class ndk::SharedRefBase; StreamOutUsb(StreamContext&& context, @@ -71,9 +71,6 @@ class StreamOutUsb final : public StreamOut, public StreamUsb { void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; - - const int mChannelCount; - std::vector mHwVolumes; }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/primary/PrimaryMixer.cpp b/audio/aidl/default/primary/PrimaryMixer.cpp new file mode 100644 index 0000000000..577d010f20 --- /dev/null +++ b/audio/aidl/default/primary/PrimaryMixer.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AHAL_PrimaryMixer" + +#include "PrimaryMixer.h" + +namespace aidl::android::hardware::audio::core::primary { + +// static +PrimaryMixer& PrimaryMixer::getInstance() { + static PrimaryMixer gInstance; + return gInstance; +} + +} // namespace aidl::android::hardware::audio::core::primary diff --git a/audio/aidl/default/primary/PrimaryMixer.h b/audio/aidl/default/primary/PrimaryMixer.h new file mode 100644 index 0000000000..3806428cfd --- /dev/null +++ b/audio/aidl/default/primary/PrimaryMixer.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +#include "alsa/Mixer.h" + +namespace aidl::android::hardware::audio::core::primary { + +class PrimaryMixer : public alsa::Mixer { + public: + static constexpr int kAlsaCard = 0; + static constexpr int kAlsaDevice = 0; + + static PrimaryMixer& getInstance(); + + private: + PrimaryMixer() : alsa::Mixer(kAlsaCard) {} +}; + +} // namespace aidl::android::hardware::audio::core::primary diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp new file mode 100644 index 0000000000..e01be8a3c6 --- /dev/null +++ b/audio/aidl/default/primary/StreamPrimary.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "AHAL_StreamPrimary" +#include +#include +#include + +#include "PrimaryMixer.h" +#include "core-impl/StreamPrimary.h" +#include "core-impl/StreamStub.h" + +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::media::audio::common::AudioDevice; +using aidl::android::media::audio::common::AudioDeviceDescription; +using aidl::android::media::audio::common::AudioDeviceType; +using aidl::android::media::audio::common::AudioOffloadInfo; +using aidl::android::media::audio::common::MicrophoneInfo; +using android::base::GetBoolProperty; + +namespace aidl::android::hardware::audio::core { + +StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata) + : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {} + +std::vector StreamPrimary::getDeviceProfiles() { + static const std::vector kBuiltInSource{ + alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard, + .device = primary::PrimaryMixer::kAlsaDevice, + .direction = PCM_IN, + .isExternal = false}}; + static const std::vector kBuiltInSink{ + alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard, + .device = primary::PrimaryMixer::kAlsaDevice, + .direction = PCM_OUT, + .isExternal = false}}; + return mIsInput ? kBuiltInSource : kBuiltInSink; +} + +StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata, + const std::vector& microphones) + : StreamIn(std::move(context), microphones), + StreamSwitcher(&mContextInstance, sinkMetadata), + StreamInHwGainHelper(&mContextInstance) {} + +bool StreamInPrimary::useStubStream(const AudioDevice& device) { + static const bool kSimulateInput = + GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false); + return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX || + device.type.type == AudioDeviceType::IN_FM_TUNER || + device.type.connection == AudioDeviceDescription::CONNECTION_BUS; +} + +StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { + LOG(DEBUG) << __func__; + if (devices.size() > 1) { + LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: " + << devices.size(); + return DeviceSwitchBehavior::UNSUPPORTED_DEVICES; + } + if (devices.empty() || useStubStream(devices[0]) == isStubStream()) { + return DeviceSwitchBehavior::USE_CURRENT_STREAM; + } + return DeviceSwitchBehavior::CREATE_NEW_STREAM; +} + +std::unique_ptr StreamInPrimary::createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) { + if (devices.empty()) { + LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream' + } + if (useStubStream(devices[0])) { + return std::unique_ptr( + new InnerStreamWrapper(context, metadata)); + } + return std::unique_ptr( + new InnerStreamWrapper(context, metadata)); +} + +ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector* _aidl_return) { + if (isStubStream()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + return getHwGainImpl(_aidl_return); +} + +ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector& in_channelGains) { + if (isStubStream()) { + LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + auto currentGains = mHwGains; + RETURN_STATUS_IF_ERROR(setHwGainImpl(in_channelGains)); + if (in_channelGains.size() < 1) { + LOG(FATAL) << __func__ << ": unexpected gain vector size: " << in_channelGains.size(); + } + if (auto status = primary::PrimaryMixer::getInstance().setMicGain(in_channelGains[0]); + !status.isOk()) { + mHwGains = currentGains; + return status; + } + return ndk::ScopedAStatus::ok(); +} + +StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata, + const std::optional& offloadInfo) + : StreamOut(std::move(context), offloadInfo), + StreamSwitcher(&mContextInstance, sourceMetadata), + StreamOutHwVolumeHelper(&mContextInstance) {} + +bool StreamOutPrimary::useStubStream(const AudioDevice& device) { + static const bool kSimulateOutput = + GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false); + return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX || + device.type.connection == AudioDeviceDescription::CONNECTION_BUS; +} + +StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { + LOG(DEBUG) << __func__; + if (devices.size() > 1) { + LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: " + << devices.size(); + return DeviceSwitchBehavior::UNSUPPORTED_DEVICES; + } + if (devices.empty() || useStubStream(devices[0]) == isStubStream()) { + return DeviceSwitchBehavior::USE_CURRENT_STREAM; + } + return DeviceSwitchBehavior::CREATE_NEW_STREAM; +} + +std::unique_ptr StreamOutPrimary::createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) { + if (devices.empty()) { + LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream' + } + if (useStubStream(devices[0])) { + return std::unique_ptr( + new InnerStreamWrapper(context, metadata)); + } + return std::unique_ptr( + new InnerStreamWrapper(context, metadata)); +} + +ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector* _aidl_return) { + if (isStubStream()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + return getHwVolumeImpl(_aidl_return); +} + +ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector& in_channelVolumes) { + if (isStubStream()) { + LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + auto currentVolumes = mHwVolumes; + RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes)); + if (auto status = primary::PrimaryMixer::getInstance().setVolumes(in_channelVolumes); + !status.isOk()) { + mHwVolumes = currentVolumes; + return status; + } + return ndk::ScopedAStatus::ok(); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp index 9b6a759c65..660a51e2e0 100644 --- a/audio/aidl/default/stub/StreamStub.cpp +++ b/audio/aidl/default/stub/StreamStub.cpp @@ -33,6 +33,7 @@ namespace aidl::android::hardware::audio::core { StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) : StreamCommonImpl(context, metadata), + mBufferSizeFrames(getContext().getBufferSizeInFrames()), mFrameSizeBytes(getContext().getFrameSize()), mSampleRate(getContext().getSampleRate()), mIsAsynchronous(!!getContext().getAsyncCallback()), @@ -40,7 +41,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) ::android::status_t StreamStub::init() { mIsInitialized = true; - usleep(500); return ::android::OK; } @@ -48,7 +48,16 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) if (!mIsInitialized) { LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; } - usleep(500); + if (!mIsInput) { + if (!mIsAsynchronous) { + static constexpr float kMicrosPerSecond = MICROS_PER_SECOND; + const size_t delayUs = static_cast( + std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate)); + usleep(delayUs); + } else { + usleep(500); + } + } return ::android::OK; } @@ -56,7 +65,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) if (!mIsInitialized) { LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; } - usleep(500); return ::android::OK; } @@ -64,7 +72,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata) if (!mIsInitialized) { LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver"; } - usleep(500); return ::android::OK; } diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp index 4efe0d8b42..b60b4fd020 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -18,14 +18,11 @@ #define LOG_TAG "AHAL_StreamUsb" #include - -#include #include #include "UsbAlsaMixerControl.h" #include "core-impl/StreamUsb.h" -using aidl::android::hardware::audio::common::getChannelCount; using aidl::android::hardware::audio::common::SinkMetadata; using aidl::android::hardware::audio::common::SourceMetadata; using aidl::android::media::audio::common::AudioDevice; @@ -97,14 +94,15 @@ StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& source const std::optional& offloadInfo) : StreamOut(std::move(context), offloadInfo), StreamUsb(&mContextInstance, sourceMetadata), - mChannelCount(getChannelCount(getContext().getChannelLayout())) {} + StreamOutHwVolumeHelper(&mContextInstance) {} ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { - *_aidl_return = mHwVolumes; - return ndk::ScopedAStatus::ok(); + return getHwVolumeImpl(_aidl_return); } ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector& in_channelVolumes) { + auto currentVolumes = mHwVolumes; + RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes)); // Avoid using mConnectedDeviceProfiles because it requires a lock. for (const auto& device : getConnectedDevices()) { if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput); @@ -114,11 +112,11 @@ ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector& in_channe !result.isOk()) { LOG(ERROR) << __func__ << ": failed to set volume for device address=" << *deviceProfile; + mHwVolumes = currentVolumes; return result; } } } - mHwVolumes = in_channelVolumes; return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp index 852255d433..f7cf4cece3 100644 --- a/audio/aidl/vts/Android.bp +++ b/audio/aidl/vts/Android.bp @@ -55,6 +55,7 @@ cc_test { "VtsHalAudioCoreConfigTargetTest.cpp", "VtsHalAudioCoreModuleTargetTest.cpp", ], + test_config: "VtsHalAudioCoreTargetTest.xml", } cc_test { diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index 0012cd559e..b680373351 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -3189,10 +3189,17 @@ class StreamLogicDefaultDriver : public StreamLogicDriver { std::string mUnexpectedTransition; }; -enum { NAMED_CMD_NAME, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS }; +enum { + NAMED_CMD_NAME, + NAMED_CMD_DELAY_MS, + NAMED_CMD_STREAM_TYPE, + NAMED_CMD_CMDS, + NAMED_CMD_VALIDATE_POS_INCREASE +}; enum class StreamTypeFilter { ANY, SYNC, ASYNC }; using NamedCommandSequence = - std::tuple>; + std::tuple, bool /*validatePositionIncrease*/>; enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ }; using StreamIoTestParameters = std::tuple; @@ -3236,10 +3243,14 @@ class AudioStreamIo : public AudioCoreModuleBase, ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get())); const auto& commandsAndStates = std::get(std::get(GetParam())); + const bool validatePositionIncrease = + std::get(std::get(GetParam())); if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates, + validatePositionIncrease)); } else { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates, + validatePositionIncrease)); } if (isNonBlocking) { // Also try running the same sequence with "aosp.forceTransientBurst" set. @@ -3250,11 +3261,11 @@ class AudioStreamIo : public AudioCoreModuleBase, if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/) .isOk()) { if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE( - RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1( + portConfig, commandsAndStates, validatePositionIncrease)); } else { - ASSERT_NO_FATAL_FAILURE( - RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2( + portConfig, commandsAndStates, validatePositionIncrease)); } } } else if (!IOTraits::is_input) { @@ -3267,11 +3278,11 @@ class AudioStreamIo : public AudioCoreModuleBase, if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/) .isOk()) { if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE( - RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1( + portConfig, commandsAndStates, validatePositionIncrease)); } else { - ASSERT_NO_FATAL_FAILURE( - RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates)); + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2( + portConfig, commandsAndStates, validatePositionIncrease)); } } } @@ -3285,11 +3296,13 @@ class AudioStreamIo : public AudioCoreModuleBase, // Set up a patch first, then open a stream. void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig, - std::shared_ptr commandsAndStates) { + std::shared_ptr commandsAndStates, + bool validatePositionIncrease) { auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort( IOTraits::is_input, portConfig); ASSERT_FALSE(devicePorts.empty()); auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]); + SCOPED_TRACE(devicePortConfig.toString()); WithAudioPatch patch(IOTraits::is_input, portConfig, devicePortConfig); ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get())); @@ -3307,14 +3320,17 @@ class AudioStreamIo : public AudioCoreModuleBase, EXPECT_FALSE(worker.hasError()) << worker.getError(); EXPECT_EQ("", driver.getUnexpectedStateTransition()); if (ValidateObservablePosition(devicePortConfig)) { - EXPECT_TRUE(driver.hasObservablePositionIncrease()); + if (validatePositionIncrease) { + EXPECT_TRUE(driver.hasObservablePositionIncrease()); + } EXPECT_FALSE(driver.hasRetrogradeObservablePosition()); } } // Open a stream, then set up a patch for it. void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig, - std::shared_ptr commandsAndStates) { + std::shared_ptr commandsAndStates, + bool validatePositionIncrease) { WithStream stream(portConfig); ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames)); StreamLogicDefaultDriver driver(commandsAndStates, @@ -3326,6 +3342,7 @@ class AudioStreamIo : public AudioCoreModuleBase, IOTraits::is_input, portConfig); ASSERT_FALSE(devicePorts.empty()); auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]); + SCOPED_TRACE(devicePortConfig.toString()); WithAudioPatch patch(IOTraits::is_input, stream.getPortConfig(), devicePortConfig); ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get())); @@ -3336,7 +3353,9 @@ class AudioStreamIo : public AudioCoreModuleBase, EXPECT_FALSE(worker.hasError()) << worker.getError(); EXPECT_EQ("", driver.getUnexpectedStateTransition()); if (ValidateObservablePosition(devicePortConfig)) { - EXPECT_TRUE(driver.hasObservablePositionIncrease()); + if (validatePositionIncrease) { + EXPECT_TRUE(driver.hasObservablePositionIncrease()); + } EXPECT_FALSE(driver.hasRetrogradeObservablePosition()); } } @@ -3673,22 +3692,28 @@ std::shared_ptr makeBurstCommands(bool isSync) { using State = StreamDescriptor::State; auto d = std::make_unique(); StateDag::Node last = d->makeFinalNode(State::ACTIVE); - StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, last); + // Use a couple of bursts to ensure that the driver starts reporting the position. + StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last); + StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, active2); StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active); if (!isSync) { // Allow optional routing via the TRANSFERRING state on bursts. - active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last)); + active2.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last)); + active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active2)); idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active)); } d->makeNode(State::STANDBY, kStartCommand, idle); return std::make_shared(std::move(d)); } static const NamedCommandSequence kReadSeq = - std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true)); + std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true), + true /*validatePositionIncrease*/); static const NamedCommandSequence kWriteSyncSeq = - std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true)); + std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true), + true /*validatePositionIncrease*/); static const NamedCommandSequence kWriteAsyncSeq = - std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false)); + std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false), + true /*validatePositionIncrease*/); std::shared_ptr makeAsyncDrainCommands(bool isInput) { using State = StreamDescriptor::State; @@ -3716,11 +3741,12 @@ std::shared_ptr makeAsyncDrainCommands(bool isInput) { } return std::make_shared(std::move(d)); } -static const NamedCommandSequence kWriteDrainAsyncSeq = - std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false)); -static const NamedCommandSequence kDrainInSeq = std::make_tuple( - std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true)); +static const NamedCommandSequence kWriteDrainAsyncSeq = std::make_tuple( + std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeAsyncDrainCommands(false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kDrainInSeq = + std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ANY, + makeAsyncDrainCommands(true), false /*validatePositionIncrease*/); std::shared_ptr makeDrainOutCommands(bool isSync) { using State = StreamDescriptor::State; @@ -3740,10 +3766,12 @@ std::shared_ptr makeDrainOutCommands(bool isSync) { d->makeNode(State::STANDBY, kStartCommand, idle); return std::make_shared(std::move(d)); } -static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple( - std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true)); -static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple( - std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false)); +static const NamedCommandSequence kDrainOutSyncSeq = + std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true), + false /*validatePositionIncrease*/); +static const NamedCommandSequence kDrainOutAsyncSeq = + std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ASYNC, + makeDrainOutCommands(false), false /*validatePositionIncrease*/); std::shared_ptr makeDrainPauseOutCommands(bool isSync) { using State = StreamDescriptor::State; @@ -3764,12 +3792,12 @@ std::shared_ptr makeDrainPauseOutCommands(bool isSync) { d->makeNode(State::STANDBY, kStartCommand, idle); return std::make_shared(std::move(d)); } -static const NamedCommandSequence kDrainPauseOutSyncSeq = - std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::SYNC, makeDrainPauseOutCommands(true)); -static const NamedCommandSequence kDrainPauseOutAsyncSeq = - std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeDrainPauseOutCommands(false)); +static const NamedCommandSequence kDrainPauseOutSyncSeq = std::make_tuple( + std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC, + makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kDrainPauseOutAsyncSeq = std::make_tuple( + std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/); // This sequence also verifies that the capture / presentation position is not reset on standby. std::shared_ptr makeStandbyCommands(bool isInput, bool isSync) { @@ -3810,13 +3838,15 @@ std::shared_ptr makeStandbyCommands(bool isInput, bool isSync) { } return std::make_shared(std::move(d)); } -static const NamedCommandSequence kStandbyInSeq = std::make_tuple( - std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false)); -static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple( - std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true)); -static const NamedCommandSequence kStandbyOutAsyncSeq = - std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeStandbyCommands(false, false)); +static const NamedCommandSequence kStandbyInSeq = + std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::ANY, + makeStandbyCommands(true, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kStandbyOutSyncSeq = + std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::SYNC, + makeStandbyCommands(false, true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kStandbyOutAsyncSeq = std::make_tuple( + std::string("Standby"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeStandbyCommands(false, false), false /*validatePositionIncrease*/); std::shared_ptr makePauseCommands(bool isInput, bool isSync) { using State = StreamDescriptor::State; @@ -3851,13 +3881,15 @@ std::shared_ptr makePauseCommands(bool isInput, bool isSync) { } return std::make_shared(std::move(d)); } -static const NamedCommandSequence kPauseInSeq = std::make_tuple( - std::string("Pause"), 0, StreamTypeFilter::ANY, makePauseCommands(true, false)); -static const NamedCommandSequence kPauseOutSyncSeq = std::make_tuple( - std::string("Pause"), 0, StreamTypeFilter::SYNC, makePauseCommands(false, true)); -static const NamedCommandSequence kPauseOutAsyncSeq = - std::make_tuple(std::string("Pause"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makePauseCommands(false, false)); +static const NamedCommandSequence kPauseInSeq = + std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY, + makePauseCommands(true, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kPauseOutSyncSeq = + std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC, + makePauseCommands(false, true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple( + std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makePauseCommands(false, false), false /*validatePositionIncrease*/); std::shared_ptr makeFlushCommands(bool isInput, bool isSync) { using State = StreamDescriptor::State; @@ -3884,13 +3916,15 @@ std::shared_ptr makeFlushCommands(bool isInput, bool isSync) { } return std::make_shared(std::move(d)); } -static const NamedCommandSequence kFlushInSeq = std::make_tuple( - std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false)); -static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple( - std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true)); -static const NamedCommandSequence kFlushOutAsyncSeq = - std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeFlushCommands(false, false)); +static const NamedCommandSequence kFlushInSeq = + std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::ANY, + makeFlushCommands(true, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kFlushOutSyncSeq = + std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::SYNC, + makeFlushCommands(false, true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kFlushOutAsyncSeq = std::make_tuple( + std::string("Flush"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeFlushCommands(false, false), false /*validatePositionIncrease*/); std::shared_ptr makeDrainPauseFlushOutCommands(bool isSync) { using State = StreamDescriptor::State; @@ -3911,10 +3945,12 @@ std::shared_ptr makeDrainPauseFlushOutCommands(bool isSync) { } static const NamedCommandSequence kDrainPauseFlushOutSyncSeq = std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true)); + StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true), + false /*validatePositionIncrease*/); static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq = std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false)); + StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false), + false /*validatePositionIncrease*/); // Note, this isn't the "official" enum printer, it is only used to make the test name suffix. std::string PrintStreamFilterToString(StreamTypeFilter filter) { diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml index dfc10397f7..9d3adc1d0f 100644 --- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml +++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml @@ -25,6 +25,11 @@ - - android.hardware.gnss.visibility_control - 1 - - IGnssVisibilityControl - default - - - - android.hardware.gnss.measurement_corrections - 1 - - IMeasurementCorrectionsInterface - default - - android.hardware.graphics.allocator diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml index 04a4674ba7..67c21c8d81 100644 --- a/compatibility_matrices/compatibility_matrix.8.xml +++ b/compatibility_matrices/compatibility_matrix.8.xml @@ -230,22 +230,6 @@ default - - android.hardware.gnss.visibility_control - 1 - - IGnssVisibilityControl - default - - - - android.hardware.gnss.measurement_corrections - 1 - - IMeasurementCorrectionsInterface - default - - android.hardware.graphics.allocator 1-2 diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml index 10091fe1ec..a5b073fbe9 100644 --- a/compatibility_matrices/compatibility_matrix.9.xml +++ b/compatibility_matrices/compatibility_matrix.9.xml @@ -222,22 +222,6 @@ default - - android.hardware.gnss.visibility_control - 1 - - IGnssVisibilityControl - default - - - - android.hardware.gnss.measurement_corrections - 1 - - IMeasurementCorrectionsInterface - default - - android.hardware.graphics.allocator 1-2 From 6d24b2ff8753492267f25bfa2f4e2a1a2504b219 Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Fri, 28 Oct 2022 10:40:51 +0900 Subject: [PATCH 097/152] Disable verbose nlinterceptor log Causing problems for folks trying to read logs in b/287414933 - should have been disabled previously. Test: No verbose log on Cloud Android with Wi-Fi is turned on Bug: 256518068 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7df5c1c34538d1e051dc3df63fcba563e40713c8) Merged-In: I062e698b64114f139997cd24b16f90dd52048247 Change-Id: I062e698b64114f139997cd24b16f90dd52048247 --- wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp index ded9122a6f..e84a5cf817 100644 --- a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp +++ b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp @@ -28,7 +28,7 @@ namespace android::nlinterceptor { using namespace std::chrono_literals; static constexpr std::chrono::milliseconds kPollTimeout = 300ms; -static constexpr bool kSuperVerbose = true; +static constexpr bool kSuperVerbose = false; InterceptorRelay::InterceptorRelay(uint32_t nlFamily, uint32_t clientNlPid, const std::string& clientName) From 5faa489f93e4eccf8bee8aea7271098dc18caa4b Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 18 Aug 2023 17:25:47 +0900 Subject: [PATCH 098/152] Put authsecret example in VAPEX authsecret example instance is put in APEX. Bug: 296522705 Test: authsecret HAL starts from APEX in cuttlefish/goldfish Change-Id: I226fd57fb1ec5c8da98c07292431df055e6078d7 --- authsecret/aidl/default/Android.bp | 50 ++++++++++++++++- ...oid.hardware.authsecret-service.example.rc | 2 +- .../com.android.hardware.authsecret.avbpubkey | Bin 0 -> 1032 bytes .../com.android.hardware.authsecret.pem | 52 ++++++++++++++++++ .../com.android.hardware.authsecret.pk8 | Bin 0 -> 2374 bytes .../com.android.hardware.authsecret.x509.pem | 34 ++++++++++++ authsecret/aidl/default/file_contexts | 3 + authsecret/aidl/default/manifest.json | 4 ++ .../compatibility_matrix.9.xml | 2 +- 9 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 authsecret/aidl/default/com.android.hardware.authsecret.avbpubkey create mode 100644 authsecret/aidl/default/com.android.hardware.authsecret.pem create mode 100644 authsecret/aidl/default/com.android.hardware.authsecret.pk8 create mode 100644 authsecret/aidl/default/com.android.hardware.authsecret.x509.pem create mode 100644 authsecret/aidl/default/file_contexts create mode 100644 authsecret/aidl/default/manifest.json diff --git a/authsecret/aidl/default/Android.bp b/authsecret/aidl/default/Android.bp index 7ce83fd9ea..7e6e48b572 100644 --- a/authsecret/aidl/default/Android.bp +++ b/authsecret/aidl/default/Android.bp @@ -26,16 +26,60 @@ package { cc_binary { name: "android.hardware.authsecret-service.example", relative_install_path: "hw", - init_rc: ["android.hardware.authsecret-service.example.rc"], - vintf_fragments: ["android.hardware.authsecret-service.example.xml"], vendor: true, srcs: [ "service.cpp", "AuthSecret.cpp", ], shared_libs: [ + "libbinder_ndk", + "liblog", + ], + static_libs: [ "android.hardware.authsecret-V1-ndk", "libbase", - "libbinder_ndk", + ], + stl: "c++_static", +} + +prebuilt_etc { + name: "android.hardware.authsecret-service.example.rc", + src: "android.hardware.authsecret-service.example.rc", + installable: false, +} + +prebuilt_etc { + name: "android.hardware.authsecret-service.example.xml", + src: "android.hardware.authsecret-service.example.xml", + sub_dir: "vintf", + installable: false, +} + +apex_key { + name: "com.android.hardware.authsecret.key", + public_key: "com.android.hardware.authsecret.avbpubkey", + private_key: "com.android.hardware.authsecret.pem", +} + +android_app_certificate { + name: "com.android.hardware.authsecret.certificate", + certificate: "com.android.hardware.authsecret", +} + +apex { + name: "com.android.hardware.authsecret", + manifest: "manifest.json", + file_contexts: "file_contexts", + key: "com.android.hardware.authsecret.key", + certificate: ":com.android.hardware.authsecret.certificate", + updatable: false, + vendor: true, + + binaries: [ + "android.hardware.authsecret-service.example", + ], + prebuilts: [ + "android.hardware.authsecret-service.example.rc", // init_rc + "android.hardware.authsecret-service.example.xml", // vintf_fragments ], } diff --git a/authsecret/aidl/default/android.hardware.authsecret-service.example.rc b/authsecret/aidl/default/android.hardware.authsecret-service.example.rc index fef6e2401e..9f51837575 100644 --- a/authsecret/aidl/default/android.hardware.authsecret-service.example.rc +++ b/authsecret/aidl/default/android.hardware.authsecret-service.example.rc @@ -1,4 +1,4 @@ -service vendor.authsecret_default /vendor/bin/hw/android.hardware.authsecret-service.example +service vendor.authsecret_default /apex/com.android.hardware.authsecret/bin/hw/android.hardware.authsecret-service.example class hal user hsm group hsm diff --git a/authsecret/aidl/default/com.android.hardware.authsecret.avbpubkey b/authsecret/aidl/default/com.android.hardware.authsecret.avbpubkey new file mode 100644 index 0000000000000000000000000000000000000000..2fb5f0b61ad11acd971c3a5d8af2e374fbf8a070 GIT binary patch literal 1032 zcmV+j1o!&@01yC0Se6~6lDbvpD_+2=x*X~t(1{xb5G}YUQ?Urd*CZI}RmJ`P&{@rk z)94^C}>wgJY$WkDj$DupK+L@b3-@f5J7vp|re`=)~^GIt!6HEvu@ z(8F$B6&|)6B$Sp0hTqHhVRkIZR7Cn5#0z6fAt=v6anVCYtIYXedU4=!a9c6LZ!6}f z0q7u}AUhAZ5NPDeS~gW%Xuw?ls?tPK>MkW|hoPv+$TVh7ev42zR20dec}_zJ7vkd` zl-dBDr}eC|CPIC)HTNHRox!3k3ct#XvhvNM){Xjt7%na?+frOU%IF6oK0eMyiLHAE z6fbSH@!jN7gcnAUzq`I9WQG7K@&QnGJl~_q;KBpTB5&GVO^)z^ys(1K*3Du$q#N6DHa_=-)E>k-VRKu|cf}+S zFA4nLHa=J2Q)bV@ehdCHdM0w)3ro3R8tc->(uY^!Cv6ibA%?%%{CO!%PmnF^8kBYg z5!s2kx3n2Ynb|Ws#)oQzGTHL&sIC11@0>4APUTuoVCKO$Yz~yA4vAvY@75@3Ua4@d@Vn@GMtz1LBUgn}S zzP-p^HzUg`CXr6P0~q7i&OGEIx|hWFoQ8XcyYxwk$3<-P^ZhECoG1EO%8~a4&{*6V zL`Y%k$?nORvCsK&mLYz<%LOlzaX8ddsc#ChF1k$$@4^O zq-zl7U>kp7sE-0lf#yD?_o_s<(Z{iq@u1FcX%E<-N%sgE3I$*p2^PnKi_ANvH{5VL zxTXgX?v7-yEtUX*y+{n6zij)m)q5^^W(L+Ekw|tJ`XkOM85v1IxKA9#2tg|$bv+9};yB+lK2-1SZJQE}F$kRt^*MGeaOD?VW^ zfI4i30SWhwApz zoPJY)W)ROi-fnP?%G!QiUk?mW&I+M4Ezt`j>M!6F-T9sqlj>2a=HG#RjJvJx>gHZz zYFWQM4X#J2%z Co&7@q literal 0 HcmV?d00001 diff --git a/authsecret/aidl/default/com.android.hardware.authsecret.pem b/authsecret/aidl/default/com.android.hardware.authsecret.pem new file mode 100644 index 0000000000..644868c9a6 --- /dev/null +++ b/authsecret/aidl/default/com.android.hardware.authsecret.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCkkrpV5StewKq6 +HOog0IkbBRAtuChTsQjE1yQY6VXF/f/QWc2L0++pe0PTNzuKJZuqD05tgLYBxsFl +QSLMKoUnGkQshVHxFLCls0CQo/umgygydxyVNW5cTdDDbl0VHrYcJJSWBobfy/hh +dizJVET6HMQLY0shKM9CcdFDRqvM+WB6ceBxcFsxwm8r5qcB6CCeIDsPuBBo5Mpa +NlVbaMBc/qrSRFLqLiVph6Goycg0Zk5+i1A4VBTJoHlOQwgX4uMdlNoAnaf1rLIm +Qn2zNfcfeZ3BoiwKv8qMsvLNotaN+oIYLi4t21JcPsroByI+Ps5Gia17BhQvbbXx +3eRShBn6/YcxcMQmCPoN5JbqeyzcE9f0grh3I8ubf1+ZAW0dL2r6QRM6uo6T4Jf7 +BFiMVB0RjTzfo8ngwgPLIm/aXU2O8IG8sILO1s1iOaQb23E2PveF1B7EOmFzW8x3 +xSQQLwn83zY+V+BTZs/Dfgv+M3omctsLS7lgGuvSx9KHV+EnbRMoIYa/2fx5KUxP +kC3rGpR2BRHZibm3tBlHmdkzOsaHaoQy2fLtqK39Au+cL05O5VpOYObBN2wOlKUO +iWLS79YoaWAKUZtZKwQNu1jpmK0OMgCeC13QSTz2AuPgL6XEuCUpcmblX3KMsu5w +MK79Yke/V61cQ71e5qI0vr3IXjcjywIDAQABAoICAAYZ0GGNyNFO6CVVHBLSWDrR +sbtYJ9qOZgpSBWsM/1qDI4AYTCfiV/Ca+rUyR3lEEqS3w4sIqfaf5Rx5US5rZxs/ +fIZ//L0orLG/1uVlxtbx5sQUKVGYtPokAli0VywIwuyBKKb1H/vc5lzKkjd2ccYp +2dSoPilBB4npiT3quUS0e/CeFxltdlv+XrusZcWK0ua5wCbBho406RF2ESz90Z/A +6xk3YjF/O3DRj9sfe9YBcuh7BqLH7ytYURbnIj4scYnvsjMypP7VA5eqgFlr5zjZ ++9CpT+OoH3yex6R65GRIBJmb4KdfiYqU41W9qfXPwzrXMMCuRYJKmWOZe7TZY9Mc +V46jaDgLgKxe+mI4CLi2auKFE4KL8x68KSqa22y2dEjWwBPiT7If6v0ZL4CiAy9n +SNHFaceMY3l485vaZEtXxusRB/UGDZnAXr9NqBVm4YVAfOaEnJNDSqvYefM5iyOG +yQZ7dCXS9Ey4JvVlceA6mybj2JSx20QS2wN/tcyZjWsjM0f/sIHAJRS6KhEqCIfX +4L8d5nXJ1wvnBFvcfboSERkPOTQsuipsvn9uj8Zs9QWNYYRSyleptL+ce8fBqed6 +9ryErCuB9lpVTjUsOiaIibtGdePleQb10club1B/4vsgPl5wvTPRNCTmpOCP3pSf +Rei2x4z1VGFOBwd3MiTtAoIBAQDiQCsK87Zs8E5cwc0CqeMWstWHvJLTkj2B42OI +Zrbr6ByRixuLpWgVWtJJLKbLXPN83wl8eksv3+Ba+yi17uafhXX7M1O5RlOzvTHt +bbFPeysB3KEmNt96dRDRKYY3z0KHJxCRWKKZjZjp8Usf3TuKi9Xbque8o2n1LKKB +KANRC4xtHmUesl6d4S4iAfIkq5/nA4ocuJ2qd/2t3nc6yhPPRrP9+4sUPYdqBEUz +ds9isqt5erUybstCoHRgsEwWo/9ew8Dyj1TCIDTSqRt1/0QnEVm77bgBrA8P66HI +KKFVoo/MLQSw5V+CDZwTJNlPQwrG9tyrSkcMFgLSRzi+7d/3AoIBAQC6Nm5Ztiad +zm/1jM89uHmvedimKCKKG6+Eom5D96PduP76uRr65s6Usn0QCZ4Jvou0xnbtCP1K +lzVI1+v6EiIQyWX0y1bd0UJDdyYo4Ck2nqOh0vgw+cBO70faV50J5QA2mS/wFdw0 +PvykQpPYGiIfv1MMHWA+rPDzMtf1uUQ18vzzN7RaZll88pletC7mc7qgBaucQVvB +/qzOZSwhiaSSvXS1sFKfkqLqpJ3x9748D74MIwDD2i3fRxxfqPcgrG3B7xxIKVgd +CYoFjeC9inZbnwvPmtaKzROJknsuJA21s/ckkSiWJJbjbyymVc1hWNhoMbtSPopa +OOJ7u695Ls3NAoIBADtRE3fVmXhKMGFFNhiCrdTfoffqSpxJdPK+yPOT6lVDD2ph +DCG6heVDYGpq2HfssLGGUBhgf6HXkhyISI4aSkB8Xwgy1rp2Y6915McYwSnTYt0k +GOPJ8yFJ29TajCPJpOmGJmPU1xxm8TY0WrvJ5rhWHQVwcz0Tos3ym9A8y1HOM0zQ +cTZxETlXNh8YX4GZtVx9oxIQnNV6i/mvn5a8MCFhqgLmlfoCf6Qd5n6toYWAzlAV +CbhlL8kSBDDtR6WP7X3M2KM/TLtwcijgySBQgm+zrtEEa/+UOoa0AkBV1qZ67jRb +gSVXnYidRNQIDykmrIapZgVKfgH/K1Ix9gCooNUCggEAeSMzwnS2xm4nc2w43YQG +1VrEz8LIRWQhWH16kgilt3XDmkOVA6fmt+EtbqNzBg/JPr7lWupALKgVZ9/fiX0G +YDlEdG1bg03Ad7cpQeohpYCqHnnqL6IpsrAC5E2ewXMSInKhNuRhrjNTk2AkYa8O +h+ylD/qERAGpdeybhSUS9K2wVGDmmPCAQsJnd65r3EtpGvTVYP87vAX7UQGMJf0u +7K8HH7Mm7Nwt08tnXKO4Q8ZR8f9LXh2vPdM66Bg5PC4v8LumgGM1CR7NhTN5ApTy +zkO3IUUvUHh8v0BlleyqZow+uLEd4B7Jcgc+2q5yv2NW1OGVZLl+s5bR74B3dLQ3 ++QKCAQBtxqTUKaRE/g+paQByORt0mFuXhO5UyfEBpg6l7+aUS4wTGMeKKDCFjTME +lDjEK7eiAAOgN3AJYQ+r6831pm3hg6DG5lpxTKUuz2eMqMHk3LVlDFkH6BZF3Jxg +XxWP1Abi88hK3nnbuGrt6rlUxvJRdWaJcF5nXybJzPMpvzPcDjAg5fCT11vZQsRl +piAO6NjAECwUOaBHSHPvIXO9fWu4zY03rhg9px+dkutydSJ/6B3jq33q1CzHDQMd +bklkBBrLu9inpuvETbhVK6IWP2zMHzdViR58M+xd5rg2E3GBQePyd6mjOB+7p7Gd +hUHo4XX1/r2CDceZTmOjaZP/MQOJ +-----END PRIVATE KEY----- diff --git a/authsecret/aidl/default/com.android.hardware.authsecret.pk8 b/authsecret/aidl/default/com.android.hardware.authsecret.pk8 new file mode 100644 index 0000000000000000000000000000000000000000..1453366b27a558f0c9b3535716b522c681dd9965 GIT binary patch literal 2374 zcmV-M3Ay$#f(b$b0RS)!1_>&LNQUwEHHuzC;|Zh0)heo0N3fI_t>e~ zHECheSH`7hi!$K+Fef=oxvh~tm?~qrt#inEdl*q?vFf@Q?r?tEZCU9Y3)j_1{9x6D zzC~AVMZk z=b6b!)nXNhmv;h(g> zTXx5r)n?<_xFg$Um=DYuV^4NtG#_mLZrXx$ZROtf+NIjPsqpwSVR&1Vr-5}f`0a^UK{VZb0|4pBtQzBG*C~u1t z5EYV#eXl8^0A-9}P-`vgBVNW{M5S#VUBKr2hTw3+ozq2^0cP`)s@)1hs2dOqS}I=<|M7`8poP?uR`>q z5cgbbQ;kiqy_+Wc7`~v|z2&e2AUDhkLX=n_)~=1nYJ5`F2d^2PX!m0Ul;7H_a_}4d zMZ|3cK1I9;6m$p&tpHGd#h71jyCL?3DZ}^mZZ>Gw(7e|Yx_>4aOX3?pEK1{=0}vwM zG)7&#zZwg?rPh=f-|)ZBjP)@!A(M{pO~c<7%709mzz03=tn>~Dopl?PmoBc`=#q2a z$^IVEEVyz`%eWelJf%~4ICzx%Pcf2Qi|cu&*N$&gDihBPPWWr#A2nG^c4{+W7ourY?cs|F`5L3?8V>%!=}RRsQICmNN4Lka z8!#ynt#?VBdd8uKXVktWfxJgCk0+c?8aqHhpZu)pxTX&2DmYXJ=AcbFL{Zm4E3iCQ zA0@Bd#PT-XVc|Jt)^_FdHo?avCBzNs$^@UqkocWw7X_7-;|x6mn{}@*nB>-Vs(V=W zi0ibl->5c5niIS;+V!({twtEE0WNKSo$I+~M9~57l+popZ)X5m0sx+~_wCSNH@Z^z ze%@`ixtmxc)*I*Rs+pFjQY!o+MPPoU=JnqH4=yR!Epd@X5=x~4f&l>l-LJQT%7>*Y zaKJce`#}_cx_?OthroRpmaXAM4eLa!?vd$e`EK{!?og}8LNiY<+rR;%jxboxv_?bX zwuoYCRnds)+g~%RmR(*6Yz^`7tF>1(vJt6ncHxm+!$rivwspPYU$(2~b2t%jWvV8j zq?EjzC@F+xP51jmvGMZA$;SjJc`8_=YqrFvkI~NLT7~2-UK>3Ld%B>2M>;6MKT{c@ z4itm&HncX)^I-ikv}hU}`lY6}|MM5lXikOH$U?tlyXWbS?idAx#T#{33^Hb7zc4?< zh$?y$%lYa|ddZ76s`!hL;yrZm%Bg0)hbmAoNBkNg>f- zy9km8OS_p94BFzoO-VYWv+^D-gWYZr=(XDWeFQ7%N}4DUJ^%T)WF>2yXu9-6}4~?7yGzW1=5o8=*peDL!Fx(`U(0Q{jb|X+buF0kT%sbZ&BTbM z3xKg!qJj-0k5y6vZ~!8;W4-+&$*3k!#;ZcQuy3pgOL!^)lUei)F}8RLfzss_!-3iu znM-?anAQ_mB=l*Y&!8^Ipt#k6nXUc6|6ZSDr{#mbclbl7WzdNk0)hbn0HgGej-}^_ znn>k=Q?SLuIc#4uPhTBZ=hc}gAb?ojV1ACNlHH@ zdI@p)2bc`*YquFh2!izP)twsqGWu(k;#!`8X7_o3p3t>Q{SF;ZNCDwI;|d75Vu3tb<`V!J9v;kl%R^-PtxyumC(Hi zjC=r|WdYd+7A8UEIy+sFX?U4v3|Z3O*&*@|f04B|&9d8`pt^41Lxq2Z2Ugm@m?MsbNet+9K*w$8_o-5mOOjR z<5~W>@`HY3JK!U-C;0!Iv{V8#f12u9nE|3cnS@>r6}5n^+2z`J{{1zaLE;p*P+$h1 zN|p0NDTg<7Z@~|We5af3W=-!89XkE#RGz!r@-mCPjK#oR@9Fywq>g^hem2NKb@XAN sHu{aFdW$T|d)>IW5ba-qVLY*NLIIS(+Hy6#h&n^~Xn>=A$vDutGjcDKnE(I) literal 0 HcmV?d00001 diff --git a/authsecret/aidl/default/com.android.hardware.authsecret.x509.pem b/authsecret/aidl/default/com.android.hardware.authsecret.x509.pem new file mode 100644 index 0000000000..71fe854ef3 --- /dev/null +++ b/authsecret/aidl/default/com.android.hardware.authsecret.x509.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF4zCCA8sCFH8r8uUt7ZiBGNZm/OxNbzMI34N3MA0GCSqGSIb3DQEBCwUAMIGs +MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91 +bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi +MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEoMCYGA1UEAwwfY29t +LmFuZHJvaWQuaGFyZHdhcmUuYXV0aHNlY3JldDAgFw0yMzA4MTgwNzA3MDFaGA80 +NzYxMDcxNDA3MDcwMVowgawxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y +bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw +DgYDVQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQu +Y29tMSgwJgYDVQQDDB9jb20uYW5kcm9pZC5oYXJkd2FyZS5hdXRoc2VjcmV0MIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1+ml99ip2TVpYdJXxqVnizLg +/DAnOUy5rZE+mCpjua1zyHl7GFFnseq6GO5wftptWekcC9fVSPxg1YS+RVduRcNz +rt3mCsJ60DexaHrElITc1GCC1vzyt9cg6UtmdYg+OXSPlfWZE2T7OLfGWrhU56El +IFt1eQDu5RDBOHZ2/N30KmKXv3yhpdl5un/kaC6q6p1PPih0aYXT2PrHsyN17wBl +smhhpWNg/OAzFhWKwFcSTLMCOAI+pjqWKqXmjQ1awBly+lLAtHEBxxEUDMD6Z4lv +2OGftL9bdseb1Wbj2bgj22bkfwWj5Yu77ilz5H27aLxQouQsmSfBkVgLq6seQMzd +ovg+MOFb9iyWgcWkGg7eKdSzjfzCKQ/d2GOxEqwGofEYUOxYM1+a0Fnb7vUtgT/v +I4tJCgXxAMFtsYGySC+gBhNx7vqLfo/8gtcZjJL6PRtRJ2V7hF9x3xKFa2/6qOLn +UD/R5z+uwzaEqom+AmmmKNdWtn58nBns7EGq/3KVPcb7CSi9Xf6CCJiV+AmRaBSx +2CtLt1fBX46LM3bV+iw7ZFAYAAXE3j6FgpM/PlozQjl61TuomHQP1ILmu/988tiF +FMbuRH6mI0u4VOkDBUg9lxmjr0uAVmysWmzkRrAKydzedsuG5WG6hy2ZcD+lCV05 +JzvE6pB65OaIEPB5cMECAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAozFo1vOIy/Js +/EU5oRtSGSIoWCNIn7EYQ68jVHQk2ZhklVH2jW+6WVGmreOjPz5iWeDb0fC4KVtH +MPXJ1Vd+GfvDysrnW5mDBzlI1O2xv/BWYeHt+RFWghhH/NFHaTQqDJpdOZXMZM4F +dwFefxLchcXftE9jihHJXJ4k0cxC03Kpd0caZE7b67W1YQdJhU9mZx6CP1A3MdWU +f48QIsmHgejkihtGNDRheBRzNdpHPhdOjYIWhOeAHh/xnm7PVZBMXmZeNW7MrAS0 ++lN99r7Xj3eqtSdrMrrob845PWYsATA/a8ouUuTT7812fl8tZx69xb8wV5hNztDj +srOxxJbjt1uwcSp67f2K91D97CQuMMPnOt1oFEXT+5QtLEiybXKfkshwO7VVDoIg +owMLoKIiA2Xr+rZn7CEBeTrqQuRJfJEI+k/49zg2zWQIKGQAz8iaO0l95Hk5kPTE +A5i9qxhn0UqC6a4Dkj8ybQOACzVA06IsbbYdprfzURQHjcUiSrEzjrwWxkkX/9El +Z0CJAtkXx4pMxo5s6zt26ZPC3cxWB7aageWSC4xDbKuQP5VCNVg1nWymg6nF4Xk9 +d7n7yvSNH6fAZrpmZo7o7CBxCb4QN8j7TpyuaPd7nzyCyR6aGbh7fz8xksukvj6w +ZSbAAy5uw4hyUwTTpyPyw+qQxI7O/PU= +-----END CERTIFICATE----- diff --git a/authsecret/aidl/default/file_contexts b/authsecret/aidl/default/file_contexts new file mode 100644 index 0000000000..8e79f26c6d --- /dev/null +++ b/authsecret/aidl/default/file_contexts @@ -0,0 +1,3 @@ +(/.*)? u:object_r:vendor_file:s0 +/etc(/.*)? u:object_r:vendor_configs_file:s0 +/bin/hw/android\.hardware\.authsecret-service\.example u:object_r:hal_authsecret_default_exec:s0 \ No newline at end of file diff --git a/authsecret/aidl/default/manifest.json b/authsecret/aidl/default/manifest.json new file mode 100644 index 0000000000..ad5a45b444 --- /dev/null +++ b/authsecret/aidl/default/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "com.android.hardware.authsecret", + "version": 1 +} diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml index 4ba49f4d47..bb401ddbd7 100644 --- a/compatibility_matrices/compatibility_matrix.9.xml +++ b/compatibility_matrices/compatibility_matrix.9.xml @@ -52,7 +52,7 @@ default - + android.hardware.authsecret 1 From ada622499bb253e93c69795d1cec800075500241 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Mon, 21 Aug 2023 14:59:08 +0900 Subject: [PATCH 099/152] Mark uwb HAL as updatable-via-apex The AOSP implementation of UWB HAL will be packaged in APEX. Bug: 296487624 Test: m Change-Id: I89004f6064fdd3ffae13e64b051208e136a03ac1 --- compatibility_matrices/compatibility_matrix.9.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml index 4ba49f4d47..7b52d1e3c7 100644 --- a/compatibility_matrices/compatibility_matrix.9.xml +++ b/compatibility_matrices/compatibility_matrix.9.xml @@ -652,7 +652,7 @@ default - + android.hardware.uwb 1 From 043b3a248d9ea692e7066902ffd43da5b6615f42 Mon Sep 17 00:00:00 2001 From: David Li Date: Thu, 10 Aug 2023 12:47:44 +0800 Subject: [PATCH 100/152] audio: Fix remote submix module device ports handling - remove the default address "0" for IN_SUBMIX and OUT_SUBMIX; - remove the profiles in the device port and assign profiles when connecting; - make remote submix input to use "virtual" connection type, same as the output; - fix ModuleConfig in VTS to avoid returning devices with virtual connections as "external devices" because they can actually be connected even when connection simulation is disabled; - fix TryConnectMissingDevice VTS test to disconnect the device if the operation has unexpectedly succeeded. Bug: 286914845 Bug: 294976817 Test: atest VtsHalAudioCoreTargetTest Change-Id: Ife11c9c356d1b5dc587d08cef47294e3b29f65c5 Merged-In: Ife11c9c356d1b5dc587d08cef47294e3b29f65c5 --- audio/aidl/default/Android.bp | 1 - audio/aidl/default/Configuration.cpp | 55 ++++++++++++------- .../include/core-impl/ModuleRemoteSubmix.h | 5 -- .../default/r_submix/ModuleRemoteSubmix.cpp | 55 +++++++------------ .../default/r_submix/RemoteSubmixUtils.cpp | 47 ---------------- .../aidl/default/r_submix/RemoteSubmixUtils.h | 30 ---------- audio/aidl/vts/ModuleConfig.cpp | 6 +- .../vts/VtsHalAudioCoreModuleTargetTest.cpp | 11 ++-- 8 files changed, 67 insertions(+), 143 deletions(-) delete mode 100644 audio/aidl/default/r_submix/RemoteSubmixUtils.cpp delete mode 100644 audio/aidl/default/r_submix/RemoteSubmixUtils.h diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 8596466738..bb8d76f8fc 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -88,7 +88,6 @@ cc_library { "primary/PrimaryMixer.cpp", "primary/StreamPrimary.cpp", "r_submix/ModuleRemoteSubmix.cpp", - "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", "r_submix/StreamRemoteSubmix.cpp", "stub/ModuleStub.cpp", diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index 0fbf55bb12..8e02e7dfa7 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -81,8 +81,6 @@ static AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags, deviceExt.device.address = "bottom"; } else if (devType == AudioDeviceType::IN_MICROPHONE_BACK && connection.empty()) { deviceExt.device.address = "back"; - } else if (devType == AudioDeviceType::IN_SUBMIX || devType == AudioDeviceType::OUT_SUBMIX) { - deviceExt.device.address = "0"; } deviceExt.device.type.connection = std::move(connection); deviceExt.flags = flags; @@ -291,15 +289,21 @@ std::unique_ptr getPrimaryConfiguration() { // // Device ports: // * "Remote Submix Out", OUT_SUBMIX -// - profile PCM 16-bit; STEREO; 48000 +// - no profiles specified // * "Remote Submix In", IN_SUBMIX -// - profile PCM 16-bit; STEREO; 48000 +// - no profiles specified // // Mix ports: -// * "r_submix output", 1 max open, 1 max active stream -// - profile PCM 16-bit; STEREO; 48000 -// * "r_submix input", 1 max open, 1 max active stream -// - profile PCM 16-bit; STEREO; 48000 +// * "r_submix output", unlimited max open, unlimited max active stream +// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 +// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 +// - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 +// - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 +// * "r_submix input", unlimited max open, unlimited max active stream +// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 +// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 +// - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 +// - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000 // // Routes: // "r_submix output" -> "Remote Submix Out" @@ -308,6 +312,19 @@ std::unique_ptr getPrimaryConfiguration() { std::unique_ptr getRSubmixConfiguration() { static const Configuration configuration = []() { Configuration c; + const std::vector standardPcmAudioProfiles{ + createProfile(PcmType::FLOAT_32_BIT, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {8000, 11025, 16000, 32000, 44100, 48000}), + createProfile(PcmType::INT_32_BIT, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {8000, 11025, 16000, 32000, 44100, 48000}), + createProfile(PcmType::INT_24_BIT, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {8000, 11025, 16000, 32000, 44100, 48000}), + createProfile(PcmType::INT_16_BIT, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {8000, 11025, 16000, 32000, 44100, 48000})}; // Device ports @@ -315,28 +332,26 @@ std::unique_ptr getRSubmixConfiguration() { createPort(c.nextPortId++, "Remote Submix Out", 0, false, createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0, AudioDeviceDescription::CONNECTION_VIRTUAL)); - rsubmixOutDevice.profiles.push_back( - createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); c.ports.push_back(rsubmixOutDevice); + c.connectedProfiles[rsubmixOutDevice.id] = standardPcmAudioProfiles; - AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true, - createDeviceExt(AudioDeviceType::IN_SUBMIX, 0)); - rsubmixInDevice.profiles.push_back( - createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + AudioPort rsubmixInDevice = + createPort(c.nextPortId++, "Remote Submix In", 0, true, + createDeviceExt(AudioDeviceType::IN_SUBMIX, 0, + AudioDeviceDescription::CONNECTION_VIRTUAL)); c.ports.push_back(rsubmixInDevice); + c.connectedProfiles[rsubmixInDevice.id] = standardPcmAudioProfiles; // Mix ports AudioPort rsubmixOutMix = - createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(1, 1)); - rsubmixOutMix.profiles.push_back( - createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0)); + rsubmixOutMix.profiles = standardPcmAudioProfiles; c.ports.push_back(rsubmixOutMix); AudioPort rsubmixInMix = - createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(1, 1)); - rsubmixInMix.profiles.push_back( - createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0)); + rsubmixInMix.profiles = standardPcmAudioProfiles; c.ports.push_back(rsubmixInMix); c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice)); diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h index e87be3d9d2..c4bf7b99c2 100644 --- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h @@ -26,8 +26,6 @@ class ModuleRemoteSubmix : public Module { private: // IModule interfaces - ndk::ScopedAStatus getTelephony(std::shared_ptr* _aidl_return) override; - ndk::ScopedAStatus getBluetooth(std::shared_ptr* _aidl_return) override; ndk::ScopedAStatus getMicMute(bool* _aidl_return) override; ndk::ScopedAStatus setMicMute(bool in_mute) override; @@ -49,9 +47,6 @@ class ModuleRemoteSubmix : public Module { const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources, const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks) override; - void onExternalDeviceConnectionChanged( - const ::aidl::android::media::audio::common::AudioPort& audioPort, - bool connected) override; ndk::ScopedAStatus onMasterMuteChanged(bool mute) override; ndk::ScopedAStatus onMasterVolumeChanged(float volume) override; }; diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp index 9be783758d..adea877be6 100644 --- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp @@ -19,8 +19,8 @@ #include #include +#include -#include "RemoteSubmixUtils.h" #include "core-impl/ModuleRemoteSubmix.h" #include "core-impl/StreamRemoteSubmix.h" @@ -33,18 +33,6 @@ using aidl::android::media::audio::common::MicrophoneInfo; namespace aidl::android::hardware::audio::core { -ndk::ScopedAStatus ModuleRemoteSubmix::getTelephony(std::shared_ptr* _aidl_return) { - *_aidl_return = nullptr; - LOG(DEBUG) << __func__ << ": returning null"; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus ModuleRemoteSubmix::getBluetooth(std::shared_ptr* _aidl_return) { - *_aidl_return = nullptr; - LOG(DEBUG) << __func__ << ": returning null"; - return ndk::ScopedAStatus::ok(); -} - ndk::ScopedAStatus ModuleRemoteSubmix::getMicMute(bool* _aidl_return __unused) { LOG(DEBUG) << __func__ << ": is not supported"; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); @@ -70,23 +58,26 @@ ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream( } ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort) { - LOG(VERBOSE) << __func__ << ": Profiles already populated by Configuration"; - for (auto profile : audioPort->profiles) { - for (auto channelMask : profile.channelMasks) { - if (!r_submix::isChannelMaskSupported(channelMask)) { - LOG(ERROR) << __func__ << ": the profile " << profile.name - << " has unsupported channel mask : " << channelMask.toString(); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - } - for (auto sampleRate : profile.sampleRates) { - if (!r_submix::isSampleRateSupported(sampleRate)) { - LOG(ERROR) << __func__ << ": the profile " << profile.name - << " has unsupported sample rate : " << sampleRate; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - } + // Find the corresponding mix port and copy its profiles. + std::vector routes; + // At this moment, the port has the same ID as the template port, see connectExternalDevice. + RETURN_STATUS_IF_ERROR(getAudioRoutesForAudioPort(audioPort->id, &routes)); + if (routes.empty()) { + LOG(ERROR) << __func__ << ": no routes found for the port " << audioPort->toString(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } + const auto& route = *routes.begin(); + AudioPort mixPort; + if (route.sinkPortId == audioPort->id) { + if (route.sourcePortIds.empty()) { + LOG(ERROR) << __func__ << ": invalid route " << route.toString(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + RETURN_STATUS_IF_ERROR(getAudioPort(*route.sourcePortIds.begin(), &mixPort)); + } else { + RETURN_STATUS_IF_ERROR(getAudioPort(route.sinkPortId, &mixPort)); + } + audioPort->profiles = mixPort.profiles; return ndk::ScopedAStatus::ok(); } @@ -106,12 +97,6 @@ ndk::ScopedAStatus ModuleRemoteSubmix::checkAudioPatchEndpointsMatch( return ndk::ScopedAStatus::ok(); } -void ModuleRemoteSubmix::onExternalDeviceConnectionChanged( - const ::aidl::android::media::audio::common::AudioPort& audioPort __unused, - bool connected __unused) { - LOG(DEBUG) << __func__ << ": do nothing and return"; -} - ndk::ScopedAStatus ModuleRemoteSubmix::onMasterMuteChanged(bool __unused) { LOG(DEBUG) << __func__ << ": is not supported"; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); diff --git a/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp b/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp deleted file mode 100644 index 2f5d17d44e..0000000000 --- a/audio/aidl/default/r_submix/RemoteSubmixUtils.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include "RemoteSubmixUtils.h" - -namespace aidl::android::hardware::audio::core::r_submix { - -bool isChannelMaskSupported(const AudioChannelLayout& channelMask) { - const static std::vector kSupportedChannelMask = { - AudioChannelLayout::make( - AudioChannelLayout::LAYOUT_MONO), - AudioChannelLayout::make( - AudioChannelLayout::LAYOUT_STEREO)}; - - if (std::find(kSupportedChannelMask.begin(), kSupportedChannelMask.end(), channelMask) != - kSupportedChannelMask.end()) { - return true; - } - return false; -} - -bool isSampleRateSupported(int sampleRate) { - const static std::vector kSupportedSampleRates = {8000, 11025, 12000, 16000, 22050, - 24000, 32000, 44100, 48000}; - - if (std::find(kSupportedSampleRates.begin(), kSupportedSampleRates.end(), sampleRate) != - kSupportedSampleRates.end()) { - return true; - } - return false; -} - -} // namespace aidl::android::hardware::audio::core::r_submix diff --git a/audio/aidl/default/r_submix/RemoteSubmixUtils.h b/audio/aidl/default/r_submix/RemoteSubmixUtils.h deleted file mode 100644 index 952a992659..0000000000 --- a/audio/aidl/default/r_submix/RemoteSubmixUtils.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -using aidl::android::media::audio::common::AudioChannelLayout; - -namespace aidl::android::hardware::audio::core::r_submix { - -bool isChannelMaskSupported(const AudioChannelLayout& channelMask); - -bool isSampleRateSupported(int sampleRate); - -} // namespace aidl::android::hardware::audio::core::r_submix diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp index 8c448a805e..7213034bcc 100644 --- a/audio/aidl/vts/ModuleConfig.cpp +++ b/audio/aidl/vts/ModuleConfig.cpp @@ -30,6 +30,7 @@ using namespace std::chrono_literals; using aidl::android::hardware::audio::common::isBitPositionFlagSet; using aidl::android::hardware::audio::core::IModule; using aidl::android::media::audio::common::AudioChannelLayout; +using aidl::android::media::audio::common::AudioDeviceDescription; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioEncapsulationMode; using aidl::android::media::audio::common::AudioFormatDescription; @@ -96,7 +97,10 @@ ModuleConfig::ModuleConfig(IModule* module) { } else { mAttachedSinkDevicePorts.insert(port.id); } - } else if (port.profiles.empty()) { + } else if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_VIRTUAL + // The "virtual" connection is used for remote submix which is a dynamic + // device but it can be connected and used w/o external hardware. + && port.profiles.empty()) { mExternalDevicePorts.insert(port.id); } } diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index b680373351..68e7151191 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -1627,14 +1627,17 @@ TEST_P(AudioCoreModule, TryConnectMissingDevice) { if (ports.empty()) { GTEST_SKIP() << "No external devices in the module."; } - AudioPort ignored; WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(*debug); doNotSimulateConnections.flags().simulateDeviceConnections = false; ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get())); for (const auto& port : ports) { - AudioPort portWithData = GenerateUniqueDeviceAddress(port); - EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored)) - << "static port " << portWithData.toString(); + AudioPort portWithData = GenerateUniqueDeviceAddress(port), connectedPort; + ScopedAStatus status = module->connectExternalDevice(portWithData, &connectedPort); + EXPECT_STATUS(EX_ILLEGAL_STATE, status) << "static port " << portWithData.toString(); + if (status.isOk()) { + EXPECT_IS_OK(module->disconnectExternalDevice(connectedPort.id)) + << "when disconnecting device port ID " << connectedPort.id; + } } } From c608187f2162979062a67ee6b55414e66924c530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kosi=C5=84ski?= Date: Sat, 19 Aug 2023 02:07:47 +0000 Subject: [PATCH 101/152] Add missing gRPC include. Othewise the header is not self contained and breaks when upgrading gRPC. Bug: 279548314 Test: presubmit (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3d3baed1bc85f8ddddb2764a5a09cd4d578419f0) Merged-In: Ife50863bd16eda6bc639261b1f91fdfcf48f6294 Change-Id: Ife50863bd16eda6bc639261b1f91fdfcf48f6294 --- automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h index 90588aa375..e740da7e5c 100644 --- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h @@ -24,6 +24,8 @@ #include "VehicleServer.grpc.pb.h" #include "VehicleServer.pb.h" +#include + #include #include #include From e284266e52e62e39a979da5c82d79dd4b5775155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gaffie?= Date: Tue, 1 Aug 2023 14:04:51 +0200 Subject: [PATCH 102/152] Audio: add system usage to audio policy engine schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 293917986 Test: m Signed-off-by: François Gaffie (cherry picked from https://android-review.googlesource.com/q/commit:acd4a677f01f7e9674e07be27aabbc3d8a5cb84d) Merged-In: I49a8d3cfeb45eddc95ad6ab4a33b0adf0585cde2 Change-Id: I49a8d3cfeb45eddc95ad6ab4a33b0adf0585cde2 --- audio/aidl/default/config/audioPolicy/engine/api/current.txt | 4 ++++ .../audioPolicy/engine/audio_policy_engine_configuration.xsd | 4 ++++ audio/policy/1.0/xml/api/current.txt | 4 ++++ audio/policy/1.0/xml/audio_policy_engine_configuration.xsd | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/audio/aidl/default/config/audioPolicy/engine/api/current.txt b/audio/aidl/default/config/audioPolicy/engine/api/current.txt index 59574f3299..063b05dd61 100644 --- a/audio/aidl/default/config/audioPolicy/engine/api/current.txt +++ b/audio/aidl/default/config/audioPolicy/engine/api/current.txt @@ -209,11 +209,13 @@ package android.audio.policy.engine.configuration { public enum UsageEnumType { method @NonNull public String getRawName(); enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ALARM; + enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANT; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT; + enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_EMERGENCY; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_GAME; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_MEDIA; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION; @@ -222,7 +224,9 @@ package android.audio.policy.engine.configuration { enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; + enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_SAFETY; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_UNKNOWN; + enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION; enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd index b58a6c84fb..40396bb9b9 100644 --- a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd +++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd @@ -359,6 +359,10 @@ + + + + diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt index 84a2b710b8..01d77d7725 100644 --- a/audio/policy/1.0/xml/api/current.txt +++ b/audio/policy/1.0/xml/api/current.txt @@ -209,11 +209,13 @@ package audio.policy.V1_0 { public enum UsageEnumType { method public String getRawName(); enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ALARM; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANT; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_EMERGENCY; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_GAME; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_MEDIA; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION; @@ -222,7 +224,9 @@ package audio.policy.V1_0 { enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_SAFETY; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_UNKNOWN; + enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION; enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd index b58a6c84fb..40396bb9b9 100644 --- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd +++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd @@ -359,6 +359,10 @@ + + + + From 236b04d3c3bd6b31d84bcb1af30841dcf92895eb Mon Sep 17 00:00:00 2001 From: maheshkkv Date: Mon, 21 Aug 2023 11:54:12 -0700 Subject: [PATCH 103/152] Fix Legacy to AIDL conversion for link state Bug: 296807191 Test: hardware/interfaces/wifi/aidl/default/tests/runtests.sh Change-Id: Iea60d7894b22558b386f62a77ff43aa374b6c40f --- wifi/aidl/default/aidl_struct_util.cpp | 10 ++++++++++ .../tests/aidl_struct_util_unit_tests.cpp | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp index 7bc2eeb349..83e11939fd 100644 --- a/wifi/aidl/default/aidl_struct_util.cpp +++ b/wifi/aidl/default/aidl_struct_util.cpp @@ -887,6 +887,15 @@ bool convertLegacyLinkLayerRadioStatsToAidl( return true; } +StaLinkLayerLinkStats::StaLinkState convertLegacyMlLinkStateToAidl(wifi_link_state state) { + if (state == wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE) { + return StaLinkLayerLinkStats::StaLinkState::NOT_IN_USE; + } else if (state == wifi_link_state::WIFI_LINK_STATE_IN_USE) { + return StaLinkLayerLinkStats::StaLinkState::IN_USE; + } + return StaLinkLayerLinkStats::StaLinkState::UNKNOWN; +} + bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& legacy_ml_stats, StaLinkLayerStats* aidl_stats) { if (!aidl_stats) { @@ -898,6 +907,7 @@ bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& leg for (const auto& link : legacy_ml_stats.links) { StaLinkLayerLinkStats linkStats = {}; linkStats.linkId = link.stat.link_id; + linkStats.state = convertLegacyMlLinkStateToAidl(link.stat.state); linkStats.radioId = link.stat.radio; linkStats.frequencyMhz = link.stat.frequency; linkStats.beaconRx = link.stat.beacon_rx; diff --git a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp index 5c334f8d56..995a13d996 100644 --- a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp +++ b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp @@ -123,6 +123,9 @@ TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerMlStatsToAidl) { // Add two radio stats legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{}); legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{}); + wifi_link_state states[sizeof(wifi_link_state)] = {wifi_link_state::WIFI_LINK_STATE_UNKNOWN, + wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE, + wifi_link_state::WIFI_LINK_STATE_IN_USE}; // Add two links. legacy_ml_stats.links.push_back(legacy_hal::LinkStats{}); legacy_ml_stats.links.push_back(legacy_hal::LinkStats{}); @@ -133,6 +136,7 @@ TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerMlStatsToAidl) { link.stat.beacon_rx = rand(); // MLO link id: 0 - 15 link.stat.link_id = rand() % 16; + link.stat.state = states[rand() % sizeof(states)]; // Maximum number of radios is limited to 3 for testing. link.stat.radio = rand() % 4; link.stat.frequency = rand(); @@ -241,6 +245,18 @@ TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerMlStatsToAidl) { int l = 0; for (legacy_hal::LinkStats& link : legacy_ml_stats.links) { EXPECT_EQ(link.stat.link_id, (uint8_t)converted.iface.links[l].linkId); + StaLinkLayerLinkStats::StaLinkState expectedState; + switch (link.stat.state) { + case wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE: + expectedState = StaLinkLayerLinkStats::StaLinkState::NOT_IN_USE; + break; + case wifi_link_state::WIFI_LINK_STATE_IN_USE: + expectedState = StaLinkLayerLinkStats::StaLinkState::IN_USE; + break; + default: + expectedState = StaLinkLayerLinkStats::StaLinkState::UNKNOWN; + } + EXPECT_EQ(expectedState, converted.iface.links[l].state); EXPECT_EQ(link.stat.radio, converted.iface.links[l].radioId); EXPECT_EQ(link.stat.frequency, (uint32_t)converted.iface.links[l].frequencyMhz); EXPECT_EQ(link.stat.beacon_rx, (uint32_t)converted.iface.links[l].beaconRx); From 33637da8c46c3cd9cde7cc1122b242a34f1d95b7 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Mon, 21 Aug 2023 18:55:24 +0000 Subject: [PATCH 104/152] Update vts to align AOSP effects support requirement with CDD Bug: 296790934 Test: atest VtsHalAudioEffectFactoryTargetTest Change-Id: I1c837125e62a083d95e279ed0584a9bccea3dcbd Merged-In: I1c837125e62a083d95e279ed0584a9bccea3dcbd --- .../VtsHalAudioEffectFactoryTargetTest.cpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp index 8084a594e0..225640e1fc 100644 --- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp @@ -134,17 +134,18 @@ TEST_P(EffectFactoryTest, CanBeRestarted) { /** * @brief Check at least support list of effect must be supported by aosp: * https://developer.android.com/reference/android/media/audiofx/AudioEffect + * + * For Android 13, they are: Equalizer, LoudnessEnhancer, Visualizer, and DynamicsProcessing. + * https://source.android.com/docs/compatibility/13/android-13-cdd#552_audio_effects */ -TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) { +TEST_P(EffectFactoryTest, SupportMandatoryEffectTypes) { std::vector descs; - std::set typeUuidSet( - {aidl::android::hardware::audio::effect::getEffectTypeUuidBassBoost(), - aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer(), - aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb(), - aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb(), - aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing(), - aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator(), - aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer()}); + std::set typeUuidSet({ + aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer(), + aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing(), + aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer(), + aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer(), + }); EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs)); EXPECT_TRUE(descs.size() >= typeUuidSet.size()); @@ -305,4 +306,4 @@ int main(int argc, char** argv) { ABinderProcess_setThreadPoolMaxThreadCount(1); ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); -} \ No newline at end of file +} From c1cd92cf9ec76c843460b7697028d0e9495b22d4 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Tue, 22 Aug 2023 20:46:34 +0000 Subject: [PATCH 105/152] r_submix: keep the signed value for offset calculation in AIDL implementation otherwise a negative offset will result in long sleep Bug: 295055755 Test: atest android.media.audio.cts.AudioPlaybackCaptureTest Change-Id: Ie941cc2525e3ea42b53106ae3a65242794b1dd1b Merged-In: Ie941cc2525e3ea42b53106ae3a65242794b1dd1b --- audio/aidl/default/r_submix/StreamRemoteSubmix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 11838f8d95..3134b86841 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -348,9 +348,9 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { // recording (including this call): it's converted to usec and compared to how long we've been // recording for, which gives us how long we must wait to sync the projected recording time, and // the observed recording time. - const size_t projectedVsObservedOffsetUs = static_cast( + const int projectedVsObservedOffsetUs = std::roundf((readCounterFrames * MICROS_PER_SECOND / mStreamConfig.sampleRate) - - recordDurationUs.count())); + recordDurationUs.count()); LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count() << " microseconds, will wait: " << projectedVsObservedOffsetUs << " microseconds"; From dbec48bbd22358aa28d5125c6d743f86358a1e44 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 23 Aug 2023 18:46:52 +0000 Subject: [PATCH 106/152] Use String8/16 c_str [camera] Bug: 295394788 Test: make checkbuild Change-Id: I7ca371112e891f4f40673b5c34e3b8ccc41841bf --- camera/common/default/CameraMetadata.cpp | 4 ++-- camera/common/default/CameraParameters.cpp | 10 +++++----- camera/common/default/VendorTagDescriptor.cpp | 10 +++++----- .../2.4/default/LegacyCameraProviderImpl_2_4.cpp | 2 +- .../functional/VtsHalCameraProviderV2_4TargetTest.cpp | 5 ++--- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/camera/common/default/CameraMetadata.cpp b/camera/common/default/CameraMetadata.cpp index ed5626115d..3252e3ca47 100644 --- a/camera/common/default/CameraMetadata.cpp +++ b/camera/common/default/CameraMetadata.cpp @@ -258,7 +258,7 @@ status_t CameraMetadata::update(uint32_t tag, const String8& string) { return res; } // string.size() doesn't count the null termination character. - return updateImpl(tag, (const void*)string.string(), string.size() + 1); + return updateImpl(tag, (const void*)string.c_str(), string.size() + 1); } status_t CameraMetadata::update(const camera_metadata_ro_entry& entry) { @@ -455,7 +455,7 @@ status_t CameraMetadata::getTagFromName(const char* name, const VendorTagDescrip for (size_t i = 0; i < totalSectionCount; ++i) { const char* str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] - : (*vendorSections)[i - ANDROID_SECTION_COUNT].string(); + : (*vendorSections)[i - ANDROID_SECTION_COUNT].c_str(); ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str); diff --git a/camera/common/default/CameraParameters.cpp b/camera/common/default/CameraParameters.cpp index 37e28a25d1..3689c900ed 100644 --- a/camera/common/default/CameraParameters.cpp +++ b/camera/common/default/CameraParameters.cpp @@ -204,7 +204,7 @@ String8 CameraParameters::flatten() const { } void CameraParameters::unflatten(const String8& params) { - const char* a = params.string(); + const char* a = params.c_str(); const char* b; mMap.clear(); @@ -263,7 +263,7 @@ void CameraParameters::setFloat(const char* key, float value) { const char* CameraParameters::get(const char* key) const { String8 v = mMap.valueFor(String8(key)); if (v.length() == 0) return 0; - return v.string(); + return v.c_str(); } int CameraParameters::getInt(const char* key) const { @@ -429,7 +429,7 @@ void CameraParameters::dump() const { String8 k, v; k = mMap.keyAt(i); v = mMap.valueAt(i); - ALOGD("%s: %s\n", k.string(), v.string()); + ALOGD("%s: %s\n", k.c_str(), v.c_str()); } } @@ -443,10 +443,10 @@ status_t CameraParameters::dump(int fd, const Vector& /*args*/) const String8 k, v; k = mMap.keyAt(i); v = mMap.valueAt(i); - snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string()); + snprintf(buffer, 255, "\t%s: %s\n", k.c_str(), v.c_str()); result.append(buffer); } - write(fd, result.string(), result.size()); + write(fd, result.c_str(), result.size()); return NO_ERROR; } diff --git a/camera/common/default/VendorTagDescriptor.cpp b/camera/common/default/VendorTagDescriptor.cpp index 1282bd0ccb..fba9caaa2e 100644 --- a/camera/common/default/VendorTagDescriptor.cpp +++ b/camera/common/default/VendorTagDescriptor.cpp @@ -97,7 +97,7 @@ const char* VendorTagDescriptor::getSectionName(uint32_t tag) const { if (index < 0) { return VENDOR_SECTION_NAME_ERR; } - return mSections[mTagToSectionMap.valueAt(index)].string(); + return mSections[mTagToSectionMap.valueAt(index)].c_str(); } ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const { @@ -109,7 +109,7 @@ const char* VendorTagDescriptor::getTagName(uint32_t tag) const { if (index < 0) { return VENDOR_TAG_NAME_ERR; } - return mTagToNameMap.valueAt(index).string(); + return mTagToNameMap.valueAt(index).c_str(); } int VendorTagDescriptor::getTagType(uint32_t tag) const { @@ -128,13 +128,13 @@ status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& sect /*out*/ uint32_t* tag) const { ssize_t index = mReverseMapping.indexOfKey(section); if (index < 0) { - ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string()); + ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.c_str()); return BAD_VALUE; } ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name); if (nameIndex < 0) { - ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string()); + ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.c_str()); return BAD_VALUE; } @@ -167,7 +167,7 @@ void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const { const char* typeName = (type >= 0 && type < NUM_TYPES) ? camera_metadata_type_names[type] : "UNKNOWN"; dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2, "", - tag, name.string(), type, typeName, sectionName.string()); + tag, name.c_str(), type, typeName, sectionName.c_str()); } } diff --git a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp index 7c3b982931..69318c7368 100644 --- a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp +++ b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp @@ -439,7 +439,7 @@ bool LegacyCameraProviderImpl_2_4::setUpVendorTags() { } mVendorTagSections.resize(numSections); for (size_t s = 0; s < numSections; s++) { - mVendorTagSections[s].sectionName = (*sectionNames)[s].string(); + mVendorTagSections[s].sectionName = (*sectionNames)[s].c_str(); mVendorTagSections[s].tags = tagsBySection[s]; } return true; diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 339a142251..c8e683c290 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -244,7 +244,7 @@ namespace { std::string* deviceVersion, std::string* cameraId) { ::android::String8 pattern; pattern.appendFormat(kDeviceNameRE, providerType.c_str()); - std::regex e(pattern.string()); + std::regex e(pattern.c_str()); std::string deviceNameStd(deviceName.c_str()); std::smatch sm; if (std::regex_match(deviceNameStd, sm, e)) { @@ -8801,8 +8801,7 @@ void CameraHidlTest::getParameters( void CameraHidlTest::setParameters( const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, const CameraParameters &cameraParams) { - Return returnStatus = device->setParameters( - cameraParams.flatten().string()); + Return returnStatus = device->setParameters(cameraParams.flatten().c_str()); ASSERT_TRUE(returnStatus.isOk()); ASSERT_EQ(Status::OK, returnStatus); } From 92d84c0c04e8a4043f331f56d2b89177229d4f1f Mon Sep 17 00:00:00 2001 From: Xin Li Date: Mon, 21 Aug 2023 13:34:40 -0700 Subject: [PATCH 107/152] Clean up android.hardware.automotive.vehicle intermediates. In ag/20886210, the VHAL properties were separated into a new AIDL interface but the names remained the same. In incremental builds with pre-existing old versions of AIDL, these generated headers would remain there and gets picked up due to include directory ordering. Eliminate this possiblity by performing a cleanup of the generated primary headers directory. Change-Id: Ic5ef401b427b2772e8527b2dc9804781a51125be --- CleanSpec.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/CleanSpec.mk b/CleanSpec.mk index 1eca2a1c21..2e9d9ab328 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -85,3 +85,4 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*) $(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/wifi/1.4/android.hardware.wifi@1.4-adapter_genc++/) +$(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/automotive/vehicle/aidl/android.hardware.automotive.vehicle-V2-ndk-source/) From d395fce7545fe68469c96e3f92d80d44876440c4 Mon Sep 17 00:00:00 2001 From: Yung Ti Su Date: Tue, 22 Aug 2023 09:29:06 +0000 Subject: [PATCH 108/152] enable host_supported for libbluetooth_audio_session_aidl Test: manual Change-Id: Iae06114020e5bc4e41fa5caa5df5de8a186dc2ff Merged-In: Iae06114020e5bc4e41fa5caa5df5de8a186dc2ff Signed-off-by: Yung Ti Su --- bluetooth/audio/aidl/Android.bp | 1 + bluetooth/audio/utils/Android.bp | 1 + bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp index 16b22fef36..1028faecf2 100644 --- a/bluetooth/audio/aidl/Android.bp +++ b/bluetooth/audio/aidl/Android.bp @@ -24,6 +24,7 @@ package { aidl_interface { name: "android.hardware.bluetooth.audio", vendor_available: true, + host_supported: true, srcs: ["android/hardware/bluetooth/audio/*.aidl"], stability: "vintf", imports: [ diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp index 914d2b2fd3..8cafb47cd8 100644 --- a/bluetooth/audio/utils/Android.bp +++ b/bluetooth/audio/utils/Android.bp @@ -36,6 +36,7 @@ cc_library_shared { cc_library_shared { name: "libbluetooth_audio_session_aidl", vendor: true, + host_supported: true, srcs: [ "aidl_session/BluetoothAudioCodecs.cpp", "aidl_session/BluetoothAudioSession.cpp", diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp index a4664f1636..3d92ee7b1f 100644 --- a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp +++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp @@ -583,7 +583,7 @@ bool HidlToAidlMiddleware_2_0::GetPresentationPosition( *total_bytes_readed = presentation_position.transmittedOctets; if (data_position) *data_position = { - .tv_sec = static_cast<__kernel_old_time_t>( + .tv_sec = static_cast( presentation_position.transmittedOctetsTimestamp.tvSec), .tv_nsec = static_cast( presentation_position.transmittedOctetsTimestamp.tvNSec)}; From f3db7ced803783f27f865b04fc29a42f2e355132 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Mon, 28 Aug 2023 13:33:05 +0900 Subject: [PATCH 109/152] Mark neuralnetworks HAL as updatable-via-apex Bug: 297786849 Test: m Change-Id: I80eb731040d23371886213941138bc73c033bb1f --- compatibility_matrices/compatibility_matrix.8.xml | 2 +- compatibility_matrices/compatibility_matrix.9.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml index 89f62f7c4e..4712437600 100644 --- a/compatibility_matrices/compatibility_matrix.8.xml +++ b/compatibility_matrices/compatibility_matrix.8.xml @@ -367,7 +367,7 @@ default - + android.hardware.neuralnetworks 1-4 diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml index 893d8c3c39..83d06e32ce 100644 --- a/compatibility_matrices/compatibility_matrix.9.xml +++ b/compatibility_matrices/compatibility_matrix.9.xml @@ -364,7 +364,7 @@ default - + android.hardware.neuralnetworks 1-4 From d6765e03e27e16eefa24617d5769ee4001010944 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Mon, 20 Mar 2023 13:49:25 +0900 Subject: [PATCH 110/152] Set min_sdk_version for Widevine APEX to 34 Bug: 294568360 Test: build WV APEX with V and install it on U device Change-Id: I3d068f72b5fcf6ee2fc746ddf1e88ae0d5d03148 --- drm/aidl/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp index fb04d842ef..afcb603db7 100644 --- a/drm/aidl/Android.bp +++ b/drm/aidl/Android.bp @@ -23,7 +23,7 @@ aidl_interface { sdk_version: "module_current", }, ndk: { - min_sdk_version: "UpsideDownCake", + min_sdk_version: "34", }, }, double_loadable: true, From 3454ce179af9123c6f3c5730209f6045bad054d5 Mon Sep 17 00:00:00 2001 From: Gabriel Biren Date: Wed, 19 Jul 2023 17:20:09 +0000 Subject: [PATCH 111/152] Add hostapd_test_utils helper methods for the Hostapd AIDL VTS tests. Main purpose will be to enable/disable the HALs and Wifi framework before and after each test. Bug: 283402709 Test: atest VtsHalHostapdTargetTest Change-Id: Ib3ceca4ad25f472e1b75fa95661235c880a489fd --- .../functional/hostapd_hidl_test_utils.cpp | 12 +- .../vts/functional/hostapd_hidl_test_utils.h | 4 + wifi/hostapd/aidl/vts/functional/Android.bp | 1 + .../vts/functional/hostapd_aidl_test_utils.h | 80 ++++++++++++ .../functional/hostapd_legacy_test_utils.h | 71 ++++++++++ .../aidl/vts/functional/hostapd_test_utils.h | 122 ++++++++++++++++++ 6 files changed, 283 insertions(+), 7 deletions(-) create mode 100644 wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h create mode 100644 wifi/hostapd/aidl/vts/functional/hostapd_legacy_test_utils.h create mode 100644 wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp index 75d6252cd2..56f285d147 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp @@ -41,10 +41,9 @@ using ::android::hardware::wifi::V1_0::IWifiChip; using ::android::wifi_system::HostapdManager; using ::android::wifi_system::SupplicantManager; -namespace { // Helper function to initialize the driver and firmware to AP mode // using the vendor HAL HIDL interface. -void initilializeDriverAndFirmware(const std::string& wifi_instance_name) { +void initializeDriverAndFirmware(const std::string& wifi_instance_name) { if (getWifi(wifi_instance_name) != nullptr) { sp wifi_chip = getWifiChip(wifi_instance_name); ChipModeId mode_id; @@ -57,21 +56,20 @@ void initilializeDriverAndFirmware(const std::string& wifi_instance_name) { // Helper function to deinitialize the driver and firmware // using the vendor HAL HIDL interface. -void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) { +void deInitializeDriverAndFirmware(const std::string& wifi_instance_name) { if (getWifi(wifi_instance_name) != nullptr) { stopWifi(wifi_instance_name); } else { LOG(WARNING) << __func__ << ": Vendor HAL not supported"; } } -} // namespace void stopSupplicantIfNeeded(const std::string& instance_name) { SupplicantManager supplicant_manager; if (supplicant_manager.IsSupplicantRunning()) { LOG(INFO) << "Supplicant is running, stop supplicant first."; ASSERT_TRUE(supplicant_manager.StopSupplicant()); - deInitilializeDriverAndFirmware(instance_name); + deInitializeDriverAndFirmware(instance_name); ASSERT_FALSE(supplicant_manager.IsSupplicantRunning()); } } @@ -80,13 +78,13 @@ void stopHostapd(const std::string& instance_name) { HostapdManager hostapd_manager; ASSERT_TRUE(hostapd_manager.StopHostapd()); - deInitilializeDriverAndFirmware(instance_name); + deInitializeDriverAndFirmware(instance_name); } void startHostapdAndWaitForHidlService( const std::string& wifi_instance_name, const std::string& hostapd_instance_name) { - initilializeDriverAndFirmware(wifi_instance_name); + initializeDriverAndFirmware(wifi_instance_name); HostapdManager hostapd_manager; ASSERT_TRUE(hostapd_manager.StartHostapd()); diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h index 5cb4f013b1..893de1e334 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h @@ -33,5 +33,9 @@ void startHostapdAndWaitForHidlService( bool is_1_1(const android::sp& hostapd); +// Used to initialize/deinitialize the driver and firmware at the +// beginning and end of each test. +void initializeDriverAndFirmware(const std::string& wifi_instance_name); +void deInitializeDriverAndFirmware(const std::string& wifi_instance_name); #endif /* HOSTAPD_HIDL_TEST_UTILS_H */ diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp index 33318a4520..ff35056076 100644 --- a/wifi/hostapd/aidl/vts/functional/Android.bp +++ b/wifi/hostapd/aidl/vts/functional/Android.bp @@ -37,6 +37,7 @@ cc_test { "android.hardware.wifi@1.5", "android.hardware.wifi@1.6", "android.hardware.wifi-V1-ndk", + "libwifi-system", "libwifi-system-iface", "VtsHalWifiTargetTestUtil", ], diff --git a/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h b/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h new file mode 100644 index 0000000000..93540b2671 --- /dev/null +++ b/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "wifi_aidl_test_utils.h" + +namespace { + +const std::string kWifiInstanceNameStr = std::string() + IWifi::descriptor + "/default"; +const char* kWifiInstanceName = kWifiInstanceNameStr.c_str(); + +} // namespace + +namespace HostapdAidlTestUtils { + +bool useAidlService() { + return isAidlServiceAvailable(kWifiInstanceName); +} + +void startAndConfigureVendorHal() { + if (getWifi(kWifiInstanceName) != nullptr) { + std::shared_ptr wifi_chip = getWifiChip(kWifiInstanceName); + int mode_id; + EXPECT_TRUE(configureChipToSupportConcurrencyType(wifi_chip, IfaceConcurrencyType::AP, + &mode_id)); + } else { + LOG(ERROR) << "Unable to initialize Vendor HAL"; + } +} + +void stopVendorHal() { + if (getWifi(kWifiInstanceName) != nullptr) { + stopWifiService(kWifiInstanceName); + } else { + LOG(ERROR) << "Unable to stop Vendor HAL"; + } +} + +std::string setupApIfaceAndGetName(bool isBridged) { + std::shared_ptr wifi_ap_iface; + if (isBridged) { + wifi_ap_iface = getBridgedWifiApIface(kWifiInstanceName); + } else { + wifi_ap_iface = getWifiApIface(kWifiInstanceName); + } + + EXPECT_TRUE(wifi_ap_iface.get() != nullptr); + if (!wifi_ap_iface.get()) { + LOG(ERROR) << "Unable to create iface. isBridged=" << isBridged; + return ""; + } + + std::string ap_iface_name; + auto status = wifi_ap_iface->getName(&ap_iface_name); + EXPECT_TRUE(status.isOk()); + if (!status.isOk()) { + LOG(ERROR) << "Unable to retrieve iface name. isBridged=" << isBridged; + return ""; + } + return ap_iface_name; +} + +} // namespace HostapdAidlTestUtils diff --git a/wifi/hostapd/aidl/vts/functional/hostapd_legacy_test_utils.h b/wifi/hostapd/aidl/vts/functional/hostapd_legacy_test_utils.h new file mode 100644 index 0000000000..fb59dc2858 --- /dev/null +++ b/wifi/hostapd/aidl/vts/functional/hostapd_legacy_test_utils.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "hostapd_hidl_test_utils.h" +#include "wifi_hidl_test_utils.h" + +using ::android::hardware::wifi::V1_0::WifiStatus; + +namespace { + +std::string getWifiInstanceName() { + const std::vector instances = android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_0::IWifi::descriptor); + EXPECT_NE(0, instances.size()); + return instances.size() != 0 ? instances[0] : ""; +} + +} // namespace + +namespace HostapdLegacyTestUtils { + +void startAndConfigureVendorHal() { + initializeDriverAndFirmware(getWifiInstanceName()); +} + +void stopVendorHal() { + deInitializeDriverAndFirmware(getWifiInstanceName()); +} + +std::string setupApIfaceAndGetName(bool isBridged) { + android::sp<::android::hardware::wifi::V1_0::IWifiApIface> wifi_ap_iface; + if (isBridged) { + wifi_ap_iface = getBridgedWifiApIface_1_6(getWifiInstanceName()); + } else { + wifi_ap_iface = getWifiApIface_1_5(getWifiInstanceName()); + } + + EXPECT_TRUE(wifi_ap_iface.get() != nullptr); + if (!wifi_ap_iface.get()) { + LOG(ERROR) << "Unable to create iface. isBridged=" << isBridged; + return ""; + } + + const auto& status_and_name = HIDL_INVOKE(wifi_ap_iface, getName); + EXPECT_TRUE(status_and_name.first.code == + android::hardware::wifi::V1_0::WifiStatusCode::SUCCESS); + if (status_and_name.first.code != android::hardware::wifi::V1_0::WifiStatusCode::SUCCESS) { + LOG(ERROR) << "Unable to retrieve iface name. isBridged=" << isBridged; + return ""; + } + return status_and_name.second; +} + +} // namespace HostapdLegacyTestUtils diff --git a/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h b/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h new file mode 100644 index 0000000000..feee2c89b2 --- /dev/null +++ b/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "hostapd_aidl_test_utils.h" +#include "hostapd_legacy_test_utils.h" + +using aidl::android::hardware::wifi::hostapd::IHostapd; +using android::wifi_system::HostapdManager; +using android::wifi_system::SupplicantManager; + +namespace { + +void startAndConfigureVendorHal() { + if (HostapdAidlTestUtils::useAidlService()) { + HostapdAidlTestUtils::startAndConfigureVendorHal(); + } else { + HostapdLegacyTestUtils::startAndConfigureVendorHal(); + } +} + +void stopVendorHal() { + if (HostapdAidlTestUtils::useAidlService()) { + HostapdAidlTestUtils::stopVendorHal(); + } else { + HostapdLegacyTestUtils::stopVendorHal(); + } +} + +void stopHostapd() { + HostapdManager hostapd_manager; + ASSERT_TRUE(hostapd_manager.StopHostapd()); +} + +void waitForSupplicantState(bool enable) { + SupplicantManager supplicant_manager; + int count = 50; // wait at most 5 seconds + while (count-- > 0) { + if (supplicant_manager.IsSupplicantRunning() == enable) { + return; + } + usleep(100000); // 100 ms + } + LOG(ERROR) << "Unable to " << (enable ? "start" : "stop") << " supplicant"; +} + +void toggleWifiFramework(bool enable) { + if (enable) { + std::system("svc wifi enable"); + std::system("cmd wifi set-scan-always-available enabled"); + waitForSupplicantState(true); + } else { + std::system("svc wifi disable"); + std::system("cmd wifi set-scan-always-available disabled"); + waitForSupplicantState(false); + } +} + +} // namespace + +std::shared_ptr getHostapd(const std::string& hostapd_instance_name) { + return IHostapd::fromBinder( + ndk::SpAIBinder(AServiceManager_waitForService(hostapd_instance_name.c_str()))); +} + +/** + * Disable the Wifi framework, hostapd, and vendor HAL. + * + * Note: The framework should be disabled to avoid having + * any other clients to the HALs during testing. + */ +void disableHalsAndFramework() { + toggleWifiFramework(false); + stopHostapd(); + stopVendorHal(); + + // Wait for the services to stop. + sleep(3); +} + +void initializeHostapdAndVendorHal(const std::string& hostapd_instance_name) { + startAndConfigureVendorHal(); + HostapdManager hostapd_manager; + ASSERT_TRUE(hostapd_manager.StartHostapd()); + getHostapd(hostapd_instance_name); +} + +void stopHostapdAndVendorHal() { + stopHostapd(); + stopVendorHal(); +} + +void startWifiFramework() { + toggleWifiFramework(true); +} + +std::string setupApIfaceAndGetName(bool isBridged) { + if (HostapdAidlTestUtils::useAidlService()) { + return HostapdAidlTestUtils::setupApIfaceAndGetName(isBridged); + } else { + return HostapdLegacyTestUtils::setupApIfaceAndGetName(isBridged); + } +} From c6cacf6149a8d5655f2aa841597104979e17c622 Mon Sep 17 00:00:00 2001 From: Gabriel Biren Date: Wed, 19 Jul 2023 17:24:21 +0000 Subject: [PATCH 112/152] Use the hostapd_test_utils helper methods in the Hostapd AIDL VTS tests. At the beginning of each test, we now: 1. Disable the Wifi framework, Hostapd, and Vendor HAL. 2. Enable the Hostapd and Vendor HAL. At the end of each test, we now: 1. Disable the Hostapd and Vendor HAL. 2. Enable the Wifi framework. Bug: 283402709 Test: atest VtsHalHostapdTargetTest --iterations 10 # Tested on both an Android T and U device. # All tests passed in both cases. Change-Id: I8b5e24ad44d13fad09d84f1b212e60ca8df3aa7e --- .../functional/VtsHalHostapdTargetTest.cpp | 79 +++---------------- 1 file changed, 11 insertions(+), 68 deletions(-) diff --git a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp index efd1538c7b..137537d18b 100644 --- a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp +++ b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp @@ -32,6 +32,7 @@ #include #include +#include "hostapd_test_utils.h" #include "wifi_aidl_test_utils.h" using aidl::android::hardware::wifi::hostapd::BandMask; @@ -56,10 +57,7 @@ const std::string kInvalidMaxPassphrase = const int kIfaceChannel = 6; const int kIfaceInvalidChannel = 567; const std::vector kTestZeroMacAddr(6, 0x0); -const Ieee80211ReasonCode kTestDisconnectReasonCode = - Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED; -const std::string kWifiAidlInstanceNameStr = std::string() + IWifi::descriptor + "/default"; -const char* kWifiAidlInstanceName = kWifiAidlInstanceNameStr.c_str(); +const Ieee80211ReasonCode kTestDisconnectReasonCode = Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED; inline BandMask operator|(BandMask a, BandMask b) { return static_cast(static_cast(a) | @@ -70,10 +68,13 @@ inline BandMask operator|(BandMask a, BandMask b) { class HostapdAidl : public testing::TestWithParam { public: virtual void SetUp() override { - hostapd = IHostapd::fromBinder(ndk::SpAIBinder( - AServiceManager_waitForService(GetParam().c_str()))); + disableHalsAndFramework(); + initializeHostapdAndVendorHal(GetParam()); + + hostapd = getHostapd(GetParam()); ASSERT_NE(hostapd, nullptr); EXPECT_TRUE(hostapd->setDebugParams(DebugLevel::EXCESSIVE).isOk()); + isAcsSupport = testing::checkSubstringInCommandOutput( "/system/bin/cmd wifi get-softap-supported-features", "wifi_softap_acs_supported"); @@ -81,81 +82,23 @@ class HostapdAidl : public testing::TestWithParam { "/system/bin/cmd wifi get-softap-supported-features", "wifi_softap_wpa3_sae_supported"); isBridgedSupport = testing::checkSubstringInCommandOutput( - "/system/bin/cmd wifi get-softap-supported-features", - "wifi_softap_bridged_ap_supported"); - if (!isAidlServiceAvailable(kWifiAidlInstanceName)) { - const std::vector instances = android::hardware::getAllHalInstanceNames( - ::android::hardware::wifi::V1_0::IWifi::descriptor); - EXPECT_NE(0, instances.size()); - wifiHidlInstanceName = instances[0]; - } + "/system/bin/cmd wifi get-softap-supported-features", + "wifi_softap_bridged_ap_supported"); } virtual void TearDown() override { - stopVendorHal(); hostapd->terminate(); // Wait 3 seconds to allow terminate to complete sleep(3); + stopHostapdAndVendorHal(); + startWifiFramework(); } std::shared_ptr hostapd; - std::string wifiHidlInstanceName; bool isAcsSupport; bool isWpa3SaeSupport; bool isBridgedSupport; - void stopVendorHal() { - if (isAidlServiceAvailable(kWifiAidlInstanceName)) { - // HIDL and AIDL versions of getWifi() take different arguments - // i.e. const char* vs string - if (getWifi(kWifiAidlInstanceName) != nullptr) { - stopWifiService(kWifiAidlInstanceName); - } - } else { - if (getWifi(wifiHidlInstanceName) != nullptr) { - stopWifi(wifiHidlInstanceName); - } - } - } - - std::string setupApIfaceAndGetName(bool isBridged) { - if (isAidlServiceAvailable(kWifiAidlInstanceName)) { - return setupApIfaceAndGetNameAidl(isBridged); - } else { - return setupApIfaceAndGetNameHidl(isBridged); - } - } - - std::string setupApIfaceAndGetNameAidl(bool isBridged) { - std::shared_ptr wifi_ap_iface; - if (isBridged) { - wifi_ap_iface = getBridgedWifiApIface(kWifiAidlInstanceName); - } else { - wifi_ap_iface = getWifiApIface(kWifiAidlInstanceName); - } - EXPECT_NE(nullptr, wifi_ap_iface.get()); - - std::string ap_iface_name; - auto status = wifi_ap_iface->getName(&ap_iface_name); - EXPECT_TRUE(status.isOk()); - return ap_iface_name; - } - - std::string setupApIfaceAndGetNameHidl(bool isBridged) { - android::sp<::android::hardware::wifi::V1_0::IWifiApIface> wifi_ap_iface; - if (isBridged) { - wifi_ap_iface = getBridgedWifiApIface_1_6(wifiHidlInstanceName); - } else { - wifi_ap_iface = getWifiApIface_1_5(wifiHidlInstanceName); - } - EXPECT_NE(nullptr, wifi_ap_iface.get()); - - const auto& status_and_name = HIDL_INVOKE(wifi_ap_iface, getName); - EXPECT_EQ(android::hardware::wifi::V1_0::WifiStatusCode::SUCCESS, - status_and_name.first.code); - return status_and_name.second; - } - IfaceParams getIfaceParamsWithoutAcs(std::string iface_name) { IfaceParams iface_params; ChannelParams channelParams; From 9c8fc4b81d3ae41de70abaae1effe7c46f159a9f Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Tue, 22 Aug 2023 22:26:52 +0000 Subject: [PATCH 113/152] Mark some HALs as updatable-via-apex retroactively These are all marked updatable-via-apex in compatibility_matrix.9.xml. Adding them to compatibility_matrix.8.xml to allow Cuttlefish to build with the apexes on 'next' Test: m Bug: 296930312 Change-Id: I2910695dbb7a79ca7164f7ed69437f9636d4135b Merged-In: I2910695dbb7a79ca7164f7ed69437f9636d4135b --- compatibility_matrices/compatibility_matrix.8.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml index 4712437600..9e3b8f93b3 100644 --- a/compatibility_matrices/compatibility_matrix.8.xml +++ b/compatibility_matrices/compatibility_matrix.8.xml @@ -52,7 +52,7 @@ default - + android.hardware.authsecret 1 @@ -122,7 +122,7 @@ default - + android.hardware.biometrics.fingerprint 3 @@ -313,7 +313,7 @@ default - + android.hardware.security.keymint 1-3 @@ -322,7 +322,7 @@ strongbox - + android.hardware.security.keymint 1-3 @@ -519,7 +519,7 @@ SIM[1-9][0-9]* - + android.hardware.security.secureclock 1 @@ -527,7 +527,7 @@ default - + android.hardware.security.sharedsecret 1 @@ -679,7 +679,7 @@ default - + android.hardware.uwb 1 From 6ea114dcd0f3a57d3079cab6fdb4c2b75cfa4d91 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Tue, 22 Aug 2023 22:39:18 +0000 Subject: [PATCH 114/152] Remove compatibility_matrix.9.xml from 'next' builds This compatibility matrix has not be finalized or released yet, so it's very important that releasing devices in the 'next' configuration don't use its contents. Test: m Bug: 296930312 Change-Id: I843a24308a1653bff0b4842ff71e657304bea2c8 Merged-In: I843a24308a1653bff0b4842ff71e657304bea2c8 --- compatibility_matrices/Android.mk | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk index a82a421ff4..f1dd956222 100644 --- a/compatibility_matrices/Android.mk +++ b/compatibility_matrices/Android.mk @@ -103,9 +103,15 @@ my_system_matrix_deps := \ framework_compatibility_matrix.6.xml \ framework_compatibility_matrix.7.xml \ framework_compatibility_matrix.8.xml \ - framework_compatibility_matrix.9.xml \ framework_compatibility_matrix.device.xml \ +# Only allow the use of the unreleased compatibility matrix when we can use unfrozen +# interfaces (in the `next` release configuration). +ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true) +my_system_matrix_deps += \ + framework_compatibility_matrix.9.xml +endif + my_framework_matrix_deps += \ $(my_system_matrix_deps) From bd4cdc6a9a80b3f71d17f58788d3d611574cedbd Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Wed, 30 Aug 2023 19:03:09 +0000 Subject: [PATCH 115/152] Camera VTS: Wait for camera provider to become active Use "AServiceManager_waitForService" instead of "AServiceManager_getService" to wait for any camera providers that might be using the lazy mechanism and are not running all the time. Bug: 297965980 Test: atest VtsAidlHalCameraProvider_TargetTest Change-Id: I6374dc768cd1068885668f927f902dcee44a7a42 --- camera/provider/aidl/vts/camera_aidl_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp index 08ad0bbaa0..5f9d605ef3 100644 --- a/camera/provider/aidl/vts/camera_aidl_test.cpp +++ b/camera/provider/aidl/vts/camera_aidl_test.cpp @@ -120,7 +120,7 @@ void CameraAidlTest::SetUp() { ABinderProcess_startThreadPool(); SpAIBinder cameraProviderBinder = - SpAIBinder(AServiceManager_getService(serviceDescriptor.c_str())); + SpAIBinder(AServiceManager_waitForService(serviceDescriptor.c_str())); ASSERT_NE(cameraProviderBinder.get(), nullptr); std::shared_ptr cameraProvider = From 166d160b78c29527e2dc474f716faa8b31dded48 Mon Sep 17 00:00:00 2001 From: Seth Moore Date: Fri, 25 Aug 2023 11:09:05 -0700 Subject: [PATCH 116/152] Only require RKP on T+ chipsets It turns out we had a bug (b/263844771) in how RKP support was detected, and that was fixed. However, due to this bug, some S chipests shipped without RKP support which is now required by the tests. This change drops the RKP requirement from S chipsets. There should be no new S chipsets, so this effectively grandfathers in the previous ones that were skipped by the RKP VTS tests. T+ tests (both VTS and other suites) will verify that RKP support is there, so there is no gap introduced by this change. Bug: 297139913 Test: VtsAidlKeyMintTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:8be875e0d0c18b8de67744c8b9629f2ff518dd60) Merged-In: I387e5f058ada698747aac103c1745682291f2d1c Change-Id: I387e5f058ada698747aac103c1745682291f2d1c --- .../aidl/vts/functional/KeyMintAidlTestBase.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index 79c6b12f03..433857c66a 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -1295,15 +1295,12 @@ std::pair> KeyMintAidlTestBase::UpgradeKey( } bool KeyMintAidlTestBase::IsRkpSupportRequired() const { - if (get_vsr_api_level() >= __ANDROID_API_T__) { - return true; - } - - if (get_vsr_api_level() >= __ANDROID_API_S__) { - return SecLevel() != SecurityLevel::STRONGBOX; - } - - return false; + // This is technically not a match to the requirements for S chipsets, + // however when S shipped there was a bug in the test that skipped the + // tests if KeyMint 2 was not on the system. So we allowed many chipests + // to ship without RKP support. In T we hardened the requirements around + // support for RKP, so relax the test to match. + return get_vsr_api_level() >= __ANDROID_API_T__; } vector KeyMintAidlTestBase::ValidKeySizes(Algorithm algorithm) { From 35bf8e1b500d7ac2e8dffbc0bf7fe5abf384dcad Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 7 Sep 2023 16:16:38 -0700 Subject: [PATCH 117/152] Add null check for osAppId Test: atest VtsHalRadioTargetTest Bug: 297467393 Change-Id: Ib94d118765bf527ba51d5e7e29942cec6bff61c4 --- radio/aidl/vts/radio_data_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/radio/aidl/vts/radio_data_test.cpp b/radio/aidl/vts/radio_data_test.cpp index 0fb2fb404f..f31c254277 100644 --- a/radio/aidl/vts/radio_data_test.cpp +++ b/radio/aidl/vts/radio_data_test.cpp @@ -214,7 +214,8 @@ TEST_P(RadioDataTest, setupDataCall_osAppId) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error, {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW})); - if (radioRsp_data->setupDataCallResult.trafficDescriptors.size() <= 0) { + if (radioRsp_data->setupDataCallResult.trafficDescriptors.size() <= 0 || + !radioRsp_data->setupDataCallResult.trafficDescriptors[0].osAppId.has_value()) { return; } EXPECT_EQ(trafficDescriptor.osAppId.value().osAppId, From 5d9b066c044211b7fd128258fe644a940815fad0 Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Thu, 7 Sep 2023 11:26:38 -0700 Subject: [PATCH 118/152] Fix bcradio HAL unsigned int comparison error Bug: 299489486 Test: atest VtsHalBroadcastradioAidlTargetTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:664048f21856ab30d5b713e524ef588f35747938) Merged-In: I87fe60a593800535e0aadb0baf87696ee6844004 Change-Id: I87fe60a593800535e0aadb0baf87696ee6844004 --- broadcastradio/aidl/default/VirtualRadio.cpp | 26 +++++++++---------- broadcastradio/common/utilsaidl/Utils.cpp | 18 ++++++------- .../include/broadcastradio-utils-aidl/Utils.h | 6 ++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/broadcastradio/aidl/default/VirtualRadio.cpp b/broadcastradio/aidl/default/VirtualRadio.cpp index 126bcff621..86c5a962bc 100644 --- a/broadcastradio/aidl/default/VirtualRadio.cpp +++ b/broadcastradio/aidl/default/VirtualRadio.cpp @@ -53,18 +53,18 @@ const VirtualRadio& VirtualRadio::getAmFmRadio() { static VirtualRadio amFmRadioMock( "AM/FM radio mock", { - {makeSelectorAmfm(/* frequency= */ 94900), "Wild 94.9", "Drake ft. Rihanna", + {makeSelectorAmfm(/* frequency= */ 94900u), "Wild 94.9", "Drake ft. Rihanna", "Too Good"}, - {makeSelectorAmfm(/* frequency= */ 96500), "KOIT", "Celine Dion", "All By Myself"}, - {makeSelectorAmfm(/* frequency= */ 97300), "Alice@97.3", "Drops of Jupiter", "Train"}, - {makeSelectorAmfm(/* frequency= */ 99700), "99.7 Now!", "The Chainsmokers", "Closer"}, - {makeSelectorAmfm(/* frequency= */ 101300), "101-3 KISS-FM", "Justin Timberlake", + {makeSelectorAmfm(/* frequency= */ 96500u), "KOIT", "Celine Dion", "All By Myself"}, + {makeSelectorAmfm(/* frequency= */ 97300u), "Alice@97.3", "Drops of Jupiter", "Train"}, + {makeSelectorAmfm(/* frequency= */ 99700u), "99.7 Now!", "The Chainsmokers", "Closer"}, + {makeSelectorAmfm(/* frequency= */ 101300u), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"}, - {makeSelectorAmfm(/* frequency= */ 103700), "iHeart80s @ 103.7", "Michael Jackson", + {makeSelectorAmfm(/* frequency= */ 103700u), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"}, - {makeSelectorAmfm(/* frequency= */ 106100), "106 KMEL", "Drake", "Marvins Room"}, - {makeSelectorAmfm(/* frequency= */ 700), "700 AM", "Artist700", "Title700"}, - {makeSelectorAmfm(/* frequency= */ 1700), "1700 AM", "Artist1700", "Title1700"}, + {makeSelectorAmfm(/* frequency= */ 106100u), "106 KMEL", "Drake", "Marvins Room"}, + {makeSelectorAmfm(/* frequency= */ 700u), "700 AM", "Artist700", "Title700"}, + {makeSelectorAmfm(/* frequency= */ 1700u), "1700 AM", "Artist1700", "Title1700"}, }); // clang-format on return amFmRadioMock; @@ -77,13 +77,13 @@ const VirtualRadio& VirtualRadio::getDabRadio() { "DAB radio mock", { {makeSelectorDab(/* sidExt= */ 0xA000000001u, /* ensemble= */ 0x0001u, - /* freq= */ 225648), "BBC Radio 1", "Khalid", "Talk"}, + /* freq= */ 225648u), "BBC Radio 1", "Khalid", "Talk"}, {makeSelectorDab(/* sidExt= */ 0xB000000001u, /* ensemble= */ 0x1001u, - /* freq= */ 222064), "Classic FM", "Jean Sibelius", "Andante Festivo"}, + /* freq= */ 222064u), "Classic FM", "Jean Sibelius", "Andante Festivo"}, {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u, - /* freq= */ 227360), "Absolute Radio", "Coldplay", "Clocks"}, + /* freq= */ 227360u), "Absolute Radio", "Coldplay", "Clocks"}, {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u, - /* freq= */ 222064), "Absolute Radio", "Coldplay", "Clocks"}, + /* freq= */ 222064u), "Absolute Radio", "Coldplay", "Clocks"}, }); // clang-format on return dabRadioMock; diff --git a/broadcastradio/common/utilsaidl/Utils.cpp b/broadcastradio/common/utilsaidl/Utils.cpp index 0551badc45..de4f52926d 100644 --- a/broadcastradio/common/utilsaidl/Utils.cpp +++ b/broadcastradio/common/utilsaidl/Utils.cpp @@ -204,7 +204,7 @@ bool isSupported(const Properties& prop, const ProgramSelector& sel) { } bool isValid(const ProgramIdentifier& id) { - int64_t val = id.value; + uint64_t val = static_cast(id.value); bool valid = true; auto expect = [&valid](bool condition, const string& message) { @@ -231,11 +231,11 @@ bool isValid(const ProgramIdentifier& id) { expect(val <= 0xFFFFu, "16bit id"); break; case IdentifierType::HD_STATION_ID_EXT: { - int64_t stationId = val & 0xFFFFFFFF; // 32bit + uint64_t stationId = val & 0xFFFFFFFF; // 32bit val >>= 32; - int64_t subchannel = val & 0xF; // 4bit + uint64_t subchannel = val & 0xF; // 4bit val >>= 4; - int64_t freq = val & 0x3FFFF; // 18bit + uint64_t freq = val & 0x3FFFF; // 18bit expect(stationId != 0u, "HD station id != 0"); expect(subchannel < 8u, "HD subch < 8"); expect(freq > 100u, "f > 100kHz"); @@ -252,9 +252,9 @@ bool isValid(const ProgramIdentifier& id) { break; } case IdentifierType::DAB_SID_EXT: { - int64_t sid = val & 0xFFFFFFFF; // 32bit + uint64_t sid = val & 0xFFFFFFFF; // 32bit val >>= 32; - int64_t ecc = val & 0xFF; // 8bit + uint64_t ecc = val & 0xFF; // 8bit expect(sid != 0u, "DAB SId != 0"); expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1"); break; @@ -305,19 +305,19 @@ ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) { return {type, value}; } -ProgramSelector makeSelectorAmfm(int32_t frequency) { +ProgramSelector makeSelectorAmfm(uint32_t frequency) { ProgramSelector sel = {}; sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency); return sel; } -ProgramSelector makeSelectorDab(int64_t sidExt) { +ProgramSelector makeSelectorDab(uint64_t sidExt) { ProgramSelector sel = {}; sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt); return sel; } -ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq) { +ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) { ProgramSelector sel = {}; sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt); vector secondaryIds = { diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h index ad075f2943..ee85a178da 100644 --- a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h +++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h @@ -137,9 +137,9 @@ bool isValid(const ProgramIdentifier& id); bool isValid(const ProgramSelector& sel); ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value); -ProgramSelector makeSelectorAmfm(int32_t frequency); -ProgramSelector makeSelectorDab(int64_t sidExt); -ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq); +ProgramSelector makeSelectorAmfm(uint32_t frequency); +ProgramSelector makeSelectorDab(uint64_t sidExt); +ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq); bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel); From 3af92ba5637ebfe55bab6f04029345765423b45c Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Thu, 7 Sep 2023 23:59:03 +0000 Subject: [PATCH 119/152] compatibility_matrices: T launching devices allow to use light V1 AIDL. AIDL deprecation checks are only implemented in U, so the existing V2 requirement on the T matrix did not take effect on T branches. Hence, we shouldn't add requirements retroactively. Test: TH Bug: 298318354 (cherry picked from https://android-review.googlesource.com/q/commit:7e2962f03a649dd4eb34c86c0eb93c98a3bc93b4) Merged-In: Iaf38c6d6270f4aa9c7163540a396045be9d7865a Change-Id: Iaf38c6d6270f4aa9c7163540a396045be9d7865a --- compatibility_matrices/compatibility_matrix.7.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compatibility_matrices/compatibility_matrix.7.xml b/compatibility_matrices/compatibility_matrix.7.xml index e5ef954255..bc5a5c41d2 100644 --- a/compatibility_matrices/compatibility_matrix.7.xml +++ b/compatibility_matrices/compatibility_matrix.7.xml @@ -419,7 +419,7 @@ android.hardware.light - 2 + 1-2 ILights default From 37a6abe4c63e3c8f680f787fcf3138dcf4eb4a8b Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Fri, 8 Sep 2023 09:27:25 -0700 Subject: [PATCH 120/152] Clarify unsigned int type in AIDL program id Clarified that the value in ProgramIdentifier in AIDL broadcast radio HAL should be unsigned 64-bit int, but is represented as signed int since unsigned int types are not supported in AIDL. Bug: 299489486 Test: m -j (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:40a58baa2cf0380dcab908a6f1e3cf8fd11d351c) Merged-In: I2f35cefebdf1b5e39bf48cab896b077c4cb6c2e4 Change-Id: I2f35cefebdf1b5e39bf48cab896b077c4cb6c2e4 --- .../android/hardware/broadcastradio/ProgramIdentifier.aidl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl index 2057d97eb0..a2de5d6e21 100644 --- a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl +++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl @@ -30,8 +30,10 @@ parcelable ProgramIdentifier { IdentifierType type = IdentifierType.INVALID; /** - * The uint64_t value field holds the value in format described in comments - * for IdentifierType enum. + * The value field holds the value in format described in comments for IdentifierType enum. + * + * The value should be 64-bit unsigned integer, but is represented as 64-bit signed integer + * in AIDL. */ long value; } From ccf273d30774ce57c234112b98027f55c94bc1cb Mon Sep 17 00:00:00 2001 From: Aaqib Ismail Date: Thu, 14 Sep 2023 15:49:34 -0700 Subject: [PATCH 121/152] Fix clang lint warnings Bug: 291278377 Test: m Change-Id: Ifcfecc313c8d27fb04a20b4e6bf304b04f4a5b55 --- .../hardware/src/FakeVehicleHardware.cpp | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp index 46c67a517a..661438516d 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -205,9 +204,10 @@ void FakeVehicleHardware::storePropInitialValue(const ConfigDeclaration& config) // Create a separate instance for each individual zone VehiclePropValue prop = { + .timestamp = elapsedRealtimeNano(), .areaId = curArea, .prop = propId, - .timestamp = elapsedRealtimeNano(), + .value = {}, }; if (config.initialAreaValues.empty()) { @@ -938,7 +938,7 @@ FakeVehicleHardware::ValueResultType FakeVehicleHardware::getValue( << StringPrintf("failed to get special value: %d, error: %s", value.prop, getErrorMsg(result).c_str()); } else { - return std::move(result); + return result; } } @@ -953,7 +953,7 @@ FakeVehicleHardware::ValueResultType FakeVehicleHardware::getValue( } } - return std::move(readResult); + return readResult; } DumpResult FakeVehicleHardware::dump(const std::vector& options) { @@ -1328,9 +1328,9 @@ std::string FakeVehicleHardware::genFakeDataCommand(const std::vector FakeVehicleHardware::getOptionValues( while (*index < options.size()) { std::string option = options[*index]; if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) { - return std::move(values); + return values; } values.push_back(option); (*index)++; } - return std::move(values); + return values; } Result FakeVehicleHardware::parsePropOptions( @@ -1837,8 +1838,9 @@ StatusCode FakeVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId, // Refresh the property value. In real implementation, this should poll the latest value // from vehicle bus. Here, we are just refreshing the existing value with a new timestamp. auto result = getValue(VehiclePropValue{ - .prop = propId, .areaId = areaId, + .prop = propId, + .value = {}, }); if (!result.ok()) { // Failed to read current value, skip refreshing. From e63c5bb5c32fbda553637a4d43994e17af2b110c Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Thu, 14 Sep 2023 15:16:27 +0100 Subject: [PATCH 122/152] KeyMint: check missing EC_CURVE on v3+ The original change to add this test didn't make it into the Android 13 version of the VTS test, so the version gate needs to be updated to be v3+ Bug: 292318194 Test: VtsAidlKeyMintTargetTest --gtest_filter="*EcdsaMissingCurve*" (cherry picked from https://android-review.googlesource.com/q/commit:9ed7d2c5bfa3958ef399567e12d84a3f67f0cb80) Merged-In: I94bf816688e57c7c04893a23cf0399129de94229 Change-Id: I94bf816688e57c7c04893a23cf0399129de94229 --- security/keymint/aidl/vts/functional/KeyMintTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp index 1297d1d978..2e6fa3b492 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -2630,16 +2630,16 @@ TEST_P(NewKeyGenerationTest, EcdsaInvalidCurve) { /* * NewKeyGenerationTest.EcdsaMissingCurve * - * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V2. + * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V3. */ TEST_P(NewKeyGenerationTest, EcdsaMissingCurve) { - if (AidlVersion() < 2) { + if (AidlVersion() < 3) { /* * The KeyMint V1 spec required that EC_CURVE be specified for EC keys. * However, this was not checked at the time so we can only be strict about checking this - * for implementations of KeyMint version 2 and above. + * for implementations of KeyMint version 3 and above. */ - GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v2"; + GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v3"; } /* If EC_CURVE not provided, generateKey * must return ErrorCode::UNSUPPORTED_KEY_SIZE or ErrorCode::UNSUPPORTED_EC_CURVE. From 24e594e05e2a5a7c1fa201ee398940241eceb1e5 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Thu, 14 Sep 2023 11:16:27 +0100 Subject: [PATCH 123/152] KeyMint VTS: re-order auth failure arms Allow for devices that claim to need external timestamps, but don't. Test: VtsAidlKeyMintTargetTest Bug: 300211206 (cherry picked from https://android-review.googlesource.com/q/commit:a35699cb5cfef3773afebf51c2dd38530db43bf0) Merged-In: Ie450d9969c337d5274502f3600e14c0b481e8b34 Change-Id: Ie450d9969c337d5274502f3600e14c0b481e8b34 --- .../keymint/aidl/vts/functional/AuthTest.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/security/keymint/aidl/vts/functional/AuthTest.cpp b/security/keymint/aidl/vts/functional/AuthTest.cpp index 78c88f4896..6499f14347 100644 --- a/security/keymint/aidl/vts/functional/AuthTest.cpp +++ b/security/keymint/aidl/vts/functional/AuthTest.cpp @@ -329,14 +329,14 @@ TEST_P(AuthTest, TimeoutAuthentication) { // Wait for long enough that the hardware auth token expires. sleep(timeout_secs + 1); - if (!timestamp_token_required_) { - // KeyMint implementation has its own clock, and can immediately detect timeout. - EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, - Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat)); - } else { - // KeyMint implementation has no clock, so only detects timeout via timestamp token provided - // on update()/finish(). - ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat)); + + auto begin_result = Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat); + if (begin_result == ErrorCode::OK) { + // If begin() succeeds despite the out-of-date HAT, that must mean that the KeyMint + // device doesn't have its own clock. In that case, it only detects timeout via a + // timestamp token provided on update()/finish() + ASSERT_TRUE(timestamp_token_required_); + secureclock::TimeStampToken time_token; EXPECT_EQ(ErrorCode::OK, GetReturnErrorCode(clock_->generateTimeStamp(challenge_, &time_token))); @@ -344,6 +344,9 @@ TEST_P(AuthTest, TimeoutAuthentication) { string output; EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, Finish(message, {} /* signature */, &output, hat, time_token)); + } else { + // The KeyMint implementation may have its own clock that can immediately detect timeout. + ASSERT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, begin_result); } } From ff914778ef5b4f940bdb19f8c1ac2d2077357ee9 Mon Sep 17 00:00:00 2001 From: Gabriel Biren Date: Thu, 14 Sep 2023 23:41:45 +0000 Subject: [PATCH 124/152] Rename toggleWifiFramework in the Hostapd AIDL test utils in order to avoid having an ambigous function call. aosp/2728874 adds a method of the same name, which is causing pre-submit issues. Bug: 297820612 Test: atest VtsHalHostapdTargetTest Change-Id: Ie4da0a0037e7411e7908401f021b48246ea227bd Merged-In: Ie4da0a0037e7411e7908401f021b48246ea227bd (cherry picked from commit 94950dc20d0c64f458d87d72c895e253e2d4ad11) --- wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h b/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h index feee2c89b2..50a38d33fd 100644 --- a/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h +++ b/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h @@ -63,7 +63,7 @@ void waitForSupplicantState(bool enable) { LOG(ERROR) << "Unable to " << (enable ? "start" : "stop") << " supplicant"; } -void toggleWifiFramework(bool enable) { +void toggleWifiFrameworkAndScan(bool enable) { if (enable) { std::system("svc wifi enable"); std::system("cmd wifi set-scan-always-available enabled"); @@ -89,7 +89,7 @@ std::shared_ptr getHostapd(const std::string& hostapd_instance_name) { * any other clients to the HALs during testing. */ void disableHalsAndFramework() { - toggleWifiFramework(false); + toggleWifiFrameworkAndScan(false); stopHostapd(); stopVendorHal(); @@ -110,7 +110,7 @@ void stopHostapdAndVendorHal() { } void startWifiFramework() { - toggleWifiFramework(true); + toggleWifiFrameworkAndScan(true); } std::string setupApIfaceAndGetName(bool isBridged) { From 88aa5f6bcdc328288e7fc63b3dd10a815b8e611b Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 7 Sep 2023 22:50:11 -0700 Subject: [PATCH 125/152] Update VTS tests with EUTRAN instead of GERAN These tests were created for IRadio 1.2 when all devices supported GSM, and REQUEST_NOT_SUPPORTED was valid for devices that didn't support GSM. Change the VTS logic to test EUTRAN instead of GERAN. Remove REQUEST_NOT_SUPPORTED for tests now without GERAN and add REQUEST_NOT_SUPPORTED for all GERAN-specific tests. Test: atest VtsHalRadioTargetTest Bug: 294965245 Change-Id: Ib36b171e33451bf0c9adc0b065a4c74df357e77e --- radio/aidl/vts/radio_network_test.cpp | 248 +++++++------------------- 1 file changed, 67 insertions(+), 181 deletions(-) diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp index 253ef82d9f..6643c1e7ff 100644 --- a/radio/aidl/vts/radio_network_test.cpp +++ b/radio/aidl/vts/radio_network_test.cpp @@ -23,6 +23,19 @@ #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) +namespace { +const RadioAccessSpecifierBands EUTRAN_BAND_17 = + RadioAccessSpecifierBands::make( + {EutranBands::BAND_17}); +const RadioAccessSpecifierBands EUTRAN_BAND_20 = + RadioAccessSpecifierBands::make( + {EutranBands::BAND_20}); +const RadioAccessSpecifier EUTRAN_SPECIFIER_17 = { + .accessNetwork = AccessNetwork::EUTRAN, .bands = EUTRAN_BAND_17, .channels = {1, 2}}; +const RadioAccessSpecifier EUTRAN_SPECIFIER_20 = { + .accessNetwork = AccessNetwork::EUTRAN, .bands = EUTRAN_BAND_20, .channels = {128, 129}}; +} // namespace + void RadioNetworkTest::SetUp() { RadioServiceTest::SetUp(); std::string serviceName = GetParam(); @@ -289,7 +302,7 @@ TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_invalidHysteresisDb) signalThresholdInfo.hysteresisDb = 10; // hysteresisDb too large given threshold list deltas signalThresholdInfo.thresholds = {-109, -103, -97, -89}; signalThresholdInfo.isEnabled = true; - signalThresholdInfo.ran = AccessNetwork::GERAN; + signalThresholdInfo.ran = AccessNetwork::EUTRAN; ndk::ScopedAStatus res = radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo}); @@ -314,7 +327,7 @@ TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_EmptyThresholds) { signalThresholdInfo.hysteresisMs = 0; signalThresholdInfo.hysteresisDb = 0; signalThresholdInfo.isEnabled = true; - signalThresholdInfo.ran = AccessNetwork::GERAN; + signalThresholdInfo.ran = AccessNetwork::EUTRAN; ndk::ScopedAStatus res = radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo}); @@ -351,7 +364,8 @@ TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Geran) { ALOGI("setSignalStrengthReportingCriteria_Geran, rspInfo.error = %s\n", toString(radioRsp_network->rspInfo.error).c_str()); - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, + {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } /* @@ -677,7 +691,7 @@ TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_multiRansPerRequest) ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); if (radioRsp_network->rspInfo.error == RadioError::NONE) { - supportedSignalThresholdInfos.push_back(signalThresholdInfoGeran); + supportedSignalThresholdInfos.push_back(signalThresholdInfoEutran); } else { // Refer to IRadioNetworkResponse#setSignalStrengthReportingCriteriaResponse ASSERT_TRUE(CheckAnyOfErrors( @@ -711,7 +725,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisDlKbp ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria( serial, 5000, 5000, // hysteresisDlKbps too big for thresholds delta - 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::GERAN); + 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::EUTRAN); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -719,11 +733,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisDlKbp ALOGI("setLinkCapacityReportingCriteria_invalidHysteresisDlKbps, rspInfo.error = %s\n", toString(radioRsp_network->rspInfo.error).c_str()); - // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported - // for GERAN - ASSERT_TRUE( - CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } /* @@ -734,7 +744,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisUlKbp ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria( serial, 5000, 500, 1000, // hysteresisUlKbps too big for thresholds delta - {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::GERAN); + {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::EUTRAN); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -742,11 +752,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisUlKbp ALOGI("setLinkCapacityReportingCriteria_invalidHysteresisUlKbps, rspInfo.error = %s\n", toString(radioRsp_network->rspInfo.error).c_str()); - // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported - // for GERAN - ASSERT_TRUE( - CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } /* @@ -756,7 +762,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_emptyParams) { serial = GetRandomSerialNumber(); ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria( - serial, 0, 0, 0, {}, {}, AccessNetwork::GERAN); + serial, 0, 0, 0, {}, {}, AccessNetwork::EUTRAN); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -764,10 +770,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_emptyParams) { ALOGI("setLinkCapacityReportingCriteria_emptyParams, rspInfo.error = %s\n", toString(radioRsp_network->rspInfo.error).c_str()); - // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported - // for GERAN - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE})); } /* @@ -808,19 +811,9 @@ TEST_P(RadioNetworkTest, setSystemSelectionChannels) { } std::vector originalSpecifiers = radioRsp_network->specifiers; - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - serial = GetRandomSerialNumber(); - res = radio_network->setSystemSelectionChannels(serial, true, {specifierP900, specifier850}); + res = radio_network->setSystemSelectionChannels(serial, true, + {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -833,8 +826,8 @@ TEST_P(RadioNetworkTest, setSystemSelectionChannels) { if (radioRsp_network->rspInfo.error == RadioError::NONE) { serial = GetRandomSerialNumber(); - res = radio_network->setSystemSelectionChannels(serial, false, - {specifierP900, specifier850}); + res = radio_network->setSystemSelectionChannels( + serial, false, {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -857,20 +850,9 @@ TEST_P(RadioNetworkTest, setSystemSelectionChannels) { TEST_P(RadioNetworkTest, startNetworkScan) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands band17 = - RadioAccessSpecifierBands::make( - {EutranBands::BAND_17}); - RadioAccessSpecifierBands band20 = - RadioAccessSpecifierBands::make( - {EutranBands::BAND_20}); - RadioAccessSpecifier specifier17 = { - .accessNetwork = AccessNetwork::EUTRAN, .bands = band17, .channels = {1, 2}}; - RadioAccessSpecifier specifier20 = { - .accessNetwork = AccessNetwork::EUTRAN, .bands = band20, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifier17, specifier20}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 60, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -892,10 +874,9 @@ TEST_P(RadioNetworkTest, startNetworkScan) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED})); } else { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED, RadioError::NONE, - RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, + {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED, + RadioError::INVALID_ARGUMENTS})); } } @@ -925,9 +906,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidArgument) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -937,20 +917,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidArgument) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC, .interval = 4, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 60, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -966,9 +935,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -978,20 +946,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC, .interval = 301, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 60, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -1007,9 +964,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1019,20 +975,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 59, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -1048,9 +993,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1060,20 +1004,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 3601, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -1089,9 +1022,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1101,20 +1033,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 600, .incrementalResults = true, .incrementalResultsPeriodicity = 0}; @@ -1130,9 +1051,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1142,20 +1062,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 600, .incrementalResults = true, .incrementalResultsPeriodicity = 11}; @@ -1171,9 +1080,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1183,20 +1091,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) { TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 360, .incrementalResults = false, .incrementalResultsPeriodicity = 10}; @@ -1213,8 +1110,7 @@ TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) { {RadioError::NONE, RadioError::SIM_ABSENT})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::INVALID_ARGUMENTS, - RadioError::REQUEST_NOT_SUPPORTED})); + {RadioError::NONE, RadioError::INVALID_ARGUMENTS})); } if (radioRsp_network->rspInfo.error == RadioError::NONE) { @@ -1229,20 +1125,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) { TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest2) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 360, .incrementalResults = false, .incrementalResultsPeriodicity = 10, @@ -1260,8 +1145,7 @@ TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest2) { {RadioError::NONE, RadioError::SIM_ABSENT})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::INVALID_ARGUMENTS, - RadioError::REQUEST_NOT_SUPPORTED})); + {RadioError::NONE, RadioError::INVALID_ARGUMENTS})); } if (radioRsp_network->rspInfo.error == RadioError::NONE) { @@ -1278,21 +1162,23 @@ TEST_P(RadioNetworkTest, setNetworkSelectionModeManual) { // can't camp on nonexistent MCCMNC, so we expect this to fail. ndk::ScopedAStatus res = - radio_network->setNetworkSelectionModeManual(serial, "123456", AccessNetwork::GERAN); + radio_network->setNetworkSelectionModeManual(serial, "123456", AccessNetwork::EUTRAN); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); EXPECT_EQ(serial, radioRsp_network->rspInfo.serial); if (cardStatus.cardState == CardStatus::STATE_ABSENT) { - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, - RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, - CHECK_GENERAL_ERROR)); + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_network->rspInfo.error, + {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, RadioError::INVALID_ARGUMENTS, + RadioError::INVALID_STATE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NO_MEMORY, + RadioError::INTERNAL_ERR, RadioError::SYSTEM_ERR, RadioError::CANCELLED})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, - RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, - CHECK_GENERAL_ERROR)); + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_network->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS, + RadioError::INVALID_STATE, RadioError::NO_MEMORY, RadioError::INTERNAL_ERR, + RadioError::SYSTEM_ERR, RadioError::CANCELLED})); } } From e59a6ce2e0c114407cb417d1ef1f9437b6b09570 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 23 Aug 2023 14:11:42 -0700 Subject: [PATCH 126/152] audio: Make IConfig.getSurroundSound default implementation more robust In the case when there is a problem with the legacy APM XML file, the converter provides a default surround sound config. However, the default implementation of IConfig::getSurroundSoundConfig did not take an advantage of that, and was returning an empty config, which is not accepted by VTS. Also, improve logging messages: clarify the situation when no readable audio policy XML file found, and use outer functions name for lambdas. Bug: 293978054 Test: atest VtsHalAudioCoreTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:1e25ef808f5e6a29d2a889213f4b42cf58ecdc29) Merged-In: Iae069a0498009605ef5ededb9c9112efab08548a Change-Id: Iae069a0498009605ef5ededb9c9112efab08548a --- audio/aidl/default/Config.cpp | 18 +++++++++--------- .../default/include/core-impl/XmlConverter.h | 12 +++++++++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp index d1023da6f5..308200abf6 100644 --- a/audio/aidl/default/Config.cpp +++ b/audio/aidl/default/Config.cpp @@ -27,12 +27,11 @@ using aidl::android::media::audio::common::AudioHalEngineConfig; namespace aidl::android::hardware::audio::core { ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) { + static const auto& func = __func__; static const SurroundSoundConfig surroundSoundConfig = [this]() { - SurroundSoundConfig surroundCfg; - if (mAudioPolicyConverter.getStatus() == ::android::OK) { - surroundCfg = mAudioPolicyConverter.getSurroundSoundConfig(); - } else { - LOG(WARNING) << __func__ << mAudioPolicyConverter.getError(); + SurroundSoundConfig surroundCfg = mAudioPolicyConverter.getSurroundSoundConfig(); + if (mAudioPolicyConverter.getStatus() != ::android::OK) { + LOG(WARNING) << func << ": " << mAudioPolicyConverter.getError(); } return surroundCfg; }(); @@ -42,21 +41,22 @@ ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_ret } ndk::ScopedAStatus Config::getEngineConfig(AudioHalEngineConfig* _aidl_return) { + static const auto& func = __func__; static const AudioHalEngineConfig returnEngCfg = [this]() { AudioHalEngineConfig engConfig; if (mEngConfigConverter.getStatus() == ::android::OK) { engConfig = mEngConfigConverter.getAidlEngineConfig(); } else { - LOG(INFO) << __func__ << mEngConfigConverter.getError(); + LOG(INFO) << func << ": " << mEngConfigConverter.getError(); if (mAudioPolicyConverter.getStatus() == ::android::OK) { engConfig = mAudioPolicyConverter.getAidlEngineConfig(); } else { - LOG(WARNING) << __func__ << mAudioPolicyConverter.getError(); + LOG(WARNING) << func << ": " << mAudioPolicyConverter.getError(); } } // Logging full contents of the config is an overkill, just provide statistics. - LOG(DEBUG) << "getEngineConfig: number of strategies parsed: " - << engConfig.productStrategies.size() + LOG(DEBUG) << func + << ": number of strategies parsed: " << engConfig.productStrategies.size() << ", default strategy: " << engConfig.defaultProductStrategyId << ", number of volume groups parsed: " << engConfig.volumeGroups.size(); return engConfig; diff --git a/audio/aidl/default/include/core-impl/XmlConverter.h b/audio/aidl/default/include/core-impl/XmlConverter.h index a68a6fdde9..383ea24836 100644 --- a/audio/aidl/default/include/core-impl/XmlConverter.h +++ b/audio/aidl/default/include/core-impl/XmlConverter.h @@ -53,10 +53,16 @@ class XmlConverter { const ::android::status_t& status) { std::string errorMessage; if (status != ::android::OK) { - if (!isReadableConfigFile) { - errorMessage = "Could not read requested config file:" + configFilePath; + if (configFilePath.empty()) { + errorMessage = "No audio configuration files found"; + } else if (!isReadableConfigFile) { + errorMessage = std::string("Could not read requested XML config file: \"") + .append(configFilePath) + .append("\""); } else { - errorMessage = "Invalid config file: " + configFilePath; + errorMessage = std::string("Invalid XML config file: \"") + .append(configFilePath) + .append("\""); } } return errorMessage; From 2e53f30f72afaf215606a8076df09f09cb8364cc Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Fri, 18 Aug 2023 23:58:05 +0000 Subject: [PATCH 127/152] Remove the limitation of max open streams Bug: 295055755 Test: atest CtsMediaAudioTestCases (cherry picked from https://android-review.googlesource.com/q/commit:2461891a1c7cc29352e82cb6fd1f23587422aa28) Merged-In: Ifc0bec23ccc2845657389783194eb18fcc7884fa Change-Id: Ifc0bec23ccc2845657389783194eb18fcc7884fa --- audio/aidl/default/Configuration.cpp | 4 ++-- audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index 8e02e7dfa7..9131935f87 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -230,14 +230,14 @@ std::unique_ptr getPrimaryConfiguration() { AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output", makeBitPositionFlagMask(AudioOutputFlags::PRIMARY), - false, createPortMixExt(1, 1)); + false, createPortMixExt(0, 0)); primaryOutMix.profiles.insert(primaryOutMix.profiles.begin(), standardPcmAudioProfiles.begin(), standardPcmAudioProfiles.end()); c.ports.push_back(primaryOutMix); AudioPort primaryInMix = - createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(1, 1)); + createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 0)); primaryInMix.profiles.push_back( createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index 68e7151191..8a8998e10c 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -1379,7 +1379,7 @@ TEST_P(AudioCoreModule, CheckMixPorts) { << "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value() << " and " << port.id; primaryMixPort = port.id; - EXPECT_EQ(1, mixPort.maxOpenStreamCount) + EXPECT_GE(mixPort.maxOpenStreamCount, 0) << "Primary mix port " << port.id << " can not have maxOpenStreamCount " << mixPort.maxOpenStreamCount; } From 9a4436477fe8611975f6413f8fdb4d55a7e3ba51 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Thu, 7 Sep 2023 17:52:45 +0000 Subject: [PATCH 128/152] Remove unused file EffectWorker.h Bug: 299213582 Test: m (cherry picked from https://android-review.googlesource.com/q/commit:5b8638c66c2113d13a2aaef505fa7a60b95f3811) Merged-In: I9ffd2e4e1cf1fbca69650eb101812db2ed3acc6f Change-Id: I9ffd2e4e1cf1fbca69650eb101812db2ed3acc6f --- .../include/effect-impl/EffectWorker.h | 74 ------------------- 1 file changed, 74 deletions(-) delete mode 100644 audio/aidl/default/include/effect-impl/EffectWorker.h diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h deleted file mode 100644 index 421429acaf..0000000000 --- a/audio/aidl/default/include/effect-impl/EffectWorker.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include -#include -#include -#include - -#include "EffectContext.h" -#include "EffectThread.h" - -namespace aidl::android::hardware::audio::effect { - -std::string toString(RetCode& code); - -class EffectWorker : public EffectThread { - public: - // set effect context for worker, suppose to only happen once here - void setContext(std::shared_ptr context) { - std::call_once(mOnceFlag, [&]() { mContext = context; }); - }; - - // handle FMQ and call effect implemented virtual function - void process() override { - RETURN_VALUE_IF(!mContext, void(), "nullContext"); - std::shared_ptr statusMQ = mContext->getStatusFmq(); - std::shared_ptr inputMQ = mContext->getInputDataFmq(); - std::shared_ptr outputMQ = mContext->getOutputDataFmq(); - - // Only this worker will read from input data MQ and write to output data MQ. - auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite(); - if (readSamples && writeSamples) { - auto processSamples = std::min(readSamples, writeSamples); - LOG(VERBOSE) << __func__ << " available to read " << readSamples - << " available to write " << writeSamples << " process " << processSamples; - - auto buffer = mContext->getWorkBuffer(); - inputMQ->read(buffer, processSamples); - - IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples); - outputMQ->write(buffer, status.fmqProduced); - statusMQ->writeBlocking(&status, 1); - LOG(VERBOSE) << __func__ << " done processing, effect consumed " << status.fmqConsumed - << " produced " << status.fmqProduced; - } else { - // TODO: maybe add some sleep here to avoid busy waiting - } - } - - // must implement by each effect implementation - // TODO: consider if this interface need adjustment to handle in-place processing - virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0; - - private: - // make sure the context only set once. - std::once_flag mOnceFlag; - std::shared_ptr mContext; -}; - -} // namespace aidl::android::hardware::audio::effect From 2dc898026a2e3f9eb536139f10b56799da6ae98e Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 7 Sep 2023 16:30:11 -0700 Subject: [PATCH 129/152] audio: Properly support external device port with static configs External device ports might not have dynamic profiles, for example, ports for BT devices. Properly handle this case in the default implementation. Bug: 264712385 Test: atest VtsHalAudioCoreTargetTest Test: atest audiosystem_tests (cherry picked from https://android-review.googlesource.com/q/commit:fcf980e586d9b0f5ad09ba9098cd2c77911526b4) Merged-In: I8d4bcbf6ccf2ba05436e68e3ba94567fc7610eb7 Change-Id: I8d4bcbf6ccf2ba05436e68e3ba94567fc7610eb7 --- audio/aidl/default/Module.cpp | 37 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index f81095e02c..b7761bf244 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -454,16 +454,15 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA LOG(ERROR) << __func__ << ": port id " << templateId << " is not a device port"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } - if (!templateIt->profiles.empty()) { - LOG(ERROR) << __func__ << ": port id " << templateId - << " does not have dynamic profiles"; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } auto& templateDevicePort = templateIt->ext.get(); if (templateDevicePort.device.type.connection.empty()) { LOG(ERROR) << __func__ << ": port id " << templateId << " is permanently attached"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } + if (mConnectedDevicePorts.find(templateId) != mConnectedDevicePorts.end()) { + LOG(ERROR) << __func__ << ": port id " << templateId << " is a connected device port"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } // Postpone id allocation until we ensure that there are no client errors. connectedPort = *templateIt; connectedPort.extraAudioDescriptors = in_templateIdAndAdditionalData.extraAudioDescriptors; @@ -486,19 +485,23 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA } } - if (!mDebug.simulateDeviceConnections) { - RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort)); - } else { - auto& connectedProfiles = getConfig().connectedProfiles; - if (auto connectedProfilesIt = connectedProfiles.find(templateId); - connectedProfilesIt != connectedProfiles.end()) { - connectedPort.profiles = connectedProfilesIt->second; - } - } if (connectedPort.profiles.empty()) { - LOG(ERROR) << "Profiles of a connected port still empty after connecting external device " - << connectedPort.toString(); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + if (!mDebug.simulateDeviceConnections) { + RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort)); + } else { + auto& connectedProfiles = getConfig().connectedProfiles; + if (auto connectedProfilesIt = connectedProfiles.find(templateId); + connectedProfilesIt != connectedProfiles.end()) { + connectedPort.profiles = connectedProfilesIt->second; + } + } + if (connectedPort.profiles.empty()) { + LOG(ERROR) << __func__ + << ": profiles of a connected port still empty after connecting external " + "device " + << connectedPort.toString(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } } for (auto profile : connectedPort.profiles) { From 1a828f1f95e8ee7f2f05de4cfcde0ddc9932d0b8 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Thu, 7 Sep 2023 17:42:39 +0000 Subject: [PATCH 130/152] Avoid sub_overflow_minimal in AIDL effects VTS Bug: 299385610 Test: atest VtsHalHapticGeneratorTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:5ed80c5144d6b0e9064e7c5a34343de29d6f431e) Merged-In: I1721fb87dd373a40453505733c8aaee647b4cf3b Change-Id: I1721fb87dd373a40453505733c8aaee647b4cf3b --- audio/aidl/vts/EffectHelper.h | 6 +++--- audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h index 685d07d191..2c8edf28fb 100644 --- a/audio/aidl/vts/EffectHelper.h +++ b/audio/aidl/vts/EffectHelper.h @@ -250,11 +250,11 @@ class EffectHelper { maxLimit = std::numeric_limits::max(); if (s.size()) { const auto min = *s.begin(), max = *s.rbegin(); - s.insert(min + (max - min) / 2); - if (min != minLimit) { + s.insert((min & max) + ((min ^ max) >> 1)); + if (min > minLimit + 1) { s.insert(min - 1); } - if (max != maxLimit) { + if (max < maxLimit - 1) { s.insert(max + 1); } } diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp index 54caed920e..b33234b04b 100644 --- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp +++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp @@ -208,7 +208,7 @@ INSTANTIATE_TEST_SUITE_P( HapticGeneratorInvalidTest, HapticGeneratorParamTest, ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( IFactory::descriptor, getEffectTypeUuidHapticGenerator())), - testing::Values(MIN_ID - 1), + testing::Values(MIN_ID), testing::Values(HapticGenerator::VibratorScale::NONE), testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT)), From e8ae75d310311691f668e8aac7ee92149ce3c8c7 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Tue, 22 Aug 2023 15:07:16 +0000 Subject: [PATCH 131/152] r_submix : Fix minor issues in AIDL implementation 1. Update refinePosition for output stream 2. Add missing exitStandby on transfer 3. Add check for availableToRead in read functionality Bug: 286914845 Test: atest VtsHalAudioCoreTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:95f9232923139f38d802054f5df27a73f1328a09) Merged-In: Ibab914e5e09474c2b55a6c64cc004ebc1bb6cb47 Change-Id: Ibab914e5e09474c2b55a6c64cc004ebc1bb6cb47 --- .../default/r_submix/StreamRemoteSubmix.cpp | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp index 3134b86841..9c9c08b048 100644 --- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp +++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp @@ -179,7 +179,7 @@ void StreamRemoteSubmix::shutdown() { LOG(ERROR) << __func__ << ": transfer without a pipe!"; return ::android::UNEXPECTED_NULL; } - + mCurrentRoute->exitStandby(mIsInput); return (mIsInput ? inRead(buffer, frameCount, actualFrameCount) : outWrite(buffer, frameCount, actualFrameCount)); } @@ -190,17 +190,14 @@ void StreamRemoteSubmix::shutdown() { return ::android::NO_INIT; } const ssize_t framesInPipe = source->availableToRead(); - if (framesInPipe < 0) { - return ::android::INVALID_OPERATION; + if (framesInPipe <= 0) { + // No need to update the position frames + return ::android::OK; } if (mIsInput) { position->frames += framesInPipe; - } else { - if (position->frames > framesInPipe) { - position->frames -= framesInPipe; - } else { - position->frames = 0; - } + } else if (position->frames >= framesInPipe) { + position->frames -= framesInPipe; } return ::android::OK; } @@ -280,18 +277,14 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { size_t* actualFrameCount) { // about to read from audio source sp source = mCurrentRoute->getSource(); - if (source == nullptr || source->availableToRead() == 0) { - if (source == nullptr) { - int readErrorCount = mCurrentRoute->notifyReadError(); - if (readErrorCount < kMaxReadErrorLogs) { - LOG(ERROR) << __func__ - << ": no audio pipe yet we're trying to read! (not all errors will be " - "logged)"; - } else { - LOG(ERROR) << __func__ << ": Read errors " << readErrorCount; - } + if (source == nullptr) { + int readErrorCount = mCurrentRoute->notifyReadError(); + if (readErrorCount < kMaxReadErrorLogs) { + LOG(ERROR) << __func__ + << ": no audio pipe yet we're trying to read! (not all errors will be " + "logged)"; } else { - LOG(INFO) << __func__ << ": no data to read yet, providing empty data"; + LOG(ERROR) << __func__ << ": Read errors " << readErrorCount; } const size_t delayUs = static_cast( std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate)); @@ -306,9 +299,10 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { const size_t delayUs = static_cast(std::roundf(kReadAttemptSleepUs)); char* buff = (char*)buffer; size_t remainingFrames = frameCount; + int availableToRead = source->availableToRead(); - while ((remainingFrames > 0) && (attempts < kMaxReadFailureAttempts)) { - LOG(VERBOSE) << __func__ << ": frames available to read " << source->availableToRead(); + while ((remainingFrames > 0) && (availableToRead > 0) && (attempts < kMaxReadFailureAttempts)) { + LOG(VERBOSE) << __func__ << ": frames available to read " << availableToRead; ssize_t framesRead = source->read(buff, remainingFrames); @@ -317,6 +311,7 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() { if (framesRead > 0) { remainingFrames -= framesRead; buff += framesRead * mStreamConfig.frameSize; + availableToRead -= framesRead; LOG(VERBOSE) << __func__ << ": (attempts = " << attempts << ") got " << framesRead << " frames, remaining=" << remainingFrames; } else { From 4329d375fe167e3dde7a47b14bec10a275678fb8 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Wed, 23 Aug 2023 12:39:15 +0000 Subject: [PATCH 132/152] Audio : Add 3 VTS test cases for remote submix module 1. OutputDoesNotBlockWhenNoInput 2. OutputDoesNotBlockWhenInputStuck 3. OutputAndInput Bug: 286914845 Test: atest AudioModuleRemoteSubmix (cherry picked from https://android-review.googlesource.com/q/commit:343db5e85e5e78e13179872e535c2248989cf081) Merged-In: I19a08bf2bf39131a70a867280c758b5ef001c024 Change-Id: I19a08bf2bf39131a70a867280c758b5ef001c024 --- audio/aidl/vts/ModuleConfig.cpp | 170 ++++++++++--- audio/aidl/vts/ModuleConfig.h | 71 ++++-- .../vts/VtsHalAudioCoreModuleTargetTest.cpp | 229 +++++++++++++++--- 3 files changed, 383 insertions(+), 87 deletions(-) diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp index 7213034bcc..8fdb1552df 100644 --- a/audio/aidl/vts/ModuleConfig.cpp +++ b/audio/aidl/vts/ModuleConfig.cpp @@ -66,15 +66,36 @@ std::optional ModuleConfig::generateOffloadInfoIfNeeded( return {}; } +std::vector +ModuleConfig::getAudioPortsForDeviceTypes(const std::vector& deviceTypes, + const std::string& connection) { + return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection); +} + // static std::vector ModuleConfig::getBuiltInMicPorts( const std::vector& ports) { + return getAudioPortsForDeviceTypes( + ports, std::vector{AudioDeviceType::IN_MICROPHONE, + AudioDeviceType::IN_MICROPHONE_BACK}); +} + +std::vector +ModuleConfig::getAudioPortsForDeviceTypes( + const std::vector& ports, + const std::vector& deviceTypes, const std::string& connection) { std::vector result; - std::copy_if(ports.begin(), ports.end(), std::back_inserter(result), [](const auto& port) { - const auto type = port.ext.template get().device.type; - return type.connection.empty() && (type.type == AudioDeviceType::IN_MICROPHONE || - type.type == AudioDeviceType::IN_MICROPHONE_BACK); - }); + for (const auto& port : ports) { + if (port.ext.getTag() != AudioPortExt::Tag::device) continue; + const auto type = port.ext.get().device.type; + if (type.connection == connection) { + for (auto deviceType : deviceTypes) { + if (type.type == deviceType) { + result.push_back(port); + } + } + } + } return result; } @@ -119,6 +140,31 @@ std::vector ModuleConfig::getAttachedDevicePorts() const { return result; } +std::vector ModuleConfig::getConnectedExternalDevicePorts() const { + std::vector result; + std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) { + return mConnectedExternalSinkDevicePorts.count(port.id) != 0 || + mConnectedExternalSourceDevicePorts.count(port.id) != 0; + }); + return result; +} + +std::set ModuleConfig::getConnectedSinkDevicePorts() const { + std::set result; + result.insert(mAttachedSinkDevicePorts.begin(), mAttachedSinkDevicePorts.end()); + result.insert(mConnectedExternalSinkDevicePorts.begin(), + mConnectedExternalSinkDevicePorts.end()); + return result; +} + +std::set ModuleConfig::getConnectedSourceDevicePorts() const { + std::set result; + result.insert(mAttachedSourceDevicePorts.begin(), mAttachedSourceDevicePorts.end()); + result.insert(mConnectedExternalSourceDevicePorts.begin(), + mConnectedExternalSourceDevicePorts.end()); + return result; +} + std::vector ModuleConfig::getExternalDevicePorts() const { std::vector result; std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), @@ -126,76 +172,77 @@ std::vector ModuleConfig::getExternalDevicePorts() const { return result; } -std::vector ModuleConfig::getInputMixPorts(bool attachedOnly) const { +std::vector ModuleConfig::getInputMixPorts(bool connectedOnly) const { std::vector result; std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) { return port.ext.getTag() == AudioPortExt::Tag::mix && port.flags.getTag() == AudioIoFlags::Tag::input && - (!attachedOnly || !getAttachedSourceDevicesPortsForMixPort(port).empty()); + (!connectedOnly || !getConnectedSourceDevicesPortsForMixPort(port).empty()); }); return result; } -std::vector ModuleConfig::getOutputMixPorts(bool attachedOnly) const { +std::vector ModuleConfig::getOutputMixPorts(bool connectedOnly) const { std::vector result; std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) { return port.ext.getTag() == AudioPortExt::Tag::mix && port.flags.getTag() == AudioIoFlags::Tag::output && - (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty()); + (!connectedOnly || !getConnectedSinkDevicesPortsForMixPort(port).empty()); }); return result; } -std::vector ModuleConfig::getNonBlockingMixPorts(bool attachedOnly, +std::vector ModuleConfig::getNonBlockingMixPorts(bool connectedOnly, bool singlePort) const { - return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) { + return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) { return isBitPositionFlagSet(port.flags.get(), AudioOutputFlags::NON_BLOCKING); }); } -std::vector ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const { - return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) { +std::vector ModuleConfig::getOffloadMixPorts(bool connectedOnly, bool singlePort) const { + return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) { return isBitPositionFlagSet(port.flags.get(), AudioOutputFlags::COMPRESS_OFFLOAD); }); } -std::vector ModuleConfig::getPrimaryMixPorts(bool attachedOnly, bool singlePort) const { - return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) { +std::vector ModuleConfig::getPrimaryMixPorts(bool connectedOnly, bool singlePort) const { + return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) { return isBitPositionFlagSet(port.flags.get(), AudioOutputFlags::PRIMARY); }); } -std::vector ModuleConfig::getMmapOutMixPorts(bool attachedOnly, bool singlePort) const { - return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) { +std::vector ModuleConfig::getMmapOutMixPorts(bool connectedOnly, bool singlePort) const { + return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) { return isBitPositionFlagSet(port.flags.get(), AudioOutputFlags::MMAP_NOIRQ); }); } -std::vector ModuleConfig::getMmapInMixPorts(bool attachedOnly, bool singlePort) const { - return findMixPorts(true /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) { +std::vector ModuleConfig::getMmapInMixPorts(bool connectedOnly, bool singlePort) const { + return findMixPorts(true /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) { return isBitPositionFlagSet(port.flags.get(), AudioInputFlags::MMAP_NOIRQ); }); } -std::vector ModuleConfig::getAttachedDevicesPortsForMixPort( +std::vector ModuleConfig::getConnectedDevicesPortsForMixPort( bool isInput, const AudioPortConfig& mixPortConfig) const { const auto mixPortIt = findById(mPorts, mixPortConfig.portId); if (mixPortIt != mPorts.end()) { - return getAttachedDevicesPortsForMixPort(isInput, *mixPortIt); + return getConnectedDevicesPortsForMixPort(isInput, *mixPortIt); } return {}; } -std::vector ModuleConfig::getAttachedSinkDevicesPortsForMixPort( +std::vector ModuleConfig::getConnectedSinkDevicesPortsForMixPort( const AudioPort& mixPort) const { std::vector result; + std::set connectedSinkDevicePorts = getConnectedSinkDevicePorts(); for (const auto& route : mRoutes) { - if (mAttachedSinkDevicePorts.count(route.sinkPortId) != 0 && + if ((connectedSinkDevicePorts.count(route.sinkPortId) != 0) && std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(), mixPort.id) != route.sourcePortIds.end()) { const auto devicePortIt = findById(mPorts, route.sinkPortId); @@ -205,13 +252,14 @@ std::vector ModuleConfig::getAttachedSinkDevicesPortsForMixPort( return result; } -std::vector ModuleConfig::getAttachedSourceDevicesPortsForMixPort( +std::vector ModuleConfig::getConnectedSourceDevicesPortsForMixPort( const AudioPort& mixPort) const { std::vector result; + std::set connectedSourceDevicePorts = getConnectedSourceDevicePorts(); for (const auto& route : mRoutes) { if (route.sinkPortId == mixPort.id) { for (const auto srcId : route.sourcePortIds) { - if (mAttachedSourceDevicePorts.count(srcId) != 0) { + if (connectedSourceDevicePorts.count(srcId) != 0) { const auto devicePortIt = findById(mPorts, srcId); if (devicePortIt != mPorts.end()) result.push_back(*devicePortIt); } @@ -221,9 +269,10 @@ std::vector ModuleConfig::getAttachedSourceDevicesPortsForMixPort( return result; } -std::optional ModuleConfig::getSourceMixPortForAttachedDevice() const { +std::optional ModuleConfig::getSourceMixPortForConnectedDevice() const { + std::set connectedSinkDevicePorts = getConnectedSinkDevicePorts(); for (const auto& route : mRoutes) { - if (mAttachedSinkDevicePorts.count(route.sinkPortId) != 0) { + if (connectedSinkDevicePorts.count(route.sinkPortId) != 0) { const auto mixPortIt = findById(mPorts, route.sourcePortIds[0]); if (mixPortIt != mPorts.end()) return *mixPortIt; } @@ -233,7 +282,7 @@ std::optional ModuleConfig::getSourceMixPortForAttachedDevice() const std::optional ModuleConfig::getNonRoutableSrcSinkPair( bool isInput) const { - const auto mixPorts = getMixPorts(isInput, false /*attachedOnly*/); + const auto mixPorts = getMixPorts(isInput, false /*connectedOnly*/); std::set> allowedRoutes; for (const auto& route : mRoutes) { for (const auto srcPortId : route.sourcePortIds) { @@ -243,7 +292,8 @@ std::optional ModuleConfig::getNonRoutableSrcSinkPair auto make_pair = [isInput](auto& device, auto& mix) { return isInput ? std::make_pair(device, mix) : std::make_pair(mix, device); }; - for (const auto portId : isInput ? mAttachedSourceDevicePorts : mAttachedSinkDevicePorts) { + for (const auto portId : + isInput ? getConnectedSourceDevicePorts() : getConnectedSinkDevicePorts()) { const auto devicePortIt = findById(mPorts, portId); if (devicePortIt == mPorts.end()) continue; auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt); @@ -262,10 +312,11 @@ std::optional ModuleConfig::getNonRoutableSrcSinkPair std::optional ModuleConfig::getRoutableSrcSinkPair(bool isInput) const { if (isInput) { + std::set connectedSourceDevicePorts = getConnectedSourceDevicePorts(); for (const auto& route : mRoutes) { auto srcPortIdIt = std::find_if( route.sourcePortIds.begin(), route.sourcePortIds.end(), - [&](const auto& portId) { return mAttachedSourceDevicePorts.count(portId); }); + [&](const auto& portId) { return connectedSourceDevicePorts.count(portId); }); if (srcPortIdIt == route.sourcePortIds.end()) continue; const auto devicePortIt = findById(mPorts, *srcPortIdIt); const auto mixPortIt = findById(mPorts, route.sinkPortId); @@ -276,8 +327,9 @@ std::optional ModuleConfig::getRoutableSrcSinkPair(bo return std::make_pair(devicePortConfig, mixPortConfig.value()); } } else { + std::set connectedSinkDevicePorts = getConnectedSinkDevicePorts(); for (const auto& route : mRoutes) { - if (mAttachedSinkDevicePorts.count(route.sinkPortId) == 0) continue; + if (connectedSinkDevicePorts.count(route.sinkPortId) == 0) continue; const auto mixPortIt = findById(mPorts, route.sourcePortIds[0]); const auto devicePortIt = findById(mPorts, route.sinkPortId); if (devicePortIt == mPorts.end() || mixPortIt == mPorts.end()) continue; @@ -293,11 +345,12 @@ std::optional ModuleConfig::getRoutableSrcSinkPair(bo std::vector ModuleConfig::getRoutableSrcSinkGroups(bool isInput) const { std::vector result; if (isInput) { + std::set connectedSourceDevicePorts = getConnectedSourceDevicePorts(); for (const auto& route : mRoutes) { std::vector srcPortIds; std::copy_if(route.sourcePortIds.begin(), route.sourcePortIds.end(), std::back_inserter(srcPortIds), [&](const auto& portId) { - return mAttachedSourceDevicePorts.count(portId); + return connectedSourceDevicePorts.count(portId); }); if (srcPortIds.empty()) continue; const auto mixPortIt = findById(mPorts, route.sinkPortId); @@ -317,8 +370,9 @@ std::vector ModuleConfig::getRoutableSrcSinkGroups(b } } } else { + std::set connectedSinkDevicePorts = getConnectedSinkDevicePorts(); for (const auto& route : mRoutes) { - if (mAttachedSinkDevicePorts.count(route.sinkPortId) == 0) continue; + if (connectedSinkDevicePorts.count(route.sinkPortId) == 0) continue; const auto devicePortIt = findById(mPorts, route.sinkPortId); if (devicePortIt == mPorts.end()) continue; auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt); @@ -352,6 +406,8 @@ std::string ModuleConfig::toString() const { result.append(android::internal::ToString(mAttachedSourceDevicePorts)); result.append("\nExternal device ports: "); result.append(android::internal::ToString(mExternalDevicePorts)); + result.append("\nConnected external device ports: "); + result.append(android::internal::ToString(getConnectedExternalDevicePorts())); result.append("\nRoutes: "); result.append(android::internal::ToString(mRoutes)); return result; @@ -384,10 +440,10 @@ static bool isDynamicProfile(const AudioProfile& profile) { } std::vector ModuleConfig::findMixPorts( - bool isInput, bool attachedOnly, bool singlePort, + bool isInput, bool connectedOnly, bool singlePort, const std::function& pred) const { std::vector result; - const auto mixPorts = getMixPorts(isInput, attachedOnly); + const auto mixPorts = getMixPorts(isInput, connectedOnly); for (auto mixPortIt = mixPorts.begin(); mixPortIt != mixPorts.end();) { mixPortIt = std::find_if(mixPortIt, mixPorts.end(), pred); if (mixPortIt == mixPorts.end()) break; @@ -401,7 +457,7 @@ std::vector ModuleConfig::generateAudioMixPortConfigs( const std::vector& ports, bool isInput, bool singleProfile) const { std::vector result; for (const auto& mixPort : ports) { - if (getAttachedDevicesPortsForMixPort(isInput, mixPort).empty()) { + if (getConnectedDevicesPortsForMixPort(isInput, mixPort).empty()) { continue; } for (const auto& profile : mixPort.profiles) { @@ -443,10 +499,48 @@ std::vector ModuleConfig::generateAudioDevicePortConfigs( return result; } +const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceConnected(IModule* module, + const AudioPort& port) { + // Update ports and routes + mStatus = module->getAudioPorts(&mPorts); + if (!mStatus.isOk()) return mStatus; + mStatus = module->getAudioRoutes(&mRoutes); + if (!mStatus.isOk()) return mStatus; + + // Validate port is present in module + if (std::find(mPorts.begin(), mPorts.end(), port) == mPorts.end()) { + mStatus = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + return mStatus; + } + + if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) { + mConnectedExternalSourceDevicePorts.insert(port.id); + } else { + mConnectedExternalSinkDevicePorts.insert(port.id); + } + return mStatus; +} + +const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceDisconnected(IModule* module, + const AudioPort& port) { + // Update ports and routes + mStatus = module->getAudioPorts(&mPorts); + if (!mStatus.isOk()) return mStatus; + mStatus = module->getAudioRoutes(&mRoutes); + if (!mStatus.isOk()) return mStatus; + + if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) { + mConnectedExternalSourceDevicePorts.erase(port.id); + } else { + mConnectedExternalSinkDevicePorts.erase(port.id); + } + return mStatus; +} + bool ModuleConfig::isMmapSupported() const { const std::vector mmapOutMixPorts = - getMmapOutMixPorts(false /*attachedOnly*/, false /*singlePort*/); + getMmapOutMixPorts(false /*connectedOnly*/, false /*singlePort*/); const std::vector mmapInMixPorts = - getMmapInMixPorts(false /*attachedOnly*/, false /*singlePort*/); + getMmapInMixPorts(false /*connectedOnly*/, false /*singlePort*/); return !mmapOutMixPorts.empty() || !mmapInMixPorts.empty(); } diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h index 6a220756f3..bce1de175f 100644 --- a/audio/aidl/vts/ModuleConfig.h +++ b/audio/aidl/vts/ModuleConfig.h @@ -37,6 +37,14 @@ class ModuleConfig { static std::optional generateOffloadInfoIfNeeded( const aidl::android::media::audio::common::AudioPortConfig& portConfig); + + std::vector getAudioPortsForDeviceTypes( + const std::vector& deviceTypes, + const std::string& connection = ""); + static std::vector getAudioPortsForDeviceTypes( + const std::vector& ports, + const std::vector& deviceTypes, + const std::string& connection = ""); static std::vector getBuiltInMicPorts( const std::vector& ports); @@ -45,45 +53,55 @@ class ModuleConfig { std::string getError() const { return mStatus.getMessage(); } std::vector getAttachedDevicePorts() const; + std::vector getConnectedExternalDevicePorts() + const; + std::set getConnectedSinkDevicePorts() const; + std::set getConnectedSourceDevicePorts() const; std::vector getAttachedMicrophonePorts() const { return getBuiltInMicPorts(getAttachedDevicePorts()); } std::vector getExternalDevicePorts() const; std::vector getInputMixPorts( - bool attachedOnly) const; + bool connectedOnly /*Permanently attached and connected external devices*/) const; std::vector getOutputMixPorts( - bool attachedOnly) const; + bool connectedOnly /*Permanently attached and connected external devices*/) const; std::vector getMixPorts( - bool isInput, bool attachedOnly) const { - return isInput ? getInputMixPorts(attachedOnly) : getOutputMixPorts(attachedOnly); + bool isInput, + bool connectedOnly /*Permanently attached and connected external devices*/) const { + return isInput ? getInputMixPorts(connectedOnly) : getOutputMixPorts(connectedOnly); } std::vector getNonBlockingMixPorts( - bool attachedOnly, bool singlePort) const; + bool connectedOnly /*Permanently attached and connected external devices*/, + bool singlePort) const; std::vector getOffloadMixPorts( - bool attachedOnly, bool singlePort) const; + bool connectedOnly /*Permanently attached and connected external devices*/, + bool singlePort) const; std::vector getPrimaryMixPorts( - bool attachedOnly, bool singlePort) const; + bool connectedOnly /*Permanently attached and connected external devices*/, + bool singlePort) const; std::vector getMmapOutMixPorts( - bool attachedOnly, bool singlePort) const; + bool connectedOnly /*Permanently attached and connected external devices*/, + bool singlePort) const; std::vector getMmapInMixPorts( - bool attachedOnly, bool singlePort) const; + bool connectedOnly /*Permanently attached and connected external devices*/, + bool singlePort) const; - std::vector getAttachedDevicesPortsForMixPort( + std::vector getConnectedDevicesPortsForMixPort( bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const { - return isInput ? getAttachedSourceDevicesPortsForMixPort(mixPort) - : getAttachedSinkDevicesPortsForMixPort(mixPort); + return isInput ? getConnectedSourceDevicesPortsForMixPort(mixPort) + : getConnectedSinkDevicesPortsForMixPort(mixPort); } - std::vector getAttachedDevicesPortsForMixPort( + std::vector getConnectedDevicesPortsForMixPort( bool isInput, const aidl::android::media::audio::common::AudioPortConfig& mixPortConfig) const; std::vector - getAttachedSinkDevicesPortsForMixPort( + getConnectedSinkDevicesPortsForMixPort( const aidl::android::media::audio::common::AudioPort& mixPort) const; std::vector - getAttachedSourceDevicesPortsForMixPort( + getConnectedSourceDevicesPortsForMixPort( const aidl::android::media::audio::common::AudioPort& mixPort) const; std::optional - getSourceMixPortForAttachedDevice() const; + getSourceMixPortForConnectedDevice() const; std::optional getNonRoutableSrcSinkPair(bool isInput) const; std::optional getRoutableSrcSinkPair(bool isInput) const; @@ -96,15 +114,15 @@ class ModuleConfig { std::vector getPortConfigsForMixPorts() const { auto inputs = - generateAudioMixPortConfigs(getInputMixPorts(false /*attachedOnly*/), true, false); - auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(false /*attachedOnly*/), false, - false); + generateAudioMixPortConfigs(getInputMixPorts(false /*connectedOnly*/), true, false); + auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(false /*connectedOnly*/), + false, false); inputs.insert(inputs.end(), outputs.begin(), outputs.end()); return inputs; } std::vector getPortConfigsForMixPorts( bool isInput) const { - return generateAudioMixPortConfigs(getMixPorts(isInput, false /*attachedOnly*/), isInput, + return generateAudioMixPortConfigs(getMixPorts(isInput, false /*connectedOnly*/), isInput, false); } std::vector getPortConfigsForMixPorts( @@ -114,7 +132,7 @@ class ModuleConfig { std::optional getSingleConfigForMixPort( bool isInput) const { const auto config = generateAudioMixPortConfigs( - getMixPorts(isInput, false /*attachedOnly*/), isInput, true); + getMixPorts(isInput, false /*connectedOnly*/), isInput, true); if (!config.empty()) { return *config.begin(); } @@ -139,13 +157,20 @@ class ModuleConfig { return *config.begin(); } + const ndk::ScopedAStatus& onExternalDeviceConnected( + aidl::android::hardware::audio::core::IModule* module, + const aidl::android::media::audio::common::AudioPort& port); + const ndk::ScopedAStatus& onExternalDeviceDisconnected( + aidl::android::hardware::audio::core::IModule* module, + const aidl::android::media::audio::common::AudioPort& port); + bool isMmapSupported() const; std::string toString() const; private: std::vector findMixPorts( - bool isInput, bool attachedOnly, bool singlePort, + bool isInput, bool connectedOnly, bool singlePort, const std::function& pred) const; std::vector generateAudioMixPortConfigs( @@ -167,5 +192,7 @@ class ModuleConfig { std::set mAttachedSinkDevicePorts; std::set mAttachedSourceDevicePorts; std::set mExternalDevicePorts; + std::set mConnectedExternalSinkDevicePorts; + std::set mConnectedExternalSourceDevicePorts; std::vector mRoutes; }; diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index 8a8998e10c..025056e132 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -525,13 +525,21 @@ class WithDevicePortConnectedState { EXPECT_IS_OK(mModule->disconnectExternalDevice(getId())) << "when disconnecting device port ID " << getId(); } + if (mModuleConfig != nullptr) { + EXPECT_IS_OK(mModuleConfig->onExternalDeviceDisconnected(mModule, mConnectedPort)) + << "when external device disconnected"; + } } - void SetUp(IModule* module) { + void SetUp(IModule* module, ModuleConfig* moduleConfig) { ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort)) << "when connecting device port ID & data " << mIdAndData.toString(); ASSERT_NE(mIdAndData.id, getId()) << "ID of the connected port must not be the same as the ID of the template port"; + ASSERT_NE(moduleConfig, nullptr); + ASSERT_IS_OK(moduleConfig->onExternalDeviceConnected(module, mConnectedPort)) + << "when external device connected"; mModule = module; + mModuleConfig = moduleConfig; } int32_t getId() const { return mConnectedPort.id; } const AudioPort& get() { return mConnectedPort; } @@ -539,6 +547,7 @@ class WithDevicePortConnectedState { private: const AudioPort mIdAndData; IModule* mModule = nullptr; + ModuleConfig* mModuleConfig = nullptr; AudioPort mConnectedPort; }; @@ -1422,7 +1431,7 @@ TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) { for (const auto& port : ports) { AudioPort portWithData = GenerateUniqueDeviceAddress(port); WithDevicePortConnectedState portConnected(portWithData); - ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); + ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get())); const int32_t connectedPortId = portConnected.getId(); ASSERT_NE(portWithData.id, connectedPortId); ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag()); @@ -1526,7 +1535,7 @@ TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) { TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) { ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig()); - auto srcMixPort = moduleConfig->getSourceMixPortForAttachedDevice(); + auto srcMixPort = moduleConfig->getSourceMixPortForConnectedDevice(); if (!srcMixPort.has_value()) { GTEST_SKIP() << "No mix port for attached output devices"; } @@ -1578,7 +1587,7 @@ TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) { } for (const auto& port : ports) { WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port)); - ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); + ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get())); ASSERT_NO_FATAL_FAILURE( ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get()))); } @@ -1648,7 +1657,7 @@ TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) { GTEST_SKIP() << "No external devices in the module."; } WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(*ports.begin())); - ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); + ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get())); ModuleDebug midwayDebugChange = debug->flags(); midwayDebugChange.simulateDeviceConnections = false; EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange)) @@ -1703,7 +1712,7 @@ TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) { << "when disconnecting already disconnected device port ID " << port.id; AudioPort portWithData = GenerateUniqueDeviceAddress(port); WithDevicePortConnectedState portConnected(portWithData); - ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); + ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get())); EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(portConnected.get(), &ignored)) << "when trying to connect a connected device port " @@ -1725,7 +1734,7 @@ TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) { } for (const auto& port : ports) { WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port)); - ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); + ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get())); const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get()); { WithAudioPortConfig config(portConfig); @@ -1753,7 +1762,7 @@ TEST_P(AudioCoreModule, ExternalDevicePortRoutes) { int32_t connectedPortId; { WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port)); - ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); + ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get())); connectedPortId = portConnected.getId(); std::vector connectedPortRoutes; ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes)) @@ -1794,7 +1803,7 @@ TEST_P(AudioCoreModule, ExternalDeviceMixPortConfigs) { } for (const auto& port : externalDevicePorts) { WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port)); - ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); + ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get())); std::vector routes; ASSERT_IS_OK(module->getAudioRoutesForAudioPort(portConnected.getId(), &routes)); std::vector allPorts; @@ -2459,7 +2468,7 @@ class AudioStream : public AudioCoreModule { void OpenOverMaxCount() { constexpr bool isInput = IOTraits::is_input; - auto ports = moduleConfig->getMixPorts(isInput, true /*attachedOnly*/); + auto ports = moduleConfig->getMixPorts(isInput, true /*connectedOnly*/); bool hasSingleRun = false; for (const auto& port : ports) { const size_t maxStreamCount = port.ext.get().maxOpenStreamCount; @@ -2580,7 +2589,7 @@ class AudioStream : public AudioCoreModule { void HwGainHwVolume() { const auto ports = - moduleConfig->getMixPorts(IOTraits::is_input, true /*attachedOnly*/); + moduleConfig->getMixPorts(IOTraits::is_input, true /*connectedOnly*/); if (ports.empty()) { GTEST_SKIP() << "No mix ports"; } @@ -2619,7 +2628,7 @@ class AudioStream : public AudioCoreModule { // it as an invalid argument, or say that offloaded effects are not supported. void AddRemoveEffectInvalidArguments() { const auto ports = - moduleConfig->getMixPorts(IOTraits::is_input, true /*attachedOnly*/); + moduleConfig->getMixPorts(IOTraits::is_input, true /*connectedOnly*/); if (ports.empty()) { GTEST_SKIP() << "No mix ports"; } @@ -2742,7 +2751,7 @@ TEST_P(AudioStreamIn, ActiveMicrophones) { if (!status.isOk()) { GTEST_SKIP() << "Microphone info is not supported"; } - const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/); + const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/); if (ports.empty()) { GTEST_SKIP() << "No input mix ports for attached devices"; } @@ -2759,7 +2768,7 @@ TEST_P(AudioStreamIn, ActiveMicrophones) { "non-empty list of active microphones"; } if (auto micDevicePorts = ModuleConfig::getBuiltInMicPorts( - moduleConfig->getAttachedSourceDevicesPortsForMixPort(port)); + moduleConfig->getConnectedSourceDevicesPortsForMixPort(port)); !micDevicePorts.empty()) { auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(micDevicePorts[0]); WithAudioPatch patch(true /*isInput*/, stream.getPortConfig(), devicePortConfig); @@ -2791,7 +2800,7 @@ TEST_P(AudioStreamIn, ActiveMicrophones) { TEST_P(AudioStreamIn, MicrophoneDirection) { using MD = IStreamIn::MicrophoneDirection; - const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/); + const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/); if (ports.empty()) { GTEST_SKIP() << "No input mix ports for attached devices"; } @@ -2814,7 +2823,7 @@ TEST_P(AudioStreamIn, MicrophoneDirection) { } TEST_P(AudioStreamIn, MicrophoneFieldDimension) { - const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/); + const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/); if (ports.empty()) { GTEST_SKIP() << "No input mix ports for attached devices"; } @@ -2846,7 +2855,7 @@ TEST_P(AudioStreamIn, MicrophoneFieldDimension) { TEST_P(AudioStreamOut, OpenTwicePrimary) { const auto mixPorts = - moduleConfig->getPrimaryMixPorts(true /*attachedOnly*/, true /*singlePort*/); + moduleConfig->getPrimaryMixPorts(true /*connectedOnly*/, true /*singlePort*/); if (mixPorts.empty()) { GTEST_SKIP() << "No primary mix port which could be routed to attached devices"; } @@ -2857,7 +2866,7 @@ TEST_P(AudioStreamOut, OpenTwicePrimary) { TEST_P(AudioStreamOut, RequireOffloadInfo) { const auto offloadMixPorts = - moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/); + moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, true /*singlePort*/); if (offloadMixPorts.empty()) { GTEST_SKIP() << "No mix port for compressed offload that could be routed to attached devices"; @@ -2879,7 +2888,7 @@ TEST_P(AudioStreamOut, RequireOffloadInfo) { TEST_P(AudioStreamOut, RequireAsyncCallback) { const auto nonBlockingMixPorts = - moduleConfig->getNonBlockingMixPorts(true /*attachedOnly*/, true /*singlePort*/); + moduleConfig->getNonBlockingMixPorts(true /*connectedOnly*/, true /*singlePort*/); if (nonBlockingMixPorts.empty()) { GTEST_SKIP() << "No mix port for non-blocking output that could be routed to attached devices"; @@ -2902,7 +2911,7 @@ TEST_P(AudioStreamOut, RequireAsyncCallback) { } TEST_P(AudioStreamOut, AudioDescriptionMixLevel) { - const auto ports = moduleConfig->getOutputMixPorts(true /*attachedOnly*/); + const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/); if (ports.empty()) { GTEST_SKIP() << "No output mix ports"; } @@ -2930,7 +2939,7 @@ TEST_P(AudioStreamOut, AudioDescriptionMixLevel) { } TEST_P(AudioStreamOut, DualMonoMode) { - const auto ports = moduleConfig->getOutputMixPorts(true /*attachedOnly*/); + const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/); if (ports.empty()) { GTEST_SKIP() << "No output mix ports"; } @@ -2954,7 +2963,7 @@ TEST_P(AudioStreamOut, DualMonoMode) { } TEST_P(AudioStreamOut, LatencyMode) { - const auto ports = moduleConfig->getOutputMixPorts(true /*attachedOnly*/); + const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/); if (ports.empty()) { GTEST_SKIP() << "No output mix ports"; } @@ -2996,7 +3005,7 @@ TEST_P(AudioStreamOut, LatencyMode) { TEST_P(AudioStreamOut, PlaybackRate) { static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION}; const auto offloadMixPorts = - moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/); + moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/); if (offloadMixPorts.empty()) { GTEST_SKIP() << "No mix port for compressed offload that could be routed to attached devices"; @@ -3066,7 +3075,7 @@ TEST_P(AudioStreamOut, PlaybackRate) { TEST_P(AudioStreamOut, SelectPresentation) { static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_UNSUPPORTED_OPERATION}; const auto offloadMixPorts = - moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/); + moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/); if (offloadMixPorts.empty()) { GTEST_SKIP() << "No mix port for compressed offload that could be routed to attached devices"; @@ -3088,7 +3097,7 @@ TEST_P(AudioStreamOut, SelectPresentation) { TEST_P(AudioStreamOut, UpdateOffloadMetadata) { const auto offloadMixPorts = - moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/); + moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/); if (offloadMixPorts.empty()) { GTEST_SKIP() << "No mix port for compressed offload that could be routed to attached devices"; @@ -3301,7 +3310,7 @@ class AudioStreamIo : public AudioCoreModuleBase, void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig, std::shared_ptr commandsAndStates, bool validatePositionIncrease) { - auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort( + auto devicePorts = moduleConfig->getConnectedDevicesPortsForMixPort( IOTraits::is_input, portConfig); ASSERT_FALSE(devicePorts.empty()); auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]); @@ -3341,7 +3350,7 @@ class AudioStreamIo : public AudioCoreModuleBase, typename IOTraits::Worker worker(*stream.getContext(), &driver, stream.getEventReceiver()); - auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort( + auto devicePorts = moduleConfig->getConnectedDevicesPortsForMixPort( IOTraits::is_input, portConfig); ASSERT_FALSE(devicePorts.empty()); auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]); @@ -4006,6 +4015,172 @@ INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch, android::PrintInstanceNameToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch); +static std::vector getRemoteSubmixModuleInstance() { + auto instances = android::getAidlHalInstanceNames(IModule::descriptor); + for (auto instance : instances) { + if (instance.find("r_submix") != std::string::npos) + return (std::vector{instance}); + } + return {}; +} + +template +class WithRemoteSubmix { + public: + WithRemoteSubmix() = default; + WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {} + WithRemoteSubmix(const WithRemoteSubmix&) = delete; + WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete; + std::optional getAudioPort() { + AudioDeviceType deviceType = IOTraits::is_input ? AudioDeviceType::IN_SUBMIX + : AudioDeviceType::OUT_SUBMIX; + auto ports = mModuleConfig->getAudioPortsForDeviceTypes( + std::vector{deviceType}, + AudioDeviceDescription::CONNECTION_VIRTUAL); + if (!ports.empty()) return ports.front(); + return {}; + } + /* Connect remote submix external device */ + void SetUpPortConnection() { + auto port = getAudioPort(); + ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found"; + if (mAddress.has_value()) { + port.value().ext.template get().device.address = + mAddress.value(); + } else { + port = GenerateUniqueDeviceAddress(port.value()); + } + mConnectedPort = std::make_unique(port.value()); + ASSERT_NO_FATAL_FAILURE(mConnectedPort->SetUp(mModule, mModuleConfig)); + } + AudioDeviceAddress getAudioDeviceAddress() { + if (!mAddress.has_value()) { + mAddress = mConnectedPort->get() + .ext.template get() + .device.address; + } + return mAddress.value(); + } + /* Get mix port config for stream and setup patch for it. */ + void SetupPatch() { + const auto portConfig = + mModuleConfig->getSingleConfigForMixPort(IOTraits::is_input); + if (!portConfig.has_value()) { + LOG(DEBUG) << __func__ << ": portConfig not found"; + mSkipTest = true; + return; + } + auto devicePortConfig = mModuleConfig->getSingleConfigForDevicePort(mConnectedPort->get()); + mPatch = std::make_unique(IOTraits::is_input, portConfig.value(), + devicePortConfig); + ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(mModule)); + } + void SetUp(IModule* module, ModuleConfig* moduleConfig) { + mModule = module; + mModuleConfig = moduleConfig; + ASSERT_NO_FATAL_FAILURE(SetUpPortConnection()); + ASSERT_NO_FATAL_FAILURE(SetupPatch()); + if (!mSkipTest) { + // open stream + mStream = std::make_unique>( + mPatch->getPortConfig(IOTraits::is_input)); + ASSERT_NO_FATAL_FAILURE( + mStream->SetUp(mModule, AudioCoreModuleBase::kDefaultBufferSizeFrames)); + } + } + void sendBurstCommands() { + const StreamContext* context = mStream->getContext(); + StreamLogicDefaultDriver driver(makeBurstCommands(true), context->getFrameSizeBytes()); + typename IOTraits::Worker worker(*context, &driver, mStream->getEventReceiver()); + + LOG(DEBUG) << __func__ << ": starting worker..."; + ASSERT_TRUE(worker.start()); + LOG(DEBUG) << __func__ << ": joining worker..."; + worker.join(); + EXPECT_FALSE(worker.hasError()) << worker.getError(); + EXPECT_EQ("", driver.getUnexpectedStateTransition()); + if (IOTraits::is_input) { + EXPECT_TRUE(driver.hasObservablePositionIncrease()); + } + EXPECT_FALSE(driver.hasRetrogradeObservablePosition()); + } + bool skipTest() { return mSkipTest; } + + private: + bool mSkipTest = false; + IModule* mModule = nullptr; + ModuleConfig* mModuleConfig = nullptr; + std::optional mAddress; + std::unique_ptr mConnectedPort; + std::unique_ptr mPatch; + std::unique_ptr> mStream; +}; + +class AudioModuleRemoteSubmix : public AudioCoreModule { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp()); + ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig()); + } + + void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); } +}; + +TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenNoInput) { + // open output stream + WithRemoteSubmix streamOut; + ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get())); + if (streamOut.skipTest()) { + GTEST_SKIP() << "No mix port for attached devices"; + } + // write something to stream + ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands()); +} + +TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputStuck) { + // open output stream + WithRemoteSubmix streamOut; + ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get())); + if (streamOut.skipTest()) { + GTEST_SKIP() << "No mix port for attached devices"; + } + + // open input stream + WithRemoteSubmix streamIn(streamOut.getAudioDeviceAddress()); + ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get())); + if (streamIn.skipTest()) { + GTEST_SKIP() << "No mix port for attached devices"; + } + + // write something to stream + ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands()); +} + +TEST_P(AudioModuleRemoteSubmix, OutputAndInput) { + // open output stream + WithRemoteSubmix streamOut; + ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get())); + if (streamOut.skipTest()) { + GTEST_SKIP() << "No mix port for attached devices"; + } + + // open input stream + WithRemoteSubmix streamIn(streamOut.getAudioDeviceAddress()); + ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get())); + if (streamIn.skipTest()) { + GTEST_SKIP() << "No mix port for attached devices"; + } + + // write something to stream + ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands()); + // read from input stream + ASSERT_NO_FATAL_FAILURE(streamIn.sendBurstCommands()); +} + +INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix, + ::testing::ValuesIn(getRemoteSubmixModuleInstance())); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModuleRemoteSubmix); + class TestExecutionTracer : public ::testing::EmptyTestEventListener { public: void OnTestStart(const ::testing::TestInfo& test_info) override { From 1f8c3b6f3f0d0a255ac20c134c54bce75297308e Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Tue, 12 Sep 2023 12:40:43 -0700 Subject: [PATCH 133/152] audio: Mitigate double receiving of the "exit" command In rare cases, a worker thread from a new stream created via StreamSwitcher can read again from the command FMQ the "exit" command which was sent to the worker of the previous stream. The underlying reason for that has to be investigated. For now, mitigate the issue by salting the cookie of the "exit" command with the worker's TID. Bug: 300130515 Test: atest VtsHalAudioCoreTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:0e7bcae462e05dbdf4ef797365f9414437914bd7) Merged-In: Ie7d2e847e8b39414ffd31afd64e32d4c9a292c03 Change-Id: Ie7d2e847e8b39414ffd31afd64e32d4c9a292c03 --- audio/aidl/default/Stream.cpp | 16 +++++++++++++--- audio/aidl/default/include/core-impl/Stream.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index af89f5fce8..f7298c0286 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #define LOG_TAG "AHAL_Stream" #include #include @@ -94,6 +96,14 @@ void StreamContext::reset() { mDataMQ.reset(); } +pid_t StreamWorkerCommonLogic::getTid() const { +#if defined(__ANDROID__) + return pthread_gettid_np(pthread_self()); +#else + return 0; +#endif +} + std::string StreamWorkerCommonLogic::init() { if (mContext->getCommandMQ() == nullptr) return "Command MQ is null"; if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null"; @@ -164,7 +174,7 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { switch (command.getTag()) { case Tag::halReservedExit: if (const int32_t cookie = command.get(); - cookie == mContext->getInternalCommandCookie()) { + cookie == (mContext->getInternalCommandCookie() ^ getTid())) { mDriver->shutdown(); setClosed(); // This is an internal command, no need to reply. @@ -384,7 +394,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { switch (command.getTag()) { case Tag::halReservedExit: if (const int32_t cookie = command.get(); - cookie == mContext->getInternalCommandCookie()) { + cookie == (mContext->getInternalCommandCookie() ^ getTid())) { mDriver->shutdown(); setClosed(); // This is an internal command, no need to reply. @@ -717,7 +727,7 @@ void StreamCommonImpl::stopWorker() { if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) { LOG(DEBUG) << __func__ << ": asking the worker to exit..."; auto cmd = StreamDescriptor::Command::make( - mContext.getInternalCommandCookie()); + mContext.getInternalCommandCookie() ^ mWorker->getTid()); // Note: never call 'pause' and 'resume' methods of StreamWorker // in the HAL implementation. These methods are to be used by // the client side only. Preventing the worker loop from running diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index a02655f1b7..88fddec233 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -223,6 +223,7 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea : mContext(context), mDriver(driver), mTransientStateDelayMs(context->getTransientStateDelayMs()) {} + pid_t getTid() const; std::string init() override; void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const; void populateReplyWrongState(StreamDescriptor::Reply* reply, From 426b8762667d296fcb4e48b08c4c822875ddbca6 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 15 Sep 2023 18:53:42 -0700 Subject: [PATCH 134/152] audio: Improve testing of point-to-point connections Point-to-point connections (analog, HDMI, SPDIF) do not use a device address. Reflect that in `GenerateUniqueDeviceAddress`. Add an analog headset into the test configuration. Bug: 300648357 Test: atest VtsHalAudioCoreTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:fe47b00628a5a9092455d370709ed63cc6b9305a) Merged-In: Id1d0b1b60df40c2474fe3151067152b8e0a261c3 Change-Id: Id1d0b1b60df40c2474fe3151067152b8e0a261c3 --- audio/aidl/default/Configuration.cpp | 26 ++++++++++- .../vts/VtsHalAudioCoreModuleTargetTest.cpp | 46 +++++++++++-------- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index 9131935f87..b9f1131eca 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -461,6 +461,10 @@ std::unique_ptr getUsbConfiguration() { // - no profiles specified // * "Test In", IN_AFE_PROXY // - no profiles specified +// * "Wired Headset", OUT_HEADSET +// - profile PCM 24-bit; STEREO; 48000 +// * "Wired Headset Mic", IN_HEADSET +// - profile PCM 24-bit; MONO; 48000 // // Mix ports: // * "test output", 1 max open, 1 max active stream @@ -476,7 +480,8 @@ std::unique_ptr getUsbConfiguration() { // // Routes: // "test output", "test fast output", "test compressed offload" -> "Test Out" -// "Test In" -> "test input" +// "test output" -> "Wired Headset" +// "Test In", "Wired Headset Mic" -> "test input" // // Initial port configs: // * "Test Out" device port: PCM 24-bit; STEREO; 48000 @@ -496,6 +501,14 @@ std::unique_ptr getStubConfiguration() { AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false, createDeviceExt(AudioDeviceType::OUT_AFE_PROXY, 0))); + AudioPort headsetOutDevice = + createPort(c.nextPortId++, "Wired Headset", 0, false, + createDeviceExt(AudioDeviceType::OUT_HEADSET, 0, + AudioDeviceDescription::CONNECTION_ANALOG)); + headsetOutDevice.profiles.push_back( + createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})); + c.ports.push_back(headsetOutDevice); + AudioPort testInDevice = createPort(c.nextPortId++, "Test In", 0, true, createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0)); c.ports.push_back(testInDevice); @@ -504,6 +517,14 @@ std::unique_ptr getStubConfiguration() { AudioChannelLayout::LAYOUT_MONO, 48000, 0, true, createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0))); + AudioPort headsetInDevice = + createPort(c.nextPortId++, "Wired Headset Mic", 0, true, + createDeviceExt(AudioDeviceType::IN_HEADSET, 0, + AudioDeviceDescription::CONNECTION_ANALOG)); + headsetInDevice.profiles.push_back( + createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO}, {48000})); + c.ports.push_back(headsetInDevice); + // Mix ports AudioPort testOutMix = @@ -549,7 +570,8 @@ std::unique_ptr getStubConfiguration() { c.routes.push_back( createRoute({testOutMix, testFastOutMix, compressedOffloadOutMix}, testOutDevice)); - c.routes.push_back(createRoute({testInDevice}, testInMIx)); + c.routes.push_back(createRoute({testOutMix}, headsetOutDevice)); + c.routes.push_back(createRoute({testInDevice, headsetInDevice}, testInMIx)); c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end()); diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index 025056e132..b1eecd2141 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -144,28 +144,36 @@ AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& de } AudioPort GenerateUniqueDeviceAddress(const AudioPort& port) { + // Point-to-point connections do not use addresses. + static const std::set kPointToPointConnections = { + AudioDeviceDescription::CONNECTION_ANALOG, AudioDeviceDescription::CONNECTION_HDMI, + AudioDeviceDescription::CONNECTION_HDMI_ARC, + AudioDeviceDescription::CONNECTION_HDMI_EARC, AudioDeviceDescription::CONNECTION_SPDIF}; static int nextId = 0; using Tag = AudioDeviceAddress::Tag; + const auto& deviceDescription = port.ext.get().device.type; AudioDeviceAddress address; - switch (suggestDeviceAddressTag(port.ext.get().device.type)) { - case Tag::id: - address = AudioDeviceAddress::make(std::to_string(++nextId)); - break; - case Tag::mac: - address = AudioDeviceAddress::make( - std::vector{1, 2, 3, 4, 5, static_cast(++nextId & 0xff)}); - break; - case Tag::ipv4: - address = AudioDeviceAddress::make( - std::vector{192, 168, 0, static_cast(++nextId & 0xff)}); - break; - case Tag::ipv6: - address = AudioDeviceAddress::make(std::vector{ - 0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff}); - break; - case Tag::alsa: - address = AudioDeviceAddress::make(std::vector{1, ++nextId}); - break; + if (kPointToPointConnections.count(deviceDescription.connection) == 0) { + switch (suggestDeviceAddressTag(deviceDescription)) { + case Tag::id: + address = AudioDeviceAddress::make(std::to_string(++nextId)); + break; + case Tag::mac: + address = AudioDeviceAddress::make( + std::vector{1, 2, 3, 4, 5, static_cast(++nextId & 0xff)}); + break; + case Tag::ipv4: + address = AudioDeviceAddress::make( + std::vector{192, 168, 0, static_cast(++nextId & 0xff)}); + break; + case Tag::ipv6: + address = AudioDeviceAddress::make(std::vector{ + 0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff}); + break; + case Tag::alsa: + address = AudioDeviceAddress::make(std::vector{1, ++nextId}); + break; + } } AudioPort result = port; result.ext.get().device.address = std::move(address); From d5712db152c60d5290102846fbac7dc6deef2fc7 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 20 Apr 2023 16:10:37 -0700 Subject: [PATCH 135/152] Fix broken and flaky VTS tests 1. nvResetConfig takes some time to reset the modem, causing subsequent tests to fail with a timeout since the modem is unavailabe. Add a timeout after nvResetConfig to allow the modem to be up again before running the next test. 2. Remove invalid errors for start/stopKeepalive. These tests should fail due to invalid arguments, so remove NONE as a possible error. RADIO_NOT_AVAILABLE should also be removed. 3. Fix incorrect startNetworkScan_InvalidInterval tests, since we only check the interval when the scan type is PERIODIC. 4. Save and reset the previous allowed network type bitmap after the test. Combine get/set into one test that tests both behaviors. 5. Fix checks for MCC/MNC in getDataRegistrationState Bug: 277626718 Bug: 240953393 Bug: 264913330 Bug: 259674407 Bug: 242801688 Test: atest VtsHalRadioTargetTest Change-Id: Ic7188f9d8ccfcd90d844b45e3b370a3be3c515d6 Merged-In: Ic7188f9d8ccfcd90d844b45e3b370a3be3c515d6 (cherry picked from commit 757a75879fe58a39a38eea031c19df8c5839537e) --- radio/aidl/vts/radio_data_test.cpp | 6 ++-- radio/aidl/vts/radio_modem_test.cpp | 2 ++ radio/aidl/vts/radio_network_test.cpp | 43 ++++++++++++++------------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/radio/aidl/vts/radio_data_test.cpp b/radio/aidl/vts/radio_data_test.cpp index 5986ff1f25..6ad3237c4d 100644 --- a/radio/aidl/vts/radio_data_test.cpp +++ b/radio/aidl/vts/radio_data_test.cpp @@ -536,8 +536,7 @@ TEST_P(RadioDataTest, startKeepalive) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_data->rspInfo.error, - {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS, - RadioError::REQUEST_NOT_SUPPORTED})); + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); } } @@ -554,8 +553,7 @@ TEST_P(RadioDataTest, stopKeepalive) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp_data->rspInfo.error, - {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, - RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); } /* diff --git a/radio/aidl/vts/radio_modem_test.cpp b/radio/aidl/vts/radio_modem_test.cpp index f88da13af1..e86737888f 100644 --- a/radio/aidl/vts/radio_modem_test.cpp +++ b/radio/aidl/vts/radio_modem_test.cpp @@ -264,6 +264,8 @@ TEST_P(RadioModemTest, nvResetConfig) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_modem->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + // wait until modem reset finishes + sleep(10); LOG(DEBUG) << "nvResetConfig finished"; } diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp index 467e6c7b7b..c4c27b7cbf 100644 --- a/radio/aidl/vts/radio_network_test.cpp +++ b/radio/aidl/vts/radio_network_test.cpp @@ -66,12 +66,20 @@ void RadioNetworkTest::stopNetworkScan() { } /* - * Test IRadioNetwork.setAllowedNetworkTypesBitmap for the response returned. + * Test IRadioNetwork.setAllowedNetworkTypesBitmap and IRadioNetwork.getAllowedNetworkTypesBitmap + * for the response returned. */ -TEST_P(RadioNetworkTest, setAllowedNetworkTypesBitmap) { +TEST_P(RadioNetworkTest, setGetAllowedNetworkTypesBitmap) { serial = GetRandomSerialNumber(); - int32_t allowedNetworkTypesBitmap = static_cast(RadioAccessFamily::LTE); + // save current value + radio_network->getAllowedNetworkTypesBitmap(serial); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + int32_t currentAllowedNetworkTypesBitmap = radioRsp_network->networkTypeBitmapResponse; + + // set new value + int32_t allowedNetworkTypesBitmap = static_cast(RadioAccessFamily::LTE); + serial = GetRandomSerialNumber(); radio_network->setAllowedNetworkTypesBitmap(serial, allowedNetworkTypesBitmap); EXPECT_EQ(std::cv_status::no_timeout, wait()); @@ -83,20 +91,6 @@ TEST_P(RadioNetworkTest, setAllowedNetworkTypesBitmap) { RadioError::MODE_NOT_SUPPORTED, RadioError::INTERNAL_ERR, RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED, RadioError::NO_RESOURCES})); -} - -/* - * Test IRadioNetwork.getAllowedNetworkTypesBitmap for the response returned. - */ -TEST_P(RadioNetworkTest, getAllowedNetworkTypesBitmap) { - serial = GetRandomSerialNumber(); - int32_t allowedNetworkTypesBitmap = static_cast(RadioAccessFamily::LTE); - - radio_network->setAllowedNetworkTypesBitmap(serial, allowedNetworkTypesBitmap); - - EXPECT_EQ(std::cv_status::no_timeout, wait()); - EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); - EXPECT_EQ(serial, radioRsp_network->rspInfo.serial); if (radioRsp_network->rspInfo.error == RadioError::NONE) { sleep(3); // wait for modem @@ -112,7 +106,16 @@ TEST_P(RadioNetworkTest, getAllowedNetworkTypesBitmap) { RadioError::OPERATION_NOT_ALLOWED, RadioError::MODE_NOT_SUPPORTED, RadioError::INVALID_ARGUMENTS, RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED, RadioError::NO_RESOURCES})); + if (radioRsp_network->rspInfo.error == RadioError::NONE) { + // verify we get the value we set + ASSERT_EQ(radioRsp_network->networkTypeBitmapResponse, allowedNetworkTypesBitmap); + } } + + // reset value to previous + serial = GetRandomSerialNumber(); + radio_network->setAllowedNetworkTypesBitmap(serial, currentAllowedNetworkTypesBitmap); + EXPECT_EQ(std::cv_status::no_timeout, wait()); } /* @@ -920,7 +923,7 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) { RadioAccessSpecifier specifier850 = { .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, + NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC, .interval = 4, .specifiers = {specifierP900, specifier850}, .maxSearchTime = 60, @@ -961,7 +964,7 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) { RadioAccessSpecifier specifier850 = { .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, + NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC, .interval = 301, .specifiers = {specifierP900, specifier850}, .maxSearchTime = 60, @@ -1494,7 +1497,7 @@ TEST_P(RadioNetworkTest, getDataRegistrationState) { } // 32 bit system might return invalid mcc and mnc string "\xff\xff..." - if (checkMccMnc && mcc.size() < 4 && mnc.size() < 4) { + if (checkMccMnc && mcc.size() == 3 && (mnc.size() == 2 || mnc.size() == 3)) { int mcc_int = stoi(mcc); int mnc_int = stoi(mnc); EXPECT_TRUE(mcc_int >= 0 && mcc_int <= 999); From 95318f2960dbaa48aae4b51457f4a5abaf425d05 Mon Sep 17 00:00:00 2001 From: Andrew Scull Date: Wed, 10 May 2023 22:08:04 +0000 Subject: [PATCH 136/152] Add security version to config descriptor Introduce a field to the configuration descriptor that provides a standard semantically-defined version number rather than the vendor-defined component version which acts more like a build ID. Test: n/a Bug: 298580435 Bug: 282205139 (cherry picked from https://android-review.googlesource.com/q/commit:0d520e8e1751fde5a3207c6f27be88a8bbc245dc) Merged-In: Idb0c991ab12ae75687236f2489e639e4422a0225 Change-Id: Idb0c991ab12ae75687236f2489e639e4422a0225 --- security/rkp/README.md | 5 +++++ .../security/keymint/IRemotelyProvisionedComponent.aidl | 1 + 2 files changed, 6 insertions(+) diff --git a/security/rkp/README.md b/security/rkp/README.md index 7477f803b3..5a93734c11 100644 --- a/security/rkp/README.md +++ b/security/rkp/README.md @@ -324,6 +324,11 @@ the range \[-70000, -70999\] (these are reserved for future additions here). : : : : boot stage : | Resettable | -70004 | null | If present, key changes on factory| : : : : reset : +| Security version | -70005 | uint | Machine-comparable, monotonically | +: : : : increasing version of the firmware: +: : : : component / boot stage where a : +: : : : greater value indicates a newer : +: : : : version : ``` Please see diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl index 2a4cba1f0e..7fed3636f6 100644 --- a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl +++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl @@ -427,6 +427,7 @@ interface IRemotelyProvisionedComponent { * ? -70002 : tstr, ; Component name * ? -70003 : int / tstr, ; Component version * ? -70004 : null, ; Resettable + * ? -70005 : uint, ; Security version * }, * -4670549 : bstr, ; Authority Hash * ? -4670550 : bstr, ; Authority Descriptor From d6854c227657b87a8a4d1570cbbd768b3ab17353 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 7 Sep 2023 22:50:11 -0700 Subject: [PATCH 137/152] Update VTS tests with EUTRAN instead of GERAN These tests were created for IRadio 1.2 when all devices supported GSM, and REQUEST_NOT_SUPPORTED was valid for devices that didn't support GSM. Change the VTS logic to test EUTRAN instead of GERAN. Remove REQUEST_NOT_SUPPORTED for tests now without GERAN and add REQUEST_NOT_SUPPORTED for all GERAN-specific tests. Test: atest VtsHalRadioTargetTest Bug: 294965245 Change-Id: Ib36b171e33451bf0c9adc0b065a4c74df357e77e Merged-In: Ib36b171e33451bf0c9adc0b065a4c74df357e77e (cherry picked from commit 88aa5f6bcdc328288e7fc63b3dd10a815b8e611b) --- radio/aidl/vts/radio_network_test.cpp | 248 +++++++------------------- 1 file changed, 67 insertions(+), 181 deletions(-) diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp index c4c27b7cbf..54250b07a8 100644 --- a/radio/aidl/vts/radio_network_test.cpp +++ b/radio/aidl/vts/radio_network_test.cpp @@ -24,6 +24,19 @@ #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) +namespace { +const RadioAccessSpecifierBands EUTRAN_BAND_17 = + RadioAccessSpecifierBands::make( + {EutranBands::BAND_17}); +const RadioAccessSpecifierBands EUTRAN_BAND_20 = + RadioAccessSpecifierBands::make( + {EutranBands::BAND_20}); +const RadioAccessSpecifier EUTRAN_SPECIFIER_17 = { + .accessNetwork = AccessNetwork::EUTRAN, .bands = EUTRAN_BAND_17, .channels = {1, 2}}; +const RadioAccessSpecifier EUTRAN_SPECIFIER_20 = { + .accessNetwork = AccessNetwork::EUTRAN, .bands = EUTRAN_BAND_20, .channels = {128, 129}}; +} // namespace + void RadioNetworkTest::SetUp() { std::string serviceName = GetParam(); @@ -291,7 +304,7 @@ TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_invalidHysteresisDb) signalThresholdInfo.hysteresisDb = 10; // hysteresisDb too large given threshold list deltas signalThresholdInfo.thresholds = {-109, -103, -97, -89}; signalThresholdInfo.isEnabled = true; - signalThresholdInfo.ran = AccessNetwork::GERAN; + signalThresholdInfo.ran = AccessNetwork::EUTRAN; ndk::ScopedAStatus res = radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo}); @@ -316,7 +329,7 @@ TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_EmptyThresholds) { signalThresholdInfo.hysteresisMs = 0; signalThresholdInfo.hysteresisDb = 0; signalThresholdInfo.isEnabled = true; - signalThresholdInfo.ran = AccessNetwork::GERAN; + signalThresholdInfo.ran = AccessNetwork::EUTRAN; ndk::ScopedAStatus res = radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo}); @@ -353,7 +366,8 @@ TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Geran) { ALOGI("setSignalStrengthReportingCriteria_Geran, rspInfo.error = %s\n", toString(radioRsp_network->rspInfo.error).c_str()); - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, + {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } /* @@ -652,7 +666,7 @@ TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_multiRansPerRequest) ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); if (radioRsp_network->rspInfo.error == RadioError::NONE) { - supportedSignalThresholdInfos.push_back(signalThresholdInfoGeran); + supportedSignalThresholdInfos.push_back(signalThresholdInfoEutran); } else { // Refer to IRadioNetworkResponse#setSignalStrengthReportingCriteriaResponse ASSERT_TRUE(CheckAnyOfErrors( @@ -686,7 +700,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisDlKbp ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria( serial, 5000, 5000, // hysteresisDlKbps too big for thresholds delta - 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::GERAN); + 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::EUTRAN); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -694,11 +708,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisDlKbp ALOGI("setLinkCapacityReportingCriteria_invalidHysteresisDlKbps, rspInfo.error = %s\n", toString(radioRsp_network->rspInfo.error).c_str()); - // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported - // for GERAN - ASSERT_TRUE( - CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } /* @@ -709,7 +719,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisUlKbp ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria( serial, 5000, 500, 1000, // hysteresisUlKbps too big for thresholds delta - {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::GERAN); + {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::EUTRAN); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -717,11 +727,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisUlKbp ALOGI("setLinkCapacityReportingCriteria_invalidHysteresisUlKbps, rspInfo.error = %s\n", toString(radioRsp_network->rspInfo.error).c_str()); - // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported - // for GERAN - ASSERT_TRUE( - CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } /* @@ -731,7 +737,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_emptyParams) { serial = GetRandomSerialNumber(); ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria( - serial, 0, 0, 0, {}, {}, AccessNetwork::GERAN); + serial, 0, 0, 0, {}, {}, AccessNetwork::EUTRAN); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -739,10 +745,7 @@ TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_emptyParams) { ALOGI("setLinkCapacityReportingCriteria_emptyParams, rspInfo.error = %s\n", toString(radioRsp_network->rspInfo.error).c_str()); - // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported - // for GERAN - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE})); } /* @@ -783,19 +786,9 @@ TEST_P(RadioNetworkTest, setSystemSelectionChannels) { } std::vector originalSpecifiers = radioRsp_network->specifiers; - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - serial = GetRandomSerialNumber(); - res = radio_network->setSystemSelectionChannels(serial, true, {specifierP900, specifier850}); + res = radio_network->setSystemSelectionChannels(serial, true, + {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -808,8 +801,8 @@ TEST_P(RadioNetworkTest, setSystemSelectionChannels) { if (radioRsp_network->rspInfo.error == RadioError::NONE) { serial = GetRandomSerialNumber(); - res = radio_network->setSystemSelectionChannels(serial, false, - {specifierP900, specifier850}); + res = radio_network->setSystemSelectionChannels( + serial, false, {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}); ASSERT_OK(res); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); @@ -832,20 +825,9 @@ TEST_P(RadioNetworkTest, setSystemSelectionChannels) { TEST_P(RadioNetworkTest, startNetworkScan) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands band17 = - RadioAccessSpecifierBands::make( - {EutranBands::BAND_17}); - RadioAccessSpecifierBands band20 = - RadioAccessSpecifierBands::make( - {EutranBands::BAND_20}); - RadioAccessSpecifier specifier17 = { - .accessNetwork = AccessNetwork::EUTRAN, .bands = band17, .channels = {1, 2}}; - RadioAccessSpecifier specifier20 = { - .accessNetwork = AccessNetwork::EUTRAN, .bands = band20, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifier17, specifier20}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 60, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -867,10 +849,9 @@ TEST_P(RadioNetworkTest, startNetworkScan) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED})); } else { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED, RadioError::NONE, - RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, + {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED, + RadioError::INVALID_ARGUMENTS})); } } @@ -900,9 +881,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidArgument) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -912,20 +892,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidArgument) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC, .interval = 4, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 60, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -941,9 +910,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -953,20 +921,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC, .interval = 301, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 60, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -982,9 +939,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -994,20 +950,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 59, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -1023,9 +968,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1035,20 +979,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 3601, .incrementalResults = false, .incrementalResultsPeriodicity = 1}; @@ -1064,9 +997,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1076,20 +1008,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 600, .incrementalResults = true, .incrementalResultsPeriodicity = 0}; @@ -1105,9 +1026,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1117,20 +1037,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) { TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 600, .incrementalResults = true, .incrementalResultsPeriodicity = 11}; @@ -1146,9 +1055,8 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_network->rspInfo.error, - {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS})); } } @@ -1158,20 +1066,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) { TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 360, .incrementalResults = false, .incrementalResultsPeriodicity = 10}; @@ -1188,8 +1085,7 @@ TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) { {RadioError::NONE, RadioError::SIM_ABSENT})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::INVALID_ARGUMENTS, - RadioError::REQUEST_NOT_SUPPORTED})); + {RadioError::NONE, RadioError::INVALID_ARGUMENTS})); } if (radioRsp_network->rspInfo.error == RadioError::NONE) { @@ -1204,20 +1100,9 @@ TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) { TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest2) { serial = GetRandomSerialNumber(); - RadioAccessSpecifierBands bandP900 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_P900}); - RadioAccessSpecifierBands band850 = - RadioAccessSpecifierBands::make( - {GeranBands::BAND_850}); - RadioAccessSpecifier specifierP900 = { - .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}}; - RadioAccessSpecifier specifier850 = { - .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}}; - NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60, - .specifiers = {specifierP900, specifier850}, + .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20}, .maxSearchTime = 360, .incrementalResults = false, .incrementalResultsPeriodicity = 10, @@ -1235,8 +1120,7 @@ TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest2) { {RadioError::NONE, RadioError::SIM_ABSENT})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::INVALID_ARGUMENTS, - RadioError::REQUEST_NOT_SUPPORTED})); + {RadioError::NONE, RadioError::INVALID_ARGUMENTS})); } if (radioRsp_network->rspInfo.error == RadioError::NONE) { @@ -1253,21 +1137,23 @@ TEST_P(RadioNetworkTest, setNetworkSelectionModeManual) { // can't camp on nonexistent MCCMNC, so we expect this to fail. ndk::ScopedAStatus res = - radio_network->setNetworkSelectionModeManual(serial, "123456", AccessNetwork::GERAN); + radio_network->setNetworkSelectionModeManual(serial, "123456", AccessNetwork::EUTRAN); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type); EXPECT_EQ(serial, radioRsp_network->rspInfo.serial); if (cardStatus.cardState == CardStatus::STATE_ABSENT) { - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, - RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, - CHECK_GENERAL_ERROR)); + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_network->rspInfo.error, + {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, RadioError::INVALID_ARGUMENTS, + RadioError::INVALID_STATE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NO_MEMORY, + RadioError::INTERNAL_ERR, RadioError::SYSTEM_ERR, RadioError::CANCELLED})); } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) { - ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, - {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, - RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, - CHECK_GENERAL_ERROR)); + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_network->rspInfo.error, + {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS, + RadioError::INVALID_STATE, RadioError::NO_MEMORY, RadioError::INTERNAL_ERR, + RadioError::SYSTEM_ERR, RadioError::CANCELLED})); } } From b5310066d4301bac068201f8e18b51571afb98e2 Mon Sep 17 00:00:00 2001 From: Aaqib Ismail Date: Thu, 14 Sep 2023 15:46:59 -0700 Subject: [PATCH 138/152] Make 2.0-libproto-native visible to sdv_ivi_cf Bug: 291278377 Test: m Change-Id: I4eba410eef0b410299bde34265b0392114e33d7b --- automotive/vehicle/proto/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/automotive/vehicle/proto/Android.bp b/automotive/vehicle/proto/Android.bp index 683f1281c4..7b98540013 100644 --- a/automotive/vehicle/proto/Android.bp +++ b/automotive/vehicle/proto/Android.bp @@ -27,6 +27,7 @@ cc_library_static { visibility: [ "//hardware/interfaces/automotive/vehicle:__subpackages__", "//device/generic/car/emulator:__subpackages__", + "//device/google/sdv/sdv_ivi_cf:__subpackages__", ], vendor: true, host_supported: true, From 7d483bc65630555b606cb74fc42b188d414b1ea0 Mon Sep 17 00:00:00 2001 From: Aaqib Ismail Date: Thu, 14 Sep 2023 15:48:22 -0700 Subject: [PATCH 139/152] Move VHAL config dirs to protected Bug: 291278377 Test: m Change-Id: I3c67e0b9398e7891bcfecddac5169fb76536cc25 --- .../fake_impl/hardware/include/FakeVehicleHardware.h | 7 +++++-- .../fake_impl/hardware/src/FakeVehicleHardware.cpp | 12 ++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h index c3ebd3b3bc..af1bb1d16d 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h @@ -99,12 +99,17 @@ class FakeVehicleHardware : public IVehicleHardware { const std::shared_ptr mValuePool; const std::shared_ptr mServerSidePropStore; + const std::string mDefaultConfigDir; + const std::string mOverrideConfigDir; + ValueResultType getValue( const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const; VhalResult setValue( const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value); + bool UseOverrideConfigDir(); + private: // Expose private methods to unit test. friend class FakeVehicleHardwareTestHelper; @@ -156,8 +161,6 @@ class FakeVehicleHardware : public IVehicleHardware { aidl::android::hardware::automotive::vehicle::SetValueRequest> mPendingSetValueRequests; - const std::string mDefaultConfigDir; - const std::string mOverrideConfigDir; const bool mForceOverride; bool mAddExtraTestVendorConfigs; diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp index 661438516d..3e67450161 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp @@ -240,6 +240,8 @@ FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir, std::string overrideConfigDir, bool forceOverride) : mValuePool(std::make_unique()), mServerSidePropStore(new VehiclePropertyStore(mValuePool)), + mDefaultConfigDir(defaultConfigDir), + mOverrideConfigDir(overrideConfigDir), mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)), mFakeUserHal(new FakeUserHal(mValuePool)), mRecurrentTimer(new RecurrentTimer()), @@ -247,8 +249,6 @@ FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir, [this](const VehiclePropValue& value) { eventFromVehicleBus(value); })), mPendingGetValueRequests(this), mPendingSetValueRequests(this), - mDefaultConfigDir(defaultConfigDir), - mOverrideConfigDir(overrideConfigDir), mForceOverride(forceOverride) { init(); } @@ -259,11 +259,15 @@ FakeVehicleHardware::~FakeVehicleHardware() { mGeneratorHub.reset(); } +bool FakeVehicleHardware::UseOverrideConfigDir() { + return mForceOverride || + android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false); +} + std::unordered_map FakeVehicleHardware::loadConfigDeclarations() { std::unordered_map configsByPropId; loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId); - if (mForceOverride || - android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false)) { + if (UseOverrideConfigDir()) { loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId); } return configsByPropId; From 514c23cad5133166d615df602be11f17ecac8f29 Mon Sep 17 00:00:00 2001 From: Aaqib Ismail Date: Tue, 19 Sep 2023 17:55:01 -0700 Subject: [PATCH 140/152] Make event callback accessible to child classes Bug: 291278377 Test: m Change-Id: Idb667aa847ba566713068a47b12dc849ffcf96cc --- automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h index e740da7e5c..ddd620ea2e 100644 --- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h @@ -82,6 +82,10 @@ class GRPCVehicleHardware : public IVehicleHardware { bool waitForConnected(std::chrono::milliseconds waitTime); + protected: + std::shared_mutex mCallbackMutex; + std::unique_ptr mOnPropChange; + private: void ValuePollingLoop(); @@ -90,8 +94,6 @@ class GRPCVehicleHardware : public IVehicleHardware { std::unique_ptr mGrpcStub; std::thread mValuePollingThread; - std::shared_mutex mCallbackMutex; - std::unique_ptr mOnPropChange; std::unique_ptr mOnSetErr; std::mutex mShutdownMutex; From d1bc0389e4b86d5f82c7528359247489db3d259a Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Mon, 5 Jun 2023 15:24:38 +0000 Subject: [PATCH 141/152] Support to get EC public key from the UdsCertchain. Bug: 297123463 Bug: 285896470 Test: VtsHalRemotelyProvisionedComponentTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:a18883a58cc9f6b702095bb17bbd0e4e894be49c) Merged-In: I7f829b1346feeab0fd429ad7b9714181b6668b34 Change-Id: I7f829b1346feeab0fd429ad7b9714181b6668b34 --- .../keymint/support/remote_prov_utils.cpp | 75 ++++++++++++++++--- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp index 3cb783cf0a..c9c3e4d4ae 100644 --- a/security/keymint/support/remote_prov_utils.cpp +++ b/security/keymint/support/remote_prov_utils.cpp @@ -115,6 +115,36 @@ ErrMsgOr> getAffineCoordinates(const bytevec& pubKe return std::make_tuple(std::move(pubX), std::move(pubY)); } +ErrMsgOr getRawPublicKey(const EVP_PKEY_Ptr& pubKey) { + if (pubKey.get() == nullptr) { + return "pkey is null."; + } + int keyType = EVP_PKEY_base_id(pubKey.get()); + switch (keyType) { + case EVP_PKEY_EC: { + auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pubKey.get())); + if (ecKey.get() == nullptr) { + return "Failed to get ec key"; + } + return ecKeyGetPublicKey(ecKey.get()); + } + case EVP_PKEY_ED25519: { + bytevec rawPubKey; + size_t rawKeySize = 0; + if (!EVP_PKEY_get_raw_public_key(pubKey.get(), NULL, &rawKeySize)) { + return "Failed to get raw public key."; + } + rawPubKey.resize(rawKeySize); + if (!EVP_PKEY_get_raw_public_key(pubKey.get(), rawPubKey.data(), &rawKeySize)) { + return "Failed to get raw public key."; + } + return rawPubKey; + } + default: + return "Unknown key type."; + } +} + ErrMsgOr> generateEc256KeyPair() { auto ec_key = EC_KEY_Ptr(EC_KEY_new()); if (ec_key.get() == nullptr) { @@ -706,11 +736,10 @@ std::string getX509SubjectName(const X509_Ptr& cert) { // Validates the certificate chain and returns the leaf public key. ErrMsgOr validateCertChain(const cppbor::Array& chain) { - uint8_t rawPubKey[64]; - size_t rawPubKeySize = sizeof(rawPubKey); + bytevec rawPubKey; for (size_t i = 0; i < chain.size(); ++i) { // Root must be self-signed. - size_t signingCertIndex = (i > 1) ? i - 1 : i; + size_t signingCertIndex = (i > 0) ? i - 1 : i; auto& keyCertItem = chain[i]; auto& signingCertItem = chain[signingCertIndex]; if (!keyCertItem || !keyCertItem->asBstr()) { @@ -724,7 +753,7 @@ ErrMsgOr validateCertChain(const cppbor::Array& chain) { if (!keyCert) { return keyCert.message(); } - auto signingCert = parseX509Cert(keyCertItem->asBstr()->value()); + auto signingCert = parseX509Cert(signingCertItem->asBstr()->value()); if (!signingCert) { return signingCert.message(); } @@ -749,17 +778,16 @@ ErrMsgOr validateCertChain(const cppbor::Array& chain) { return "Certificate " + std::to_string(i) + " has wrong issuer. Signer subject is " + signerSubj + " Issuer subject is " + certIssuer; } - - rawPubKeySize = sizeof(rawPubKey); - if (!EVP_PKEY_get_raw_public_key(pubKey.get(), rawPubKey, &rawPubKeySize)) { - return "Failed to get raw public key."; + if (i == chain.size() - 1) { + auto key = getRawPublicKey(pubKey); + if (!key) key.moveMessage(); + rawPubKey = key.moveValue(); } } - - return bytevec(rawPubKey, rawPubKey + rawPubKeySize); + return rawPubKey; } -std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsPub) { +std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsCoseKeyBytes) { for (const auto& [signerName, udsCertChain] : udsCerts) { if (!signerName || !signerName->asTstr()) { return "Signer Name must be a Tstr."; @@ -775,8 +803,31 @@ std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsPub) if (!leafPubKey) { return leafPubKey.message(); } + auto coseKey = CoseKey::parse(udsCoseKeyBytes); + if (!coseKey) return coseKey.moveMessage(); + + auto curve = coseKey->getIntValue(CoseKey::CURVE); + if (!curve) { + return "CoseKey must contain curve."; + } + bytevec udsPub; + if (curve == CoseKeyCurve::P256 || curve == CoseKeyCurve::P384) { + auto pubKey = coseKey->getEcPublicKey(); + if (!pubKey) return pubKey.moveMessage(); + // convert public key to uncompressed form by prepending 0x04 at begin. + pubKey->insert(pubKey->begin(), 0x04); + udsPub = pubKey.moveValue(); + } else if (curve == CoseKeyCurve::ED25519) { + auto& pubkey = coseKey->getMap().get(cppcose::CoseKey::PUBKEY_X); + if (!pubkey || !pubkey->asBstr()) { + return "Invalid public key."; + } + udsPub = pubkey->asBstr()->value(); + } else { + return "Unknown curve."; + } if (*leafPubKey != udsPub) { - return "Leaf public key in UDS certificat chain doesn't match UDS public key."; + return "Leaf public key in UDS certificate chain doesn't match UDS public key."; } } return ""; From 88eb9d0fce7c93ba3b492a8671ac0d6c2945d814 Mon Sep 17 00:00:00 2001 From: terryguan Date: Tue, 22 Aug 2023 17:46:12 -0700 Subject: [PATCH 142/152] Add buffer result for generating vendor configs Add buffers to verify the success of generating and restoring vendor configs. Bug: 281835821 Test: atest android.car.apitest.CarPropertyManagerTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6791803d4ad568c8ba66d20199e84746f412df23) Merged-In: Ic3cb8bf3e606847ff55d719900ad0b764b56aaf4 Change-Id: Ic3cb8bf3e606847ff55d719900ad0b764b56aaf4 --- .../aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp index 46c67a517a..b5b325c5d3 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp @@ -990,9 +990,11 @@ DumpResult FakeVehicleHardware::dump(const std::vector& options) { } else if (EqualsIgnoreCase(option, "--genTestVendorConfigs")) { mAddExtraTestVendorConfigs = true; result.refreshPropertyConfigs = true; + result.buffer = "successfully generated vendor configs"; } else if (EqualsIgnoreCase(option, "--restoreVendorConfigs")) { mAddExtraTestVendorConfigs = false; result.refreshPropertyConfigs = true; + result.buffer = "successfully restored vendor configs"; } else { result.buffer = StringPrintf("Invalid option: %s\n", option.c_str()); } From 7f9c8ae6d9012f3e8d36ffae3cf127139e7367c8 Mon Sep 17 00:00:00 2001 From: Jaideep Sharma Date: Fri, 23 Jun 2023 10:27:39 +0530 Subject: [PATCH 143/152] vts: Don't excercise data path for offloaded/bypass effects Incase of offload effects or effects running in bypass mode data is not handled by effect module, in those cases skip the testcases to excercise data path. Bug: 287590880 Test: run vts -m VtsHalAudioEffectTargetTest Change-Id: I76155f8997b415bc96242f995ccc2e33c8989dc5 Merged-In: I76155f8997b415bc96242f995ccc2e33c8989dc5 --- audio/aidl/vts/TestUtils.h | 7 +++ .../aidl/vts/VtsHalAudioEffectTargetTest.cpp | 44 ++++++++++++++++--- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h index 72ca56f228..10c2fc652d 100644 --- a/audio/aidl/vts/TestUtils.h +++ b/audio/aidl/vts/TestUtils.h @@ -77,3 +77,10 @@ inline ::testing::AssertionResult assertResult(const char* exp_expr, const char* #define EXPECT_STATUS(expected, ret) \ EXPECT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \ expected, ret) + +#define SKIP_TEST_IF_DATA_UNSUPPORTED(flags) \ + ({ \ + if ((flags).hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL || (flags).bypass) { \ + GTEST_SKIP() << "Skip data path for offload"; \ + } \ + }) \ No newline at end of file diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp index 4ad9b2ddae..3011a5ed2c 100644 --- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp @@ -46,6 +46,7 @@ using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; using aidl::android::hardware::audio::effect::Parameter; using aidl::android::hardware::audio::effect::State; +using aidl::android::hardware::audio::effect::Flags; using aidl::android::media::audio::common::AudioDeviceDescription; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioMode; @@ -85,6 +86,14 @@ class AudioEffectTest : public testing::TestWithParam, public E } }; +class AudioEffectDataPathTest : public AudioEffectTest { + public: + void SetUp() override { + AudioEffectTest::SetUp(); + SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags); + } +}; + TEST_P(AudioEffectTest, SetupAndTearDown) { // Intentionally empty test body. } @@ -577,7 +586,8 @@ TEST_P(AudioEffectTest, SetAndGetParameterVolume) { /// Data processing test // Send data to effects and expect it to be consumed by checking statusMQ. -TEST_P(AudioEffectTest, ConsumeDataInProcessingState) { +// Effects exposing bypass flags or operating in offload mode will be skipped. +TEST_P(AudioEffectDataPathTest, ConsumeDataInProcessingState) { ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); Parameter::Common common = EffectHelper::createParamCommon( @@ -610,7 +620,8 @@ TEST_P(AudioEffectTest, ConsumeDataInProcessingState) { } // Send data to effects and expect it to be consumed after effect restart. -TEST_P(AudioEffectTest, ConsumeDataAfterRestart) { +// Effects exposing bypass flags or operating in offload mode will be skipped. +TEST_P(AudioEffectDataPathTest, ConsumeDataAfterRestart) { ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); Parameter::Common common = EffectHelper::createParamCommon( @@ -649,7 +660,8 @@ TEST_P(AudioEffectTest, ConsumeDataAfterRestart) { } // Send data to IDLE effects and expect it to be consumed after effect start. -TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) { +// Effects exposing bypass flags or operating in offload mode will be skipped. +TEST_P(AudioEffectDataPathTest, SendDataAtIdleAndConsumeDataInProcessing) { ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); Parameter::Common common = EffectHelper::createParamCommon( @@ -682,7 +694,8 @@ TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) { } // Send data multiple times. -TEST_P(AudioEffectTest, ProcessDataMultipleTimes) { +// Effects exposing bypass flags or operating in offload mode will be skipped. +TEST_P(AudioEffectDataPathTest, ProcessDataMultipleTimes) { ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); Parameter::Common common = EffectHelper::createParamCommon( @@ -721,7 +734,8 @@ TEST_P(AudioEffectTest, ProcessDataMultipleTimes) { } // Send data to processing state effects, stop, and restart. -TEST_P(AudioEffectTest, ConsumeDataAndRestart) { +// Effects exposing bypass flags or operating in offload mode will be skipped. +TEST_P(AudioEffectDataPathTest, ConsumeDataAndRestart) { ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); Parameter::Common common = EffectHelper::createParamCommon( @@ -762,7 +776,8 @@ TEST_P(AudioEffectTest, ConsumeDataAndRestart) { } // Send data to closed effects and expect it not be consumed. -TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) { +// Effects exposing bypass flags or operating in offload mode will be skipped. +TEST_P(AudioEffectDataPathTest, NotConsumeDataByClosedEffect) { ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); Parameter::Common common = EffectHelper::createParamCommon( @@ -788,7 +803,8 @@ TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) { } // Send data to multiple effects. -TEST_P(AudioEffectTest, ConsumeDataMultipleEffects) { +// Effects exposing bypass flags or operating in offload mode will be skipped. +TEST_P(AudioEffectDataPathTest, ConsumeDataMultipleEffects) { std::shared_ptr effect1, effect2; ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor)); ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor)); @@ -855,6 +871,20 @@ INSTANTIATE_TEST_SUITE_P( }); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectTest); +INSTANTIATE_TEST_SUITE_P( + SingleEffectInstanceTest, AudioEffectDataPathTest, + ::testing::Combine(testing::ValuesIn( + EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))), + [](const testing::TestParamInfo& info) { + auto descriptor = std::get(info.param).second; + std::string name = getPrefix(descriptor); + std::replace_if( + name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); + return name; + }); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectDataPathTest); + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ABinderProcess_setThreadPoolMaxThreadCount(1); From 2d3112f2e3b3b650c98dcb8da81123dffeaa311a Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Mon, 18 Sep 2023 17:37:45 +0000 Subject: [PATCH 144/152] Effect AIDL: Skipping vts test case if its not supported by effect Check audioModeIndication/audioSourceIndication/volume flags and only test if they are supported Bug: 300735428 Test: atest VtsHalAudioEffectTargetTest Change-Id: I539b408fcdb73c25984ec8f39b401475a3ccab69 Merged-In: I539b408fcdb73c25984ec8f39b401475a3ccab69 --- .../aidl/vts/VtsHalAudioEffectTargetTest.cpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp index 3011a5ed2c..aa61593dfa 100644 --- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp @@ -504,6 +504,11 @@ TEST_P(AudioEffectTest, SetAndGetParameterAfterReset) { // Set and get AudioDeviceDescription in Parameter TEST_P(AudioEffectTest, SetAndGetParameterDeviceDescription) { + if (!mDescriptor.common.flags.deviceIndication) { + GTEST_SKIP() << "Skipping test as effect does not support deviceIndication" + << mDescriptor.common.flags.toString(); + } + ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); ASSERT_NO_FATAL_FAILURE(open(mEffect)); @@ -527,6 +532,11 @@ TEST_P(AudioEffectTest, SetAndGetParameterDeviceDescription) { // Set and get AudioMode in Parameter TEST_P(AudioEffectTest, SetAndGetParameterAudioMode) { + if (!mDescriptor.common.flags.audioModeIndication) { + GTEST_SKIP() << "Skipping test as effect does not support audioModeIndication" + << mDescriptor.common.flags.toString(); + } + ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); ASSERT_NO_FATAL_FAILURE(open(mEffect)); @@ -547,6 +557,11 @@ TEST_P(AudioEffectTest, SetAndGetParameterAudioMode) { // Set and get AudioSource in Parameter TEST_P(AudioEffectTest, SetAndGetParameterAudioSource) { + if (!mDescriptor.common.flags.audioSourceIndication) { + GTEST_SKIP() << "Skipping test as effect does not support audioSourceIndication" + << mDescriptor.common.flags.toString(); + } + ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); ASSERT_NO_FATAL_FAILURE(open(mEffect)); @@ -567,6 +582,11 @@ TEST_P(AudioEffectTest, SetAndGetParameterAudioSource) { // Set and get VolumeStereo in Parameter TEST_P(AudioEffectTest, SetAndGetParameterVolume) { + if (mDescriptor.common.flags.volume == Flags::Volume::NONE) { + GTEST_SKIP() << "Skipping test as effect does not support volume" + << mDescriptor.common.flags.toString(); + } + ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); ASSERT_NO_FATAL_FAILURE(open(mEffect)); From 97edf6051d1e3f2aa2eebc55067037039778c856 Mon Sep 17 00:00:00 2001 From: Shunkai Yao Date: Wed, 20 Sep 2023 22:43:41 +0000 Subject: [PATCH 145/152] Effect AIDL: correct some code format Bug: 300735428 Test: atest VtsHalAudioEffectTargetTest Change-Id: I34db56fe6ac203d1ac48202ba1f66dcc36e89262 --- audio/aidl/vts/TestUtils.h | 10 +++++----- audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h index 10c2fc652d..b559669856 100644 --- a/audio/aidl/vts/TestUtils.h +++ b/audio/aidl/vts/TestUtils.h @@ -78,9 +78,9 @@ inline ::testing::AssertionResult assertResult(const char* exp_expr, const char* EXPECT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \ expected, ret) -#define SKIP_TEST_IF_DATA_UNSUPPORTED(flags) \ - ({ \ - if ((flags).hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL || (flags).bypass) { \ - GTEST_SKIP() << "Skip data path for offload"; \ - } \ +#define SKIP_TEST_IF_DATA_UNSUPPORTED(flags) \ + ({ \ + if ((flags).hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL || (flags).bypass) { \ + GTEST_SKIP() << "Skip data path for offload"; \ + } \ }) \ No newline at end of file diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp index aa61593dfa..1876756437 100644 --- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp @@ -42,11 +42,11 @@ using ndk::ScopedAStatus; using aidl::android::hardware::audio::effect::CommandId; using aidl::android::hardware::audio::effect::Descriptor; +using aidl::android::hardware::audio::effect::Flags; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; using aidl::android::hardware::audio::effect::Parameter; using aidl::android::hardware::audio::effect::State; -using aidl::android::hardware::audio::effect::Flags; using aidl::android::media::audio::common::AudioDeviceDescription; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioMode; @@ -87,11 +87,11 @@ class AudioEffectTest : public testing::TestWithParam, public E }; class AudioEffectDataPathTest : public AudioEffectTest { - public: - void SetUp() override { - AudioEffectTest::SetUp(); - SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags); - } + public: + void SetUp() override { + AudioEffectTest::SetUp(); + SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags); + } }; TEST_P(AudioEffectTest, SetupAndTearDown) { From b5cc022359f37474ab36eca630e1cbe133f5b6b0 Mon Sep 17 00:00:00 2001 From: Alisher Alikhodjaev Date: Wed, 20 Sep 2023 15:15:38 -0700 Subject: [PATCH 146/152] Temporary disable one of the transmit checks The transmit without openning a channel passes on some platforms, because a basic channel can be opened by external applications and the state is maintained in the HAL. Bug: 300502872 Test: run vts -m VtsHalSecureElementTargetTest (cherry picked from https://android-review.googlesource.com/q/commit:d0ed43bb7eeb8c2cdc23d23d0d926e083322b7f3) Merged-In: If727c613e8575802b99604f7242e16cf85fc97a0 Change-Id: If727c613e8575802b99604f7242e16cf85fc97a0 --- secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp index 97b4e27629..9678da4a5b 100644 --- a/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp +++ b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp @@ -293,11 +293,13 @@ TEST_P(SecureElementAidl, transmit) { std::vector response; LogicalChannelResponse logical_channel_response; + /* Temporaly disable this check to clarify Basic Channel behavior (b/300502872) // Note: no channel is opened for this test // transmit() will return an empty response with the error // code CHANNEL_NOT_AVAILABLE when the SE cannot be // communicated with. EXPECT_ERR(secure_element_->transmit(kDataApdu, &response)); + */ EXPECT_OK(secure_element_->openLogicalChannel(kSelectableAid, 0x00, &logical_channel_response)); EXPECT_GE(logical_channel_response.selectResponse.size(), 2u); From 08fe547a3aba3e3d357bf9e3898b65bc058935de Mon Sep 17 00:00:00 2001 From: Jaideep Sharma Date: Wed, 20 Sep 2023 11:43:17 +0530 Subject: [PATCH 147/152] audio: Fix Effect worker thread When a effect is closed and reopened from framework, mExit and mStop states are not reset,that causes threadloop to exit and eventually blocks framework as FMQs are never filled from effects HAL. Reset the state of mExit and mStop on every time when thread is created, so open->close->open kind of scenarios can be handled. Bug: 301214647 Test: run vts-hal-audio Change-Id: If54c8fa62827e5f28e620dd841d638028149b1b8 Merged-In: If54c8fa62827e5f28e620dd841d638028149b1b8 --- audio/aidl/default/EffectThread.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp index cd2ba5375b..47ba9f44cb 100644 --- a/audio/aidl/default/EffectThread.cpp +++ b/audio/aidl/default/EffectThread.cpp @@ -48,6 +48,8 @@ RetCode EffectThread::createThread(std::shared_ptr context, const mPriority = priority; { std::lock_guard lg(mThreadMutex); + mStop = true; + mExit = false; mThreadContext = std::move(context); auto statusMQ = mThreadContext->getStatusFmq(); EventFlag* efGroup = nullptr; From 2236b96bf451bdf131643c5e64cf627be0f91143 Mon Sep 17 00:00:00 2001 From: Ye Jiao Date: Mon, 28 Aug 2023 15:22:43 +0800 Subject: [PATCH 148/152] Disable Wi-Fi framework during VTS When VTS case kills supplicant in SetUp, Wi-Fi framework will trigger recovery process and causes races between VTS and Wi-Fi framework. Disable Wi-Fi framework using 'cmd wifi' in SetUp. Bug: 297820612 Test: run vts -m VtsHalWifiHostapdV1_0TargetTest with new case (cherry picked from https://android-review.googlesource.com/q/commit:46538346af90bf93dcafa36206fc2ea5c545dd93) Merged-In: I5ea7f00cfebf79021185f66766454d053c973b31 Change-Id: I5ea7f00cfebf79021185f66766454d053c973b31 --- .../1.0/vts/functional/hostapd_hidl_test.cpp | 18 ++++++++++++++-- .../functional/hostapd_hidl_test_utils.cpp | 21 +++++++++++++++++++ .../vts/functional/hostapd_hidl_test_utils.h | 7 +++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp index bb99ae4d6b..46cba93c72 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp @@ -48,6 +48,13 @@ class HostapdHidlTest virtual void SetUp() override { wifi_instance_name_ = std::get<0>(GetParam()); hostapd_instance_name_ = std::get<1>(GetParam()); + + // Disable Wi-Fi framework to avoid interference + isWifiEnabled_ = isWifiFrameworkEnabled(); + isScanAlwaysEnabled_ = isWifiScanAlwaysAvailable(); + toggleWifiFramework(false); + toggleWifiScanAlwaysAvailable(false); + stopSupplicantIfNeeded(wifi_instance_name_); startHostapdAndWaitForHidlService(wifi_instance_name_, hostapd_instance_name_); @@ -58,14 +65,21 @@ class HostapdHidlTest virtual void TearDown() override { HIDL_INVOKE_VOID_WITHOUT_ARGUMENTS(hostapd_, terminate); stopHostapd(wifi_instance_name_); + + // Restore Wi-Fi framework state + toggleWifiFramework(isWifiEnabled_); + toggleWifiScanAlwaysAvailable(isScanAlwaysEnabled_); } protected: - std::string getPrimaryWlanIfaceName() { + bool isWifiEnabled_ = false; + bool isScanAlwaysEnabled_ = false; + + std::string getPrimaryWlanIfaceName() { std::array buffer; property_get("wifi.interface", buffer.data(), "wlan0"); return buffer.data(); - } + } IHostapd::IfaceParams getIfaceParamsWithAcs() { IHostapd::IfaceParams iface_params; diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp index 56f285d147..4c452fbd86 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp @@ -98,3 +98,24 @@ bool is_1_1(const sp& hostapd) { ::android::hardware::wifi::hostapd::V1_1::IHostapd::castFrom(hostapd); return hostapd_1_1.get() != nullptr; } + +void toggleWifiFramework(bool enable) { + std::string cmd = "/system/bin/cmd wifi set-wifi-enabled "; + cmd += enable ? "enabled" : "disabled"; + testing::checkSubstringInCommandOutput(cmd.c_str(), "X"); +} + +void toggleWifiScanAlwaysAvailable(bool enable) { + std::string cmd = "/system/bin/cmd wifi set-scan-always-available "; + cmd += enable ? "enabled" : "disabled"; + testing::checkSubstringInCommandOutput(cmd.c_str(), "X"); +} + +bool isWifiFrameworkEnabled() { + return testing::checkSubstringInCommandOutput("/system/bin/cmd wifi status", "Wifi is enabled"); +} + +bool isWifiScanAlwaysAvailable() { + return testing::checkSubstringInCommandOutput("/system/bin/cmd wifi status", + "Wifi scanning is always available"); +} diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h index 893de1e334..aa34c9a98f 100644 --- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h +++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h @@ -17,14 +17,17 @@ #ifndef HOSTAPD_HIDL_TEST_UTILS_H #define HOSTAPD_HIDL_TEST_UTILS_H +#include #include #include // Used to stop the android wifi framework before every test. -void stopWifiFramework(const std::string& instance_name); -void startWifiFramework(const std::string& instance_name); void stopSupplicantIfNeeded(const std::string& instance_name); void stopHostapd(const std::string& instance_name); +void toggleWifiFramework(bool enable); +void toggleWifiScanAlwaysAvailable(bool enable); +bool isWifiFrameworkEnabled(); +bool isWifiScanAlwaysAvailable(); // Used to configure the chip, driver and start wpa_hostapd before every // test. void startHostapdAndWaitForHidlService( From f1522dc4bf0ccca98b7fc8eb54a9e9d8b27a37f3 Mon Sep 17 00:00:00 2001 From: Hugo Drumond Jacob Date: Wed, 27 Sep 2023 16:07:37 +0200 Subject: [PATCH 149/152] Adjust path to sdv_ivi_cf Bug: 301578741 Bug: 291278377 Change-Id: I48d24ca611a92f3945a1e0b66fb14a13b2786e7f --- automotive/vehicle/proto/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automotive/vehicle/proto/Android.bp b/automotive/vehicle/proto/Android.bp index 7b98540013..e7dabcf891 100644 --- a/automotive/vehicle/proto/Android.bp +++ b/automotive/vehicle/proto/Android.bp @@ -27,7 +27,7 @@ cc_library_static { visibility: [ "//hardware/interfaces/automotive/vehicle:__subpackages__", "//device/generic/car/emulator:__subpackages__", - "//device/google/sdv/sdv_ivi_cf:__subpackages__", + "//system/software_defined_vehicle/core_services:__subpackages__", ], vendor: true, host_supported: true, From a47d46affbd5e522a426ed5bd5f436fe9904ed2e Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 29 Sep 2023 00:21:37 +0000 Subject: [PATCH 150/152] Setting layer brightness doesn't need nit info for readback tests The nit information was used when we set exact nit values rather than a relative brightness per layer. But we only need nit values for the renderengine interface, which isn't tied to any hwc or panel capabilities. Bug: 301261125 Test: VtsHalGraphicsComposer3_TargetTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:712b3d9880b6aff51ab17d539bfcbdf3785cc6ca) Merged-In: I770dc5620648df2eab608e030c5e76cf190f315d Change-Id: I770dc5620648df2eab608e030c5e76cf190f315d --- graphics/composer/aidl/vts/Android.bp | 1 - .../VtsHalGraphicsComposer3_ReadbackTest.cpp | 143 +----------------- 2 files changed, 5 insertions(+), 139 deletions(-) diff --git a/graphics/composer/aidl/vts/Android.bp b/graphics/composer/aidl/vts/Android.bp index 88b5de41bb..60360fd596 100644 --- a/graphics/composer/aidl/vts/Android.bp +++ b/graphics/composer/aidl/vts/Android.bp @@ -54,7 +54,6 @@ cc_test { "libgui", "libhidlbase", "libprocessgroup", - "libtinyxml2", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@3.0", diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp index 269abd150d..9b849cc133 100644 --- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp +++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp @@ -31,12 +31,6 @@ #include "RenderEngineVts.h" #include "VtsComposerClient.h" -// tinyxml2 does implicit conversions >:( -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#include -#pragma clang diagnostic pop - namespace aidl::android::hardware::graphics::composer3::vts { namespace { @@ -129,63 +123,6 @@ class GraphicsCompositionTestBase : public ::testing::Test { return {false, graphicBuffer}; } - // Gets the per-display XML config - std::unique_ptr getDisplayConfigXml(int64_t display) { - - if (auto document = getDisplayConfigXmlByStableId(getStableDisplayId(display)); - document != nullptr) { - return document; - } - - // Fallback to looking up a per-port config if no config exists for the full ID - if (auto document = getDisplayConfigXmlByPort(getPort(display)); document != nullptr) { - return document; - } - - return nullptr; - } - - // Gets the max display brightness for this display. - // If the display config xml does not exist, then assume that the display is not well-configured - // enough to provide a display brightness, so return nullopt. - std::optional getMaxDisplayBrightnessNits(int64_t display) { - const auto document = getDisplayConfigXml(display); - if (!document) { - // Assume the device doesn't support display brightness - return std::nullopt; - } - - const auto root = document->RootElement(); - if (!root) { - // If there's somehow no root element, then this isn't a valid config - return std::nullopt; - } - - const auto screenBrightnessMap = root->FirstChildElement("screenBrightnessMap"); - if (!screenBrightnessMap) { - // A valid display config must have a screen brightness map - return std::nullopt; - } - - auto point = screenBrightnessMap->FirstChildElement("point"); - float maxNits = -1.f; - while (point != nullptr) { - const auto nits = point->FirstChildElement("nits"); - if (nits) { - maxNits = std::max(maxNits, nits->FloatText(-1.f)); - } - point = point->NextSiblingElement("point"); - } - - if (maxNits < 0.f) { - // If we got here, then there were no point elements containing a nit value, so this - // config isn't valid - return std::nullopt; - } - - return maxNits; - } - void writeLayers(const std::vector>& layers) { for (const auto& layer : layers) { layer->write(*mWriter); @@ -243,53 +180,6 @@ class GraphicsCompositionTestBase : public ::testing::Test { } } } - - uint8_t getPort(int64_t display) { - const auto& [status, identification] = - mComposerClient->getDisplayIdentificationData(display); - EXPECT_TRUE(status.isOk()); - return static_cast(identification.port); - } - - uint64_t getStableDisplayId(int64_t display) { - const auto& [status, identification] = - mComposerClient->getDisplayIdentificationData(display); - EXPECT_TRUE(status.isOk()); - - if (const auto info = ::android::parseDisplayIdentificationData( - static_cast(identification.port), identification.data)) { - return info->id.value; - } - - return ::android::PhysicalDisplayId::fromPort(static_cast(identification.port)) - .value; - } - - std::unique_ptr loadXml(const std::string& path) { - auto document = std::make_unique(); - const tinyxml2::XMLError error = document->LoadFile(path.c_str()); - if (error != tinyxml2::XML_SUCCESS) { - ALOGD("%s: Failed to load config file: %s", __func__, path.c_str()); - return nullptr; - } - - ALOGD("%s: Successfully loaded config file: %s", __func__, path.c_str()); - return document; - } - - std::unique_ptr getDisplayConfigXmlByPort(uint8_t port) { - std::stringstream pathBuilder; - pathBuilder << "/vendor/etc/displayconfig/display_port_" << static_cast(port) - << ".xml"; - return loadXml(pathBuilder.str()); - } - - std::unique_ptr getDisplayConfigXmlByStableId(uint64_t stableId) { - std::stringstream pathBuilder; - pathBuilder << "/vendor/etc/displayconfig/display_id_" << stableId - << ".xml"; - return loadXml(pathBuilder.str()); - } }; class GraphicsCompositionTest : public GraphicsCompositionTestBase, @@ -991,32 +881,6 @@ TEST_P(GraphicsCompositionTest, SetLayerZOrder) { } TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) { - const auto& [status, capabilities] = - mComposerClient->getDisplayCapabilities(getPrimaryDisplayId()); - ASSERT_TRUE(status.isOk()); - - const bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(), - DisplayCapability::BRIGHTNESS) != capabilities.end(); - - if (!brightnessSupport) { - GTEST_SUCCEED() << "Cannot verify dimming behavior without brightness support"; - return; - } - - const std::optional maxBrightnessNitsOptional = - getMaxDisplayBrightnessNits(getPrimaryDisplayId()); - - ASSERT_TRUE(maxBrightnessNitsOptional.has_value()); - - const float maxBrightnessNits = *maxBrightnessNitsOptional; - - // Preconditions to successfully run are knowing the max brightness and successfully applying - // the max brightness - ASSERT_GT(maxBrightnessNits, 0.f); - mWriter->setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.f, maxBrightnessNits); - execute(); - ASSERT_TRUE(mReader.takeErrors().empty()); - for (ColorMode mode : mTestColorModes) { EXPECT_TRUE(mComposerClient ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) @@ -1033,11 +897,14 @@ TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) { const common::Rect redRect = {0, 0, getDisplayWidth(), getDisplayHeight() / 2}; const common::Rect dimmerRedRect = {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}; + + static constexpr float kMaxBrightnessNits = 300.f; + const auto redLayer = std::make_shared(mComposerClient, getPrimaryDisplayId()); redLayer->setColor(RED); redLayer->setDisplayFrame(redRect); - redLayer->setWhitePointNits(maxBrightnessNits); + redLayer->setWhitePointNits(kMaxBrightnessNits); redLayer->setBrightness(1.f); const auto dimmerRedLayer = @@ -1047,7 +914,7 @@ TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) { // Intentionally use a small dimming ratio as some implementations may be more likely to // kick into GPU composition to apply dithering when the dimming ratio is high. static constexpr float kDimmingRatio = 0.9f; - dimmerRedLayer->setWhitePointNits(maxBrightnessNits * kDimmingRatio); + dimmerRedLayer->setWhitePointNits(kMaxBrightnessNits * kDimmingRatio); dimmerRedLayer->setBrightness(kDimmingRatio); const std::vector> layers = {redLayer, dimmerRedLayer}; From ab586ba7d34cd5c8169ed86ad6ba167af7e7366e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 11 Oct 2023 01:39:03 +0000 Subject: [PATCH 151/152] OMX: allow in 8 Bug: 293538526 Change-Id: Ieda8e14d23c367c18537d79c28aeea8a9efbec53 Test: N/A --- compatibility_matrices/compatibility_matrix.8.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml index c04a4999ae..5ea075a377 100644 --- a/compatibility_matrices/compatibility_matrix.8.xml +++ b/compatibility_matrices/compatibility_matrix.8.xml @@ -365,6 +365,18 @@ vendor[0-9]*_software + + android.hardware.media.omx + 1.0 + + IOmx + default + + + IOmxStore + default + + android.hardware.memtrack 1 From 076976eea264db3d2da9df6925f64218fb9d1a11 Mon Sep 17 00:00:00 2001 From: Yu Shan Date: Mon, 9 Oct 2023 14:43:36 -0700 Subject: [PATCH 152/152] Allow CDD required properties to be absent in VTS. Allow CDD required properties not to be supported in VHAL VTS since this is already covered in CTS. We also need to consider special cases where one VHAL instance does not support all required properties. Test: atest VtsHalAutomotiveVehicle_TargetTest Bug: 301577794 Change-Id: I93020e7e024760601bc5a8edf9997cc356a568c6 (Cherry-picked from commit b84f6f3c68fcd7f613146146821130eb354865c1) --- .../VtsHalAutomotiveVehicle_TargetTest.cpp | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp index 8bcad1e0cb..737be847ed 100644 --- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp +++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp @@ -115,6 +115,9 @@ class VtsVehicleCallback final : public ISubscriptionCallback { }; class VtsHalAutomotiveVehicleTargetTest : public testing::TestWithParam { + protected: + bool checkIsSupported(int32_t propertyId); + public: void verifyProperty(VehicleProperty propId, VehiclePropertyAccess access, VehiclePropertyChangeMode changeMode, VehiclePropertyGroup group, @@ -155,7 +158,7 @@ TEST_P(VtsHalAutomotiveVehicleTargetTest, useHidlBackend) { } } -// Test getAllPropConfig() returns at least 4 property configs. +// Test getAllPropConfigs() returns at least 1 property configs. TEST_P(VtsHalAutomotiveVehicleTargetTest, getAllPropConfigs) { ALOGD("VtsHalAutomotiveVehicleTargetTest::getAllPropConfigs"); @@ -163,25 +166,31 @@ TEST_P(VtsHalAutomotiveVehicleTargetTest, getAllPropConfigs) { ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: " << result.error().message(); - ASSERT_GE(result.value().size(), 4u) << StringPrintf( - "Expect to get at least 4 property configs, got %zu", result.value().size()); + ASSERT_GE(result.value().size(), 1u) + << StringPrintf("Expect to get at least 1 property config, got %zu", + result.value().size()); } -// Test getPropConfigs() can query all properties listed in CDD. -TEST_P(VtsHalAutomotiveVehicleTargetTest, getRequiredPropConfigs) { +// Test getPropConfigs() can query properties returned by getAllPropConfigs. +TEST_P(VtsHalAutomotiveVehicleTargetTest, getPropConfigsWithValidProps) { ALOGD("VtsHalAutomotiveVehicleTargetTest::getRequiredPropConfigs"); - // Check the properties listed in CDD - std::vector properties = { - toInt(VehicleProperty::GEAR_SELECTION), toInt(VehicleProperty::NIGHT_MODE), - toInt(VehicleProperty::PARKING_BRAKE_ON), toInt(VehicleProperty::PERF_VEHICLE_SPEED)}; + std::vector properties; + auto result = mVhalClient->getAllPropConfigs(); - auto result = mVhalClient->getPropConfigs(properties); + ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: " + << result.error().message(); + for (const auto& cfgPtr : result.value()) { + properties.push_back(cfgPtr->getPropId()); + } + + result = mVhalClient->getPropConfigs(properties); ASSERT_TRUE(result.ok()) << "Failed to get required property config, error: " << result.error().message(); - ASSERT_EQ(result.value().size(), 4u) - << StringPrintf("Expect to get exactly 4 configs, got %zu", result.value().size()); + ASSERT_EQ(result.value().size(), properties.size()) + << StringPrintf("Expect to get exactly %zu configs, got %zu", + properties.size(), result.value().size()); } // Test getPropConfig() with an invalid propertyId returns an error code. @@ -200,6 +209,9 @@ TEST_P(VtsHalAutomotiveVehicleTargetTest, get) { ALOGD("VtsHalAutomotiveVehicleTargetTest::get"); int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED); + if (!checkIsSupported(propId)) { + GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test"; + } auto result = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId)); ASSERT_TRUE(result.ok()) << StringPrintf("Failed to get value for property: %" PRId32 @@ -285,6 +297,10 @@ TEST_P(VtsHalAutomotiveVehicleTargetTest, setNotWritableProp) { ALOGD("VtsHalAutomotiveVehicleTargetTest::setNotWritableProp"); int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED); + if (!checkIsSupported(propId)) { + GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test"; + } + auto getValueResult = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId)); ASSERT_TRUE(getValueResult.ok()) << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s", propId, @@ -325,6 +341,9 @@ TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribeAndUnsubscribe) { ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribeAndUnsubscribe"); int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED); + if (!checkIsSupported(propId)) { + GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test"; + } auto propConfigsResult = mVhalClient->getPropConfigs({propId}); @@ -414,6 +433,9 @@ TEST_P(VtsHalAutomotiveVehicleTargetTest, testGetValuesTimestampAIDL) { } int32_t propId = toInt(VehicleProperty::PARKING_BRAKE_ON); + if (!checkIsSupported(propId)) { + GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test"; + } auto prop = mVhalClient->createHalPropValue(propId); auto result = mVhalClient->getValueSync(*prop); @@ -865,6 +887,11 @@ TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneCenteringAssistStateConfig) VehicleArea::GLOBAL, VehiclePropertyType::INT32); } +bool VtsHalAutomotiveVehicleTargetTest::checkIsSupported(int32_t propertyId) { + auto result = mVhalClient->getPropConfigs({propertyId}); + return result.ok(); +} + std::vector getDescriptors() { std::vector descriptors; for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {