1 /*
2 * Copyright (C) 2022 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 #include <android-base/strings.h>
18 #include <dirent.h>
19 #include <dlfcn.h>
20 #include <media/cas/CasAPI.h>
21 #include <utils/KeyedVector.h>
22 #include <utils/Mutex.h>
23 #include "SharedLibrary.h"
24
25 using namespace std;
26
27 namespace aidl {
28 namespace android {
29 namespace hardware {
30 namespace cas {
31
32 using namespace ::android;
33
34 template <class T>
35 class FactoryLoader {
36 public:
FactoryLoader(const char * name)37 FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
38
~FactoryLoader()39 virtual ~FactoryLoader() { closeFactory(); }
40
41 bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
42 T** factory = NULL);
43
44 bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
45
46 private:
47 typedef T* (*CreateFactoryFunc)();
48
49 Mutex mMapLock;
50 T* mFactory;
51 const char* mCreateFactoryFuncName;
52 shared_ptr<SharedLibrary> mLibrary;
53 KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
54 KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
55
56 bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
57 shared_ptr<SharedLibrary>* library, T** factory);
58
59 bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
60
61 bool openFactory(const String8& path);
62 void closeFactory();
63 };
64
65 template <class T>
findFactoryForScheme(int32_t CA_system_id,shared_ptr<SharedLibrary> * library,T ** factory)66 bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
67 shared_ptr<SharedLibrary>* library, T** factory) {
68 if (library != NULL) {
69 library->reset();
70 }
71 if (factory != NULL) {
72 *factory = NULL;
73 }
74
75 Mutex::Autolock autoLock(mMapLock);
76
77 // first check cache
78 ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
79 if (index >= 0) {
80 return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
81 library, factory);
82 }
83
84 // no luck, have to search
85 #ifdef __LP64__
86 String8 dirPath("/vendor/lib64/mediacas");
87 #else
88 String8 dirPath("/vendor/lib/mediacas");
89 #endif
90 DIR* pDir = opendir(dirPath.c_str());
91
92 if (pDir == NULL) {
93 ALOGE("Failed to open plugin directory %s", dirPath.c_str());
94 return false;
95 }
96
97 struct dirent* pEntry;
98 while ((pEntry = readdir(pDir))) {
99 String8 pluginPath = dirPath + "/" + pEntry->d_name;
100 if (base::EndsWith(pluginPath.c_str(), ".so")) {
101 if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
102 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
103 closedir(pDir);
104
105 return true;
106 }
107 }
108 }
109
110 closedir(pDir);
111
112 ALOGE("Failed to find plugin");
113 return false;
114 }
115
116 template <class T>
enumeratePlugins(vector<AidlCasPluginDescriptor> * results)117 bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
118 ALOGI("enumeratePlugins");
119
120 results->clear();
121
122 #ifdef __LP64__
123 String8 dirPath("/vendor/lib64/mediacas");
124 #else
125 String8 dirPath("/vendor/lib/mediacas");
126 #endif
127 DIR* pDir = opendir(dirPath.c_str());
128
129 if (pDir == NULL) {
130 ALOGE("Failed to open plugin directory %s", dirPath.c_str());
131 return false;
132 }
133
134 Mutex::Autolock autoLock(mMapLock);
135
136 struct dirent* pEntry;
137 while ((pEntry = readdir(pDir))) {
138 String8 pluginPath = dirPath + "/" + pEntry->d_name;
139 if (base::EndsWith(pluginPath.c_str(), ".so")) {
140 queryPluginsFromPath(pluginPath, results);
141 }
142 }
143 closedir(pDir);
144 return true;
145 }
146
147 template <class T>
loadFactoryForSchemeFromPath(const String8 & path,int32_t CA_system_id,shared_ptr<SharedLibrary> * library,T ** factory)148 bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
149 shared_ptr<SharedLibrary>* library,
150 T** factory) {
151 closeFactory();
152
153 if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
154 closeFactory();
155 return false;
156 }
157
158 if (library != NULL) {
159 *library = mLibrary;
160 }
161 if (factory != NULL) {
162 *factory = mFactory;
163 }
164 return true;
165 }
166
167 template <class T>
queryPluginsFromPath(const String8 & path,vector<AidlCasPluginDescriptor> * results)168 bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
169 vector<AidlCasPluginDescriptor>* results) {
170 closeFactory();
171
172 vector<CasPluginDescriptor> descriptors;
173 if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
174 closeFactory();
175 return false;
176 }
177
178 for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
179 results->push_back(
180 AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
181 }
182 return true;
183 }
184
185 template <class T>
openFactory(const String8 & path)186 bool FactoryLoader<T>::openFactory(const String8& path) {
187 // get strong pointer to open shared library
188 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
189 if (index >= 0) {
190 mLibrary = mLibraryPathToOpenLibraryMap[index];
191 } else {
192 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
193 }
194
195 if (!mLibrary.get()) {
196 mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
197 if (!*mLibrary) {
198 return false;
199 }
200
201 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
202 }
203
204 CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
205 if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
206 return false;
207 }
208 return true;
209 }
210
211 template <class T>
closeFactory()212 void FactoryLoader<T>::closeFactory() {
213 delete mFactory;
214 mFactory = NULL;
215 mLibrary.reset();
216 }
217
218 } // namespace cas
219 } // namespace hardware
220 } // namespace android
221 } // namespace aidl
222