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