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