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