1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "APM_EngineLoader"
18 
19 #include <dlfcn.h>
20 #include <utils/Log.h>
21 
22 #include "EngineLibrary.h"
23 
24 namespace android {
25 
loadApmEngineLibraryAndCreateEngine(const std::string & librarySuffix,const std::string & configXmlFilePath)26 EngineInstance loadApmEngineLibraryAndCreateEngine(const std::string& librarySuffix,
27         const std::string& configXmlFilePath)
28 {
29     auto engLib = EngineLibrary::load(librarySuffix);
30     if (!engLib) {
31         ALOGE("%s: Failed to load the engine library, suffix \"%s\"",
32                 __func__, librarySuffix.c_str());
33         return nullptr;
34     }
35     auto engine = engLib->createEngineUsingXmlConfig(configXmlFilePath);
36     if (engine == nullptr) {
37         ALOGE("%s: Failed to instantiate the APM engine", __func__);
38         return nullptr;
39     }
40     return engine;
41 }
42 
loadApmEngineLibraryAndCreateEngine(const std::string & librarySuffix,const media::audio::common::AudioHalEngineConfig & config)43 EngineInstance loadApmEngineLibraryAndCreateEngine(const std::string& librarySuffix,
44         const media::audio::common::AudioHalEngineConfig& config)
45 {
46     auto engLib = EngineLibrary::load(librarySuffix);
47     if (!engLib) {
48         ALOGE("%s: Failed to load the engine library, suffix \"%s\"",
49                 __func__, librarySuffix.c_str());
50         return nullptr;
51     }
52     auto engine = engLib->createEngineUsingHalConfig(config);
53     if (engine == nullptr) {
54         ALOGE("%s: Failed to instantiate the APM engine", __func__);
55         return nullptr;
56     }
57     return engine;
58 }
59 
60 // static
load(const std::string & librarySuffix)61 std::shared_ptr<EngineLibrary> EngineLibrary::load(const std::string& librarySuffix)
62 {
63     std::string libraryPath = "libaudiopolicyengine" + librarySuffix + ".so";
64     std::shared_ptr<EngineLibrary> engLib(new EngineLibrary());
65     return engLib->init(std::move(libraryPath)) ? engLib : nullptr;
66 }
67 
~EngineLibrary()68 EngineLibrary::~EngineLibrary()
69 {
70     close();
71 }
72 
createEngineUsingXmlConfig(const std::string & xmlFilePath)73 EngineInstance EngineLibrary::createEngineUsingXmlConfig(const std::string& xmlFilePath)
74 {
75     auto instance = createEngine();
76     if (instance != nullptr) {
77         if (status_t status = instance->loadFromXmlConfigWithFallback(xmlFilePath);
78                 status == OK) {
79             return instance;
80         } else {
81             ALOGE("%s: loading of the engine config with XML configuration file \"%s\" failed: %d",
82                     __func__, xmlFilePath.empty() ? "default" : xmlFilePath.c_str(), status);
83         }
84     }
85     return nullptr;
86 }
87 
createEngineUsingHalConfig(const media::audio::common::AudioHalEngineConfig & config)88 EngineInstance EngineLibrary::createEngineUsingHalConfig(
89         const media::audio::common::AudioHalEngineConfig& config)
90 {
91     auto instance = createEngine();
92     if (instance != nullptr) {
93         if (status_t status = instance->loadFromHalConfigWithFallback(config); status == OK) {
94             return instance;
95         } else {
96             ALOGE("%s: loading of the engine config with HAL configuration \"%s\" failed: %d",
97                     __func__, config.toString().c_str(), status);
98         }
99     }
100     return nullptr;
101 }
102 
init(std::string libraryPath)103 bool EngineLibrary::init(std::string libraryPath)
104 {
105     mLibraryHandle = dlopen(libraryPath.c_str(), 0);
106     if (mLibraryHandle == nullptr) {
107         ALOGE("Could not dlopen %s: %s", libraryPath.c_str(), dlerror());
108         return false;
109     }
110     mCreateEngineInstance = (EngineInterface* (*)())dlsym(mLibraryHandle, "createEngineInstance");
111     mDestroyEngineInstance = (void (*)(EngineInterface*))dlsym(
112             mLibraryHandle, "destroyEngineInstance");
113     if (mCreateEngineInstance == nullptr || mDestroyEngineInstance == nullptr) {
114         ALOGE("Could not find engine interface functions in %s", libraryPath.c_str());
115         close();
116         return false;
117     }
118     ALOGD("Loaded engine from %s", libraryPath.c_str());
119     return true;
120 }
121 
createEngine()122 EngineInstance EngineLibrary::createEngine()
123 {
124     if (mCreateEngineInstance == nullptr || mDestroyEngineInstance == nullptr) {
125         return EngineInstance();
126     }
127     return EngineInstance(mCreateEngineInstance(),
128             [lib = shared_from_this(), destroy = mDestroyEngineInstance] (EngineInterface* e) {
129                 destroy(e);
130             });
131 }
132 
close()133 void EngineLibrary::close()
134 {
135     if (mLibraryHandle != nullptr) {
136         dlclose(mLibraryHandle);
137     }
138     mLibraryHandle = nullptr;
139     mCreateEngineInstance = nullptr;
140     mDestroyEngineInstance = nullptr;
141 }
142 
143 }  // namespace android
144