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 #ifdef __LP64__
96     String8 dirPath("/vendor/lib64/mediacas");
97 #else
98     String8 dirPath("/vendor/lib/mediacas");
99 #endif
100 
101     DIR* pDir = opendir(dirPath.string());
102 
103     if (pDir == NULL) {
104         ALOGE("Failed to open plugin directory %s", dirPath.string());
105         return false;
106     }
107 
108     struct dirent* pEntry;
109     while ((pEntry = readdir(pDir))) {
110         String8 pluginPath = dirPath + "/" + pEntry->d_name;
111         if (pluginPath.getPathExtension() == ".so") {
112             if (loadFactoryForSchemeFromPath(
113                     pluginPath, CA_system_id, library, factory)) {
114                 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
115                 closedir(pDir);
116 
117                 return true;
118             }
119         }
120     }
121 
122     closedir(pDir);
123 
124     ALOGE("Failed to find plugin");
125     return false;
126 }
127 
128 template <class T>
enumeratePlugins(vector<HidlCasPluginDescriptor> * results)129 bool FactoryLoader<T>::enumeratePlugins(
130         vector<HidlCasPluginDescriptor>* results) {
131     ALOGI("enumeratePlugins");
132 
133     results->clear();
134 
135 #ifdef __LP64__
136     String8 dirPath("/vendor/lib64/mediacas");
137 #else
138     String8 dirPath("/vendor/lib/mediacas");
139 #endif
140 
141     DIR* pDir = opendir(dirPath.string());
142 
143     if (pDir == NULL) {
144         ALOGE("Failed to open plugin directory %s", dirPath.string());
145         return false;
146     }
147 
148     Mutex::Autolock autoLock(mMapLock);
149 
150     struct dirent* pEntry;
151     while ((pEntry = readdir(pDir))) {
152         String8 pluginPath = dirPath + "/" + pEntry->d_name;
153         if (pluginPath.getPathExtension() == ".so") {
154             queryPluginsFromPath(pluginPath, results);
155         }
156     }
157     return true;
158 }
159 
160 template <class T>
loadFactoryForSchemeFromPath(const String8 & path,int32_t CA_system_id,sp<SharedLibrary> * library,T ** factory)161 bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
162         const String8 &path, int32_t CA_system_id,
163         sp<SharedLibrary> *library, T** factory) {
164     closeFactory();
165 
166     if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
167         closeFactory();
168         return false;
169     }
170 
171     if (library != NULL) {
172         *library = mLibrary;
173     }
174     if (factory != NULL) {
175         *factory = mFactory;
176     }
177     return true;
178 }
179 
180 template <class T>
queryPluginsFromPath(const String8 & path,vector<HidlCasPluginDescriptor> * results)181 bool FactoryLoader<T>::queryPluginsFromPath(
182         const String8 &path, vector<HidlCasPluginDescriptor>* results) {
183     closeFactory();
184 
185     vector<CasPluginDescriptor> descriptors;
186     if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
187         closeFactory();
188         return false;
189     }
190 
191     for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
192         results->push_back( HidlCasPluginDescriptor {
193                 .caSystemId = it->CA_system_id,
194                 .name = it->name.c_str()});
195     }
196     return true;
197 }
198 
199 template <class T>
openFactory(const String8 & path)200 bool FactoryLoader<T>::openFactory(const String8 &path) {
201     // get strong pointer to open shared library
202     ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
203     if (index >= 0) {
204         mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
205     } else {
206         index = mLibraryPathToOpenLibraryMap.add(path, NULL);
207     }
208 
209     if (!mLibrary.get()) {
210         mLibrary = new SharedLibrary(path);
211         if (!*mLibrary) {
212             return false;
213         }
214 
215         mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
216     }
217 
218     CreateFactoryFunc createFactory =
219         (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
220     if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
221         return false;
222     }
223     return true;
224 }
225 
226 template <class T>
closeFactory()227 void FactoryLoader<T>::closeFactory() {
228     delete mFactory;
229     mFactory = NULL;
230     mLibrary.clear();
231 }
232 
233 } // namespace implementation
234 } // namespace V1_0
235 } // namespace cas
236 } // namespace hardware
237 } // namespace android
238 
239 #endif // ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_
240