diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp index 7b35133cfe..48aa273f74 100644 --- a/audio/aidl/vts/Android.bp +++ b/audio/aidl/vts/Android.bp @@ -41,3 +41,31 @@ cc_test { "vts", ], } + +cc_test { + name: "VtsHalAudioEffectTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "VtsHalAudioEffectTargetTest.cpp", + ], + shared_libs: [ + "libbinder_ndk", + ], + static_libs: [ + "android.media.audio.common.types-V1-ndk", + "android.hardware.audio.effect-V1-ndk", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-Wthread-safety", + ], + test_suites: [ + "general-tests", + "vts", + ], +} diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h new file mode 100644 index 0000000000..e9282867dd --- /dev/null +++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +#include + +class AudioHalBinderServiceUtil { + public: + ndk::SpAIBinder connectToService(const std::string& serviceName) { + mServiceName = serviceName; + mBinder = ndk::SpAIBinder(AServiceManager_getService(serviceName.c_str())); + if (mBinder == nullptr) { + LOG(ERROR) << "Failed to get service " << serviceName; + } else { + LOG(DEBUG) << "succeed to get service " << serviceName; + } + return mBinder; + } + + ndk::SpAIBinder restartService( + std::chrono::milliseconds timeoutMs = std::chrono::milliseconds(3000)) { + mDeathHandler.reset(new AidlDeathRecipient(mBinder)); + if (STATUS_OK != mDeathHandler->linkToDeath()) { + LOG(ERROR) << "linkToDeath failed"; + return nullptr; + } + if (!android::base::SetProperty("sys.audio.restart.hal", "1")) { + LOG(ERROR) << "SetProperty failed"; + return nullptr; + } + if (!mDeathHandler->waitForFired(timeoutMs)) { + LOG(ERROR) << "Timeout wait for death"; + return nullptr; + } + mDeathHandler.reset(); + return connectToService(mServiceName); + } + + private: + class AidlDeathRecipient { + public: + explicit AidlDeathRecipient(const ndk::SpAIBinder& binder) + : binder(binder), recipient(AIBinder_DeathRecipient_new(&binderDiedCallbackAidl)) {} + + binder_status_t linkToDeath() { + return AIBinder_linkToDeath(binder.get(), recipient.get(), this); + } + + bool waitForFired(std::chrono::milliseconds timeoutMs) { + std::unique_lock lock(mutex); + condition.wait_for(lock, timeoutMs, [this]() { return fired; }); + return fired; + } + + private: + const ndk::SpAIBinder binder; + const ndk::ScopedAIBinder_DeathRecipient recipient; + std::mutex mutex; + std::condition_variable condition; + bool fired = false; + + void binderDied() { + std::unique_lock lock(mutex); + fired = true; + condition.notify_one(); + }; + + static void binderDiedCallbackAidl(void* cookie) { + AidlDeathRecipient* self = static_cast(cookie); + self->binderDied(); + } + }; + + std::string mServiceName; + ndk::SpAIBinder mBinder; + std::unique_ptr mDeathHandler; +}; diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp index 290f5f0494..ab70ec4c29 100644 --- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp @@ -15,10 +15,8 @@ */ #include -#include #include #include -#include #include #include #include @@ -35,11 +33,9 @@ #include #include #include -#include -#include -#include #include +#include "AudioHalBinderServiceUtil.h" #include "ModuleConfig.h" using namespace android; @@ -101,38 +97,20 @@ AudioDeviceAddress GenerateUniqueDeviceAddress() { return AudioDeviceAddress::make(std::to_string(++nextId)); } -struct AidlDeathRecipient { - const ndk::SpAIBinder binder; - const ndk::ScopedAIBinder_DeathRecipient recipient; - std::mutex mutex; - std::condition_variable condition; - bool fired = false; - - explicit AidlDeathRecipient(const ndk::SpAIBinder& binder) - : binder(binder), recipient(AIBinder_DeathRecipient_new(&binderDiedCallbackAidl)) {} - - binder_status_t linkToDeath() { - return AIBinder_linkToDeath(binder.get(), recipient.get(), this); - } - - void binderDied() { - std::unique_lock lock(mutex); - fired = true; - condition.notify_one(); - }; - - bool waitForFired(int timeoutMs) { - std::unique_lock lock(mutex); - condition.wait_for(lock, std::chrono::milliseconds(timeoutMs), [this]() { return fired; }); - return fired; - } - - static void binderDiedCallbackAidl(void* cookie) { - AidlDeathRecipient* self = static_cast(cookie); - self->binderDied(); - } +template +struct IsInput { + constexpr operator bool() const; }; +template <> +constexpr IsInput::operator bool() const { + return true; +} +template <> +constexpr IsInput::operator bool() const { + return false; +} + // All 'With*' classes are move-only because they are associated with some // resource or state of a HAL module. class WithDebugFlags { @@ -238,20 +216,15 @@ class AudioCoreModule : public testing::TestWithParam { } void ConnectToService() { - module = IModule::fromBinder( - ndk::SpAIBinder(AServiceManager_getService(GetParam().c_str()))); + module = IModule::fromBinder(binderUtil.connectToService(GetParam())); ASSERT_NE(module, nullptr); } void RestartService() { ASSERT_NE(module, nullptr); moduleConfig.reset(); - deathHandler.reset(new AidlDeathRecipient(module->asBinder())); - ASSERT_EQ(STATUS_OK, deathHandler->linkToDeath()); - ASSERT_TRUE(base::SetProperty("sys.audio.restart.hal", "1")); - EXPECT_TRUE(deathHandler->waitForFired(3000)); - deathHandler.reset(); - ASSERT_NO_FATAL_FAILURE(ConnectToService()); + module = IModule::fromBinder(binderUtil.restartService()); + ASSERT_NE(module, nullptr); } void ApplyEveryConfig(const std::vector& configs) { @@ -322,8 +295,8 @@ class AudioCoreModule : public testing::TestWithParam { } std::shared_ptr module; - std::unique_ptr deathHandler; std::unique_ptr moduleConfig; + AudioHalBinderServiceUtil binderUtil; WithDebugFlags debug; }; diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp new file mode 100644 index 0000000000..f70948c3be --- /dev/null +++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "VtsHalAudioEffect" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "AudioHalBinderServiceUtil.h" + +using namespace android; + +using ndk::ScopedAStatus; + +using aidl::android::hardware::audio::effect::Descriptor; +using aidl::android::hardware::audio::effect::IFactory; +using aidl::android::media::audio::common::AudioUuid; + +namespace ndk { +std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) { + str << status.getDescription(); + return str; +} +} // namespace ndk + +class EffectFactory : public testing::TestWithParam { + public: + void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); } + + void TearDown() override {} + + void ConnectToService() { + serviceName = GetParam(); + factory = IFactory::fromBinder(binderUtil.connectToService(serviceName)); + ASSERT_NE(factory, nullptr); + } + + void RestartService() { + ASSERT_NE(factory, nullptr); + factory = IFactory::fromBinder(binderUtil.restartService()); + ASSERT_NE(factory, nullptr); + } + + std::shared_ptr factory; + std::string serviceName; + AudioHalBinderServiceUtil binderUtil; + // TODO: these UUID can get from config file + // ec7178ec-e5e1-4432-a3f4-4657e6795210 + const AudioUuid nullUuid = {static_cast(0xec7178ec), + 0xe5e1, + 0x4432, + 0xa3f4, + {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}}; + const AudioUuid zeroUuid = { + static_cast(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; +}; + +TEST_P(EffectFactory, SetupAndTearDown) { + // Intentionally empty test body. +} + +TEST_P(EffectFactory, CanBeRestarted) { + ASSERT_NO_FATAL_FAILURE(RestartService()); +} + +TEST_P(EffectFactory, QueriedDescriptorList) { + std::vector descriptors; + ScopedAStatus status = factory->queryEffects(std::nullopt, std::nullopt, &descriptors); + EXPECT_EQ(EX_NONE, status.getExceptionCode()); + EXPECT_NE(static_cast(descriptors.size()), 0); +} + +TEST_P(EffectFactory, DescriptorUUIDNotNull) { + std::vector descriptors; + ScopedAStatus status = factory->queryEffects(std::nullopt, std::nullopt, &descriptors); + EXPECT_EQ(EX_NONE, status.getExceptionCode()); + // TODO: Factory eventually need to return the full list of MUST supported AOSP effects. + for (auto& desc : descriptors) { + EXPECT_NE(desc.type, zeroUuid); + EXPECT_NE(desc.uuid, zeroUuid); + } +} + +TEST_P(EffectFactory, QueriedDescriptorNotExistType) { + std::vector descriptors; + ScopedAStatus status = factory->queryEffects(nullUuid, std::nullopt, &descriptors); + EXPECT_EQ(EX_NONE, status.getExceptionCode()); + EXPECT_EQ(static_cast(descriptors.size()), 0); +} + +TEST_P(EffectFactory, QueriedDescriptorNotExistInstance) { + std::vector descriptors; + ScopedAStatus status = factory->queryEffects(std::nullopt, nullUuid, &descriptors); + EXPECT_EQ(EX_NONE, status.getExceptionCode()); + EXPECT_EQ(static_cast(descriptors.size()), 0); +} + +INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactory, + testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)), + android::PrintInstanceNameToString); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactory); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); + return RUN_ALL_TESTS(); +}