Merge "Make EffectFactory implementation thread-safe" into main

This commit is contained in:
Treehugger Robot 2023-07-17 22:43:24 +00:00 committed by Gerrit Code Review
commit cdac9b5064
6 changed files with 47 additions and 36 deletions

View file

@ -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<kMapEntryInterfaceIndex>(entry);
RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
"dlNullQueryEffectFunc");
@ -75,6 +75,7 @@ ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type
const std::optional<AudioUuid>& in_impl_uuid,
const std::optional<AudioUuid>& in_proxy_uuid,
std::vector<Descriptor>* _aidl_return) {
std::lock_guard lg(mMutex);
// get the matching list
std::vector<Descriptor::Identity> idList;
std::copy_if(mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(idList),
@ -88,7 +89,8 @@ ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& 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<AudioUuid>& in_type
ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type>& in_type,
std::vector<Processing>* _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<Processing::Type
if (libs.proxyLibrary.has_value()) {
desc.common.id.proxy = libs.proxyLibrary.value().uuid;
}
RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(lib.uuid, &desc),
RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid_l(lib.uuid, &desc),
"getDescriptorFailed");
process.ids.emplace_back(desc);
}
@ -125,9 +128,10 @@ ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type
ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid,
std::shared_ptr<IEffect>* _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<kMapEntryInterfaceIndex>(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<IEffect>& in_handle) {
ndk::ScopedAStatus Factory::destroyEffectImpl_l(const std::shared_ptr<IEffect>& in_handle) {
std::weak_ptr<IEffect> wpHandle(in_handle);
// find the effect entry with key (std::weak_ptr<IEffect>)
if (auto effectIt = mEffectMap.find(wpHandle); effectIt != mEffectMap.end()) {
@ -177,7 +181,7 @@ ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr<IEffect>& 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<IEffect>& 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<void(void*)> 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<AudioUuid> proxyUuid) {
void Factory::createIdentityWithConfig(
const EffectConfig::Library& configLib, const AudioUuid& typeUuid,
const std::optional<AudioUuid> 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<kMapEntryHandleIndex>(entry);
RETURN_VALUE_IF(!dlHandle, void(), "dlNullHandle");
// Get the reference of the DL interfaces in library map tuple.

View file

@ -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};
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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
}

View file

@ -24,6 +24,7 @@
#include <vector>
#include <aidl/android/hardware/audio/effect/BnFactory.h>
#include <android-base/thread_annotations.h>
#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<Descriptor> mDescSet;
std::set<Descriptor::Identity> mIdentitySet;
std::set<Descriptor> mDescSet GUARDED_BY(mMutex);
std::set<Descriptor::Identity> 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<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap;
std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap
GUARDED_BY(mMutex);
typedef std::pair<aidl::android::media::audio::common::AudioUuid, ndk::SpAIBinder> EffectEntry;
std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap;
std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap GUARDED_BY(mMutex);
ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
void cleanupEffectMap();
ndk::ScopedAStatus destroyEffectImpl_l(const std::shared_ptr<IEffect>& 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