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