blob: d7f1118654e0f3d835022ed70a314ba88af36151 [file] [log] [blame]
Chong Zhang9dbe9a52017-01-03 11:35:15 -08001/*
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
26namespace android {
27using namespace std;
28using namespace media;
29using namespace MediaCas;
30
31template <class T>
32class FactoryLoader {
33public:
34 FactoryLoader(const char *name) :
35 mFactory(NULL), mCreateFactoryFuncName(name) {}
36
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
46private:
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
70template <class T>
71bool 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
Chong Zhang3b1d1402017-04-18 15:01:37 -070091 String8 dirPath("/system/lib/mediacas");
Chong Zhang9dbe9a52017-01-03 11:35:15 -080092 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
119template <class T>
120bool FactoryLoader<T>::enumeratePlugins(
121 vector<ParcelableCasPluginDescriptor>* results) {
122 ALOGI("enumeratePlugins");
123
124 results->clear();
125
Chong Zhang3b1d1402017-04-18 15:01:37 -0700126 String8 dirPath("/system/lib/mediacas");
Chong Zhang9dbe9a52017-01-03 11:35:15 -0800127 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
146template <class T>
147bool 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
166template <class T>
167bool 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
184template <class T>
185bool 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
211template <class T>
212void FactoryLoader<T>::closeFactory() {
213 delete mFactory;
214 mFactory = NULL;
215 mLibrary.clear();
216}
217
218} // namespace android
219
220#endif // MEDIA_CAS_LOADER_H_