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