Merge "audiopolicy: Load the engine library dynamically"

gugelfrei
Treehugger Robot 5 years ago committed by Gerrit Code Review
commit 706d9606be

@ -40,7 +40,8 @@ public:
DeviceVector &availableOutputDevices,
DeviceVector &availableInputDevices,
sp<DeviceDescriptor> &defaultOutputDevice)
: mHwModules(hwModules),
: mEngineLibraryNameSuffix(kDefaultEngineLibraryNameSuffix),
mHwModules(hwModules),
mAvailableOutputDevices(availableOutputDevices),
mAvailableInputDevices(availableInputDevices),
mDefaultOutputDevice(defaultOutputDevice),
@ -55,6 +56,14 @@ public:
mSource = file;
}
const std::string& getEngineLibraryNameSuffix() const {
return mEngineLibraryNameSuffix;
}
void setEngineLibraryNameSuffix(const std::string& suffix) {
mEngineLibraryNameSuffix = suffix;
}
void setHwModules(const HwModuleCollection &hwModules)
{
mHwModules = hwModules;
@ -108,6 +117,7 @@ public:
void setDefault(void)
{
mSource = "AudioPolicyConfig::setDefault";
mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic());
sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
@ -167,7 +177,10 @@ public:
}
private:
static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";
std::string mSource;
std::string mEngineLibraryNameSuffix;
HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
DeviceVector &mAvailableOutputDevices;
DeviceVector &mAvailableInputDevices;

@ -17,18 +17,18 @@
#pragma once
#include <EngineConfig.h>
#include <AudioPolicyManagerInterface.h>
#include <EngineInterface.h>
#include <ProductStrategy.h>
#include <VolumeGroup.h>
namespace android {
namespace audio_policy {
class EngineBase : public AudioPolicyManagerInterface
class EngineBase : public EngineInterface
{
public:
///
/// from AudioPolicyManagerInterface
/// from EngineInterface
///
android::status_t initCheck() override;

@ -19,7 +19,6 @@
#include "VolumeGroup.h"
#include <system/audio.h>
#include <AudioPolicyManagerInterface.h>
#include <utils/RefBase.h>
#include <HandleGenerator.h>
#include <string>
@ -27,6 +26,7 @@
#include <map>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <media/AudioAttributes.h>
namespace android {

@ -18,7 +18,6 @@
#include "IVolumeCurves.h"
#include <policy.h>
#include <AudioPolicyManagerInterface.h>
#include <utils/RefBase.h>
#include <HandleGenerator.h>
#include <utils/String8.h>

@ -16,7 +16,6 @@
#pragma once
#include <AudioPolicyManagerInterface.h>
#include <VolumeCurve.h>
#include <system/audio.h>
#include <utils/RefBase.h>

@ -19,6 +19,7 @@
#include "ProductStrategy.h"
#include <media/AudioProductStrategy.h>
#include <media/TypeConverter.h>
#include <utils/String8.h>
#include <cstdint>

@ -32,9 +32,9 @@
#include <istream>
#include <cstdint>
#include <stdarg.h>
#include <string>
namespace android {
using utilities::convertTo;
@ -603,7 +603,39 @@ static status_t deserializeLegacyVolumeCollection(_xmlDoc *doc, const _xmlNode *
return NO_ERROR;
}
namespace {
class XmlErrorHandler {
public:
XmlErrorHandler() {
xmlSetGenericErrorFunc(this, &xmlErrorHandler);
}
XmlErrorHandler(const XmlErrorHandler&) = delete;
XmlErrorHandler(XmlErrorHandler&&) = delete;
XmlErrorHandler& operator=(const XmlErrorHandler&) = delete;
XmlErrorHandler& operator=(XmlErrorHandler&&) = delete;
~XmlErrorHandler() {
xmlSetGenericErrorFunc(NULL, NULL);
if (!mErrorMessage.empty()) {
ALOG(LOG_ERROR, "libxml2", "%s", mErrorMessage.c_str());
}
}
static void xmlErrorHandler(void* ctx, const char* msg, ...) {
char buffer[256];
va_list args;
va_start(args, msg);
vsnprintf(buffer, sizeof(buffer), msg, args);
va_end(args);
static_cast<XmlErrorHandler*>(ctx)->mErrorMessage += buffer;
}
private:
std::string mErrorMessage;
};
} // namespace
ParsingResult parse(const char* path) {
XmlErrorHandler errorHandler;
xmlDocPtr doc;
doc = xmlParseFile(path);
if (doc == NULL) {
@ -641,6 +673,7 @@ ParsingResult parse(const char* path) {
}
android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups) {
XmlErrorHandler errorHandler;
xmlDocPtr doc;
doc = xmlParseFile(path);
if (doc == NULL) {

@ -38,7 +38,7 @@ using VolumeGroupVector = std::vector<volume_group_t>;
/**
* This interface is dedicated to the policy manager that a Policy Engine shall implement.
*/
class AudioPolicyManagerInterface
class EngineInterface
{
public:
/**
@ -295,7 +295,13 @@ public:
virtual void dump(String8 *dst) const = 0;
protected:
virtual ~AudioPolicyManagerInterface() {}
virtual ~EngineInterface() {}
};
__attribute__((visibility("default")))
extern "C" EngineInterface* createEngineInstance();
__attribute__((visibility("default")))
extern "C" void destroyEngineInstance(EngineInterface *engine);
} // namespace android

@ -16,7 +16,7 @@
#pragma once
class AudioPolicyManagerInterface;
class EngineInterface;
class AudioPolicyPluginInterface;
namespace android {
@ -69,7 +69,7 @@ private:
* Compile time error will claim if invalid interface is requested.
*/
template <>
AudioPolicyManagerInterface *EngineInstance::queryInterface() const;
EngineInterface *EngineInstance::queryInterface() const;
template <>
AudioPolicyPluginInterface *EngineInstance::queryInterface() const;

@ -361,7 +361,7 @@ bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, audio
}
template <>
AudioPolicyManagerInterface *Engine::queryInterface()
EngineInterface *Engine::queryInterface()
{
return this;
}

@ -17,7 +17,7 @@
#pragma once
#include "EngineBase.h"
#include <AudioPolicyManagerInterface.h>
#include <EngineInterface.h>
#include <AudioPolicyPluginInterface.h>
#include "Collection.h"

@ -14,7 +14,7 @@
* limitations under the License.
*/
#include <AudioPolicyManagerInterface.h>
#include <EngineInterface.h>
#include <AudioPolicyPluginInterface.h>
#include "AudioPolicyEngineInstance.h"
#include "Engine.h"
@ -45,9 +45,9 @@ Engine *EngineInstance::getEngine() const
}
template <>
AudioPolicyManagerInterface *EngineInstance::queryInterface() const
EngineInterface *EngineInstance::queryInterface() const
{
return getEngine()->queryInterface<AudioPolicyManagerInterface>();
return getEngine()->queryInterface<EngineInterface>();
}
template <>
@ -57,5 +57,16 @@ AudioPolicyPluginInterface *EngineInstance::queryInterface() const
}
} // namespace audio_policy
extern "C" EngineInterface* createEngineInstance()
{
return audio_policy::EngineInstance::getInstance()->queryInterface<EngineInterface>();
}
extern "C" void destroyEngineInstance(EngineInterface*)
{
// The engine is a singleton.
}
} // namespace android

@ -1,16 +1,15 @@
cc_library_shared {
name: "libaudiopolicyenginedefault",
export_include_dirs: ["include"],
srcs: [
"src/Engine.cpp",
"src/EngineInstance.cpp",
],
cflags: [
"-fvisibility=hidden",
"-Wall",
"-Werror",
"-Wextra",
],
local_include_dirs: ["include"],
header_libs: [
"libbase_headers",
"libaudiopolicycommon",

@ -1,76 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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
class AudioPolicyManagerInterface;
namespace android
{
namespace audio_policy
{
class Engine;
class EngineInstance
{
protected:
EngineInstance();
public:
virtual ~EngineInstance();
/**
* Get Audio Policy Engine instance.
*
* @return pointer to Route Manager Instance object.
*/
static EngineInstance *getInstance();
/**
* Interface query.
* The first client of an interface of the policy engine will start the singleton.
*
* @tparam RequestedInterface: interface that the client is wishing to retrieve.
*
* @return interface handle.
*/
template <class RequestedInterface>
RequestedInterface *queryInterface() const;
protected:
/**
* Get Audio Policy Engine instance.
*
* @return Audio Policy Engine singleton.
*/
Engine *getEngine() const;
private:
/* Copy facilities are put private to disable copy. */
EngineInstance(const EngineInstance &object);
EngineInstance &operator=(const EngineInstance &object);
};
/**
* Limit template instantation to supported type interfaces.
* Compile time error will claim if invalid interface is requested.
*/
template <>
AudioPolicyManagerInterface *EngineInstance::queryInterface() const;
} // namespace audio_policy
} // namespace android

@ -762,12 +762,6 @@ sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_
AUDIO_FORMAT_DEFAULT);
}
template <>
AudioPolicyManagerInterface *Engine::queryInterface()
{
return this;
}
} // namespace audio_policy
} // namespace android

@ -17,7 +17,7 @@
#pragma once
#include "EngineBase.h"
#include "AudioPolicyManagerInterface.h"
#include "EngineInterface.h"
#include <AudioGain.h>
#include <policy.h>
@ -48,12 +48,9 @@ public:
Engine();
virtual ~Engine() = default;
template <class RequestedInterface>
RequestedInterface *queryInterface();
private:
///
/// from EngineBase, so from AudioPolicyManagerInterface
/// from EngineBase, so from EngineInterface
///
status_t setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config) override;

@ -14,41 +14,21 @@
* limitations under the License.
*/
#include <AudioPolicyManagerInterface.h>
#include "AudioPolicyEngineInstance.h"
#include <EngineInterface.h>
#include "Engine.h"
namespace android
{
namespace audio_policy
{
EngineInstance::EngineInstance()
{
}
EngineInstance *EngineInstance::getInstance()
{
static EngineInstance instance;
return &instance;
}
EngineInstance::~EngineInstance()
{
}
namespace android {
namespace audio_policy {
Engine *EngineInstance::getEngine() const
extern "C" EngineInterface* createEngineInstance()
{
static Engine engine;
return &engine;
return new (std::nothrow) Engine();
}
template <>
AudioPolicyManagerInterface *EngineInstance::queryInterface() const
extern "C" void destroyEngineInstance(EngineInterface *engine)
{
return getEngine()->queryInterface<AudioPolicyManagerInterface>();
delete static_cast<Engine*>(engine);
}
} // namespace audio_policy
} // namespace android

@ -0,0 +1,43 @@
cc_library_shared {
name: "libaudiopolicymanagerdefault",
srcs: [
"AudioPolicyManager.cpp",
"EngineLibrary.cpp",
],
export_include_dirs: ["."],
shared_libs: [
"libcutils",
"libdl",
"libutils",
"liblog",
"libaudiopolicy",
"libsoundtrigger",
"libmedia_helper",
"libmediametrics",
"libbinder",
"libhidlbase",
"libxml2",
// The default audio policy engine is always present in the system image.
// libaudiopolicyengineconfigurable can be built in addition by specifying
// a dependency on it in the device makefile. There will be no build time
// conflict with libaudiopolicyenginedefault.
"libaudiopolicyenginedefault",
],
header_libs: [
"libaudiopolicycommon",
"libaudiopolicyengine_interface_headers",
"libaudiopolicymanager_interface_headers",
],
static_libs: ["libaudiopolicycomponents"],
cflags: [
"-Wall",
"-Werror",
],
}

@ -1,48 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= AudioPolicyManager.cpp
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog \
libaudiopolicy \
libsoundtrigger
ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
LOCAL_SHARED_LIBRARIES += libaudiopolicyengineconfigurable
else
LOCAL_SHARED_LIBRARIES += libaudiopolicyenginedefault
endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
LOCAL_C_INCLUDES += \
$(call include-path-for, audio-utils)
LOCAL_HEADER_LIBRARIES := \
libaudiopolicycommon \
libaudiopolicyengine_interface_headers \
libaudiopolicymanager_interface_headers
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents
LOCAL_SHARED_LIBRARIES += libmedia_helper
LOCAL_SHARED_LIBRARIES += libmediametrics
LOCAL_SHARED_LIBRARIES += libbinder libhidlbase libxml2
LOCAL_CFLAGS += -Wall -Werror
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
LOCAL_MODULE:= libaudiopolicymanagerdefault
include $(BUILD_SHARED_LIBRARY)

@ -42,8 +42,6 @@
#include <set>
#include <unordered_set>
#include <vector>
#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyEngineInstance.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <media/AudioParameter.h>
@ -4304,17 +4302,18 @@ void AudioPolicyManager::loadConfig() {
}
status_t AudioPolicyManager::initialize() {
// Once policy config has been parsed, retrieve an instance of the engine and initialize it.
audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
if (!engineInstance) {
ALOGE("%s: Could not get an instance of policy engine", __FUNCTION__);
return NO_INIT;
}
// Retrieve the Policy Manager Interface
mEngine = engineInstance->queryInterface<AudioPolicyManagerInterface>();
if (mEngine == NULL) {
ALOGE("%s: Failed to get Policy Engine Interface", __FUNCTION__);
return NO_INIT;
{
auto engLib = EngineLibrary::load(
"libaudiopolicyengine" + getConfig().getEngineLibraryNameSuffix() + ".so");
if (!engLib) {
ALOGE("%s: Failed to load the engine library", __FUNCTION__);
return NO_INIT;
}
mEngine = engLib->createEngine();
if (mEngine == nullptr) {
ALOGE("%s: Failed to instantiate the APM engine", __FUNCTION__);
return NO_INIT;
}
}
mEngine->setObserver(this);
status_t status = mEngine->initCheck();

@ -34,7 +34,6 @@
#include <media/PatchBuilder.h>
#include "AudioPolicyInterface.h"
#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyManagerObserver.h>
#include <AudioGain.h>
#include <AudioPolicyConfig.h>
@ -49,6 +48,7 @@
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
#include "EngineLibrary.h"
#include "TypeConverter.h"
namespace android {
@ -752,7 +752,7 @@ protected:
uint32_t nextAudioPortGeneration();
// Audio Policy Engine Interface.
AudioPolicyManagerInterface *mEngine;
EngineInstance mEngine;
// Surround formats that are enabled manually. Taken into account when
// "encoded surround" is forced into "manual" mode.

@ -0,0 +1,78 @@
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "APM_EngineLoader"
#include <dlfcn.h>
#include <utils/Log.h>
#include "EngineLibrary.h"
namespace android {
// static
std::shared_ptr<EngineLibrary> EngineLibrary::load(std::string libraryPath)
{
std::shared_ptr<EngineLibrary> engLib(new EngineLibrary());
return engLib->init(std::move(libraryPath)) ? engLib : nullptr;
}
EngineLibrary::~EngineLibrary()
{
close();
}
bool EngineLibrary::init(std::string libraryPath)
{
mLibraryHandle = dlopen(libraryPath.c_str(), 0);
if (mLibraryHandle == nullptr) {
ALOGE("Could not dlopen %s: %s", libraryPath.c_str(), dlerror());
return false;
}
mCreateEngineInstance = (EngineInterface* (*)())dlsym(mLibraryHandle, "createEngineInstance");
mDestroyEngineInstance = (void (*)(EngineInterface*))dlsym(
mLibraryHandle, "destroyEngineInstance");
if (mCreateEngineInstance == nullptr || mDestroyEngineInstance == nullptr) {
ALOGE("Could not find engine interface functions in %s", libraryPath.c_str());
close();
return false;
}
ALOGD("Loaded engine from %s", libraryPath.c_str());
return true;
}
EngineInstance EngineLibrary::createEngine()
{
if (mCreateEngineInstance == nullptr || mDestroyEngineInstance == nullptr) {
return EngineInstance();
}
return EngineInstance(mCreateEngineInstance(),
[lib = shared_from_this(), destroy = mDestroyEngineInstance] (EngineInterface* e) {
destroy(e);
});
}
void EngineLibrary::close()
{
if (mLibraryHandle != nullptr) {
dlclose(mLibraryHandle);
}
mLibraryHandle = nullptr;
mCreateEngineInstance = nullptr;
mDestroyEngineInstance = nullptr;
}
} // namespace android

@ -0,0 +1,51 @@
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <EngineInterface.h>
namespace android {
using EngineInstance = std::unique_ptr<EngineInterface, std::function<void (EngineInterface*)>>;
class EngineLibrary : public std::enable_shared_from_this<EngineLibrary> {
public:
static std::shared_ptr<EngineLibrary> load(std::string libraryPath);
~EngineLibrary();
EngineLibrary(const EngineLibrary&) = delete;
EngineLibrary(EngineLibrary&&) = delete;
EngineLibrary& operator=(const EngineLibrary&) = delete;
EngineLibrary& operator=(EngineLibrary&&) = delete;
EngineInstance createEngine();
private:
EngineLibrary() = default;
bool init(std::string libraryPath);
void close();
void *mLibraryHandle = nullptr;
EngineInterface* (*mCreateEngineInstance)() = nullptr;
void (*mDestroyEngineInstance)(EngineInterface*) = nullptr;
};
} // namespace android

@ -30,7 +30,16 @@
using namespace android;
TEST(AudioPolicyManagerTestInit, Failure) {
TEST(AudioPolicyManagerTestInit, EngineFailure) {
AudioPolicyTestClient client;
AudioPolicyTestManager manager(&client);
manager.getConfig().setDefault();
manager.getConfig().setEngineLibraryNameSuffix("non-existent");
ASSERT_EQ(NO_INIT, manager.initialize());
ASSERT_EQ(NO_INIT, manager.initCheck());
}
TEST(AudioPolicyManagerTestInit, ClientFailure) {
AudioPolicyTestClient client;
AudioPolicyTestManager manager(&client);
manager.getConfig().setDefault();

Loading…
Cancel
Save