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