1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker *
4*4d7e907cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker *
8*4d7e907cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker *
10*4d7e907cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker */
16*4d7e907cSAndroid Build Coastguard Worker
17*4d7e907cSAndroid Build Coastguard Worker #ifndef ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
18*4d7e907cSAndroid Build Coastguard Worker #define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
19*4d7e907cSAndroid Build Coastguard Worker
20*4d7e907cSAndroid Build Coastguard Worker #include <android-base/strings.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <dirent.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <dlfcn.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <media/cas/CasAPI.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <utils/KeyedVector.h>
25*4d7e907cSAndroid Build Coastguard Worker #include <utils/Mutex.h>
26*4d7e907cSAndroid Build Coastguard Worker #include "SharedLibrary.h"
27*4d7e907cSAndroid Build Coastguard Worker
28*4d7e907cSAndroid Build Coastguard Worker using namespace std;
29*4d7e907cSAndroid Build Coastguard Worker
30*4d7e907cSAndroid Build Coastguard Worker namespace android {
31*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
32*4d7e907cSAndroid Build Coastguard Worker namespace cas {
33*4d7e907cSAndroid Build Coastguard Worker namespace V1_1 {
34*4d7e907cSAndroid Build Coastguard Worker namespace implementation {
35*4d7e907cSAndroid Build Coastguard Worker
36*4d7e907cSAndroid Build Coastguard Worker using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
37*4d7e907cSAndroid Build Coastguard Worker
38*4d7e907cSAndroid Build Coastguard Worker template <class T>
39*4d7e907cSAndroid Build Coastguard Worker class FactoryLoader {
40*4d7e907cSAndroid Build Coastguard Worker public:
FactoryLoader(const char * name)41*4d7e907cSAndroid Build Coastguard Worker FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
42*4d7e907cSAndroid Build Coastguard Worker
~FactoryLoader()43*4d7e907cSAndroid Build Coastguard Worker virtual ~FactoryLoader() { closeFactory(); }
44*4d7e907cSAndroid Build Coastguard Worker
45*4d7e907cSAndroid Build Coastguard Worker bool findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library = NULL,
46*4d7e907cSAndroid Build Coastguard Worker T** factory = NULL);
47*4d7e907cSAndroid Build Coastguard Worker
48*4d7e907cSAndroid Build Coastguard Worker bool enumeratePlugins(vector<HidlCasPluginDescriptor>* results);
49*4d7e907cSAndroid Build Coastguard Worker
50*4d7e907cSAndroid Build Coastguard Worker private:
51*4d7e907cSAndroid Build Coastguard Worker typedef T* (*CreateFactoryFunc)();
52*4d7e907cSAndroid Build Coastguard Worker
53*4d7e907cSAndroid Build Coastguard Worker Mutex mMapLock;
54*4d7e907cSAndroid Build Coastguard Worker T* mFactory;
55*4d7e907cSAndroid Build Coastguard Worker const char* mCreateFactoryFuncName;
56*4d7e907cSAndroid Build Coastguard Worker sp<SharedLibrary> mLibrary;
57*4d7e907cSAndroid Build Coastguard Worker KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
58*4d7e907cSAndroid Build Coastguard Worker KeyedVector<String8, wp<SharedLibrary>> mLibraryPathToOpenLibraryMap;
59*4d7e907cSAndroid Build Coastguard Worker
60*4d7e907cSAndroid Build Coastguard Worker bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
61*4d7e907cSAndroid Build Coastguard Worker sp<SharedLibrary>* library, T** factory);
62*4d7e907cSAndroid Build Coastguard Worker
63*4d7e907cSAndroid Build Coastguard Worker bool queryPluginsFromPath(const String8& path, vector<HidlCasPluginDescriptor>* results);
64*4d7e907cSAndroid Build Coastguard Worker
65*4d7e907cSAndroid Build Coastguard Worker bool openFactory(const String8& path);
66*4d7e907cSAndroid Build Coastguard Worker void closeFactory();
67*4d7e907cSAndroid Build Coastguard Worker };
68*4d7e907cSAndroid Build Coastguard Worker
69*4d7e907cSAndroid Build Coastguard Worker template <class T>
findFactoryForScheme(int32_t CA_system_id,sp<SharedLibrary> * library,T ** factory)70*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library,
71*4d7e907cSAndroid Build Coastguard Worker T** factory) {
72*4d7e907cSAndroid Build Coastguard Worker if (library != NULL) {
73*4d7e907cSAndroid Build Coastguard Worker library->clear();
74*4d7e907cSAndroid Build Coastguard Worker }
75*4d7e907cSAndroid Build Coastguard Worker if (factory != NULL) {
76*4d7e907cSAndroid Build Coastguard Worker *factory = NULL;
77*4d7e907cSAndroid Build Coastguard Worker }
78*4d7e907cSAndroid Build Coastguard Worker
79*4d7e907cSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mMapLock);
80*4d7e907cSAndroid Build Coastguard Worker
81*4d7e907cSAndroid Build Coastguard Worker // first check cache
82*4d7e907cSAndroid Build Coastguard Worker ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
83*4d7e907cSAndroid Build Coastguard Worker if (index >= 0) {
84*4d7e907cSAndroid Build Coastguard Worker return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
85*4d7e907cSAndroid Build Coastguard Worker library, factory);
86*4d7e907cSAndroid Build Coastguard Worker }
87*4d7e907cSAndroid Build Coastguard Worker
88*4d7e907cSAndroid Build Coastguard Worker // no luck, have to search
89*4d7e907cSAndroid Build Coastguard Worker #ifdef __LP64__
90*4d7e907cSAndroid Build Coastguard Worker String8 dirPath("/vendor/lib64/mediacas");
91*4d7e907cSAndroid Build Coastguard Worker #else
92*4d7e907cSAndroid Build Coastguard Worker String8 dirPath("/vendor/lib/mediacas");
93*4d7e907cSAndroid Build Coastguard Worker #endif
94*4d7e907cSAndroid Build Coastguard Worker DIR* pDir = opendir(dirPath.c_str());
95*4d7e907cSAndroid Build Coastguard Worker
96*4d7e907cSAndroid Build Coastguard Worker if (pDir == NULL) {
97*4d7e907cSAndroid Build Coastguard Worker ALOGE("Failed to open plugin directory %s", dirPath.c_str());
98*4d7e907cSAndroid Build Coastguard Worker return false;
99*4d7e907cSAndroid Build Coastguard Worker }
100*4d7e907cSAndroid Build Coastguard Worker
101*4d7e907cSAndroid Build Coastguard Worker struct dirent* pEntry;
102*4d7e907cSAndroid Build Coastguard Worker while ((pEntry = readdir(pDir))) {
103*4d7e907cSAndroid Build Coastguard Worker String8 pluginPath = dirPath + "/" + pEntry->d_name;
104*4d7e907cSAndroid Build Coastguard Worker if (base::EndsWith(pluginPath.c_str(), ".so")) {
105*4d7e907cSAndroid Build Coastguard Worker if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
106*4d7e907cSAndroid Build Coastguard Worker mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
107*4d7e907cSAndroid Build Coastguard Worker closedir(pDir);
108*4d7e907cSAndroid Build Coastguard Worker
109*4d7e907cSAndroid Build Coastguard Worker return true;
110*4d7e907cSAndroid Build Coastguard Worker }
111*4d7e907cSAndroid Build Coastguard Worker }
112*4d7e907cSAndroid Build Coastguard Worker }
113*4d7e907cSAndroid Build Coastguard Worker
114*4d7e907cSAndroid Build Coastguard Worker closedir(pDir);
115*4d7e907cSAndroid Build Coastguard Worker
116*4d7e907cSAndroid Build Coastguard Worker ALOGE("Failed to find plugin");
117*4d7e907cSAndroid Build Coastguard Worker return false;
118*4d7e907cSAndroid Build Coastguard Worker }
119*4d7e907cSAndroid Build Coastguard Worker
120*4d7e907cSAndroid Build Coastguard Worker template <class T>
enumeratePlugins(vector<HidlCasPluginDescriptor> * results)121*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::enumeratePlugins(vector<HidlCasPluginDescriptor>* results) {
122*4d7e907cSAndroid Build Coastguard Worker ALOGI("enumeratePlugins");
123*4d7e907cSAndroid Build Coastguard Worker
124*4d7e907cSAndroid Build Coastguard Worker results->clear();
125*4d7e907cSAndroid Build Coastguard Worker
126*4d7e907cSAndroid Build Coastguard Worker #ifdef __LP64__
127*4d7e907cSAndroid Build Coastguard Worker String8 dirPath("/vendor/lib64/mediacas");
128*4d7e907cSAndroid Build Coastguard Worker #else
129*4d7e907cSAndroid Build Coastguard Worker String8 dirPath("/vendor/lib/mediacas");
130*4d7e907cSAndroid Build Coastguard Worker #endif
131*4d7e907cSAndroid Build Coastguard Worker DIR* pDir = opendir(dirPath.c_str());
132*4d7e907cSAndroid Build Coastguard Worker
133*4d7e907cSAndroid Build Coastguard Worker if (pDir == NULL) {
134*4d7e907cSAndroid Build Coastguard Worker ALOGE("Failed to open plugin directory %s", dirPath.c_str());
135*4d7e907cSAndroid Build Coastguard Worker return false;
136*4d7e907cSAndroid Build Coastguard Worker }
137*4d7e907cSAndroid Build Coastguard Worker
138*4d7e907cSAndroid Build Coastguard Worker Mutex::Autolock autoLock(mMapLock);
139*4d7e907cSAndroid Build Coastguard Worker
140*4d7e907cSAndroid Build Coastguard Worker struct dirent* pEntry;
141*4d7e907cSAndroid Build Coastguard Worker while ((pEntry = readdir(pDir))) {
142*4d7e907cSAndroid Build Coastguard Worker String8 pluginPath = dirPath + "/" + pEntry->d_name;
143*4d7e907cSAndroid Build Coastguard Worker if (base::EndsWith(pluginPath.c_str(), ".so")) {
144*4d7e907cSAndroid Build Coastguard Worker queryPluginsFromPath(pluginPath, results);
145*4d7e907cSAndroid Build Coastguard Worker }
146*4d7e907cSAndroid Build Coastguard Worker }
147*4d7e907cSAndroid Build Coastguard Worker return true;
148*4d7e907cSAndroid Build Coastguard Worker }
149*4d7e907cSAndroid Build Coastguard Worker
150*4d7e907cSAndroid Build Coastguard Worker template <class T>
loadFactoryForSchemeFromPath(const String8 & path,int32_t CA_system_id,sp<SharedLibrary> * library,T ** factory)151*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
152*4d7e907cSAndroid Build Coastguard Worker sp<SharedLibrary>* library, T** factory) {
153*4d7e907cSAndroid Build Coastguard Worker closeFactory();
154*4d7e907cSAndroid Build Coastguard Worker
155*4d7e907cSAndroid Build Coastguard Worker if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
156*4d7e907cSAndroid Build Coastguard Worker closeFactory();
157*4d7e907cSAndroid Build Coastguard Worker return false;
158*4d7e907cSAndroid Build Coastguard Worker }
159*4d7e907cSAndroid Build Coastguard Worker
160*4d7e907cSAndroid Build Coastguard Worker if (library != NULL) {
161*4d7e907cSAndroid Build Coastguard Worker *library = mLibrary;
162*4d7e907cSAndroid Build Coastguard Worker }
163*4d7e907cSAndroid Build Coastguard Worker if (factory != NULL) {
164*4d7e907cSAndroid Build Coastguard Worker *factory = mFactory;
165*4d7e907cSAndroid Build Coastguard Worker }
166*4d7e907cSAndroid Build Coastguard Worker return true;
167*4d7e907cSAndroid Build Coastguard Worker }
168*4d7e907cSAndroid Build Coastguard Worker
169*4d7e907cSAndroid Build Coastguard Worker template <class T>
queryPluginsFromPath(const String8 & path,vector<HidlCasPluginDescriptor> * results)170*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
171*4d7e907cSAndroid Build Coastguard Worker vector<HidlCasPluginDescriptor>* results) {
172*4d7e907cSAndroid Build Coastguard Worker closeFactory();
173*4d7e907cSAndroid Build Coastguard Worker
174*4d7e907cSAndroid Build Coastguard Worker vector<CasPluginDescriptor> descriptors;
175*4d7e907cSAndroid Build Coastguard Worker if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
176*4d7e907cSAndroid Build Coastguard Worker closeFactory();
177*4d7e907cSAndroid Build Coastguard Worker return false;
178*4d7e907cSAndroid Build Coastguard Worker }
179*4d7e907cSAndroid Build Coastguard Worker
180*4d7e907cSAndroid Build Coastguard Worker for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
181*4d7e907cSAndroid Build Coastguard Worker results->push_back(
182*4d7e907cSAndroid Build Coastguard Worker HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
183*4d7e907cSAndroid Build Coastguard Worker }
184*4d7e907cSAndroid Build Coastguard Worker return true;
185*4d7e907cSAndroid Build Coastguard Worker }
186*4d7e907cSAndroid Build Coastguard Worker
187*4d7e907cSAndroid Build Coastguard Worker template <class T>
openFactory(const String8 & path)188*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::openFactory(const String8& path) {
189*4d7e907cSAndroid Build Coastguard Worker // get strong pointer to open shared library
190*4d7e907cSAndroid Build Coastguard Worker ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
191*4d7e907cSAndroid Build Coastguard Worker if (index >= 0) {
192*4d7e907cSAndroid Build Coastguard Worker mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
193*4d7e907cSAndroid Build Coastguard Worker } else {
194*4d7e907cSAndroid Build Coastguard Worker index = mLibraryPathToOpenLibraryMap.add(path, NULL);
195*4d7e907cSAndroid Build Coastguard Worker }
196*4d7e907cSAndroid Build Coastguard Worker
197*4d7e907cSAndroid Build Coastguard Worker if (!mLibrary.get()) {
198*4d7e907cSAndroid Build Coastguard Worker mLibrary = new SharedLibrary(path);
199*4d7e907cSAndroid Build Coastguard Worker if (!*mLibrary) {
200*4d7e907cSAndroid Build Coastguard Worker return false;
201*4d7e907cSAndroid Build Coastguard Worker }
202*4d7e907cSAndroid Build Coastguard Worker
203*4d7e907cSAndroid Build Coastguard Worker mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
204*4d7e907cSAndroid Build Coastguard Worker }
205*4d7e907cSAndroid Build Coastguard Worker
206*4d7e907cSAndroid Build Coastguard Worker CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
207*4d7e907cSAndroid Build Coastguard Worker if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
208*4d7e907cSAndroid Build Coastguard Worker return false;
209*4d7e907cSAndroid Build Coastguard Worker }
210*4d7e907cSAndroid Build Coastguard Worker return true;
211*4d7e907cSAndroid Build Coastguard Worker }
212*4d7e907cSAndroid Build Coastguard Worker
213*4d7e907cSAndroid Build Coastguard Worker template <class T>
closeFactory()214*4d7e907cSAndroid Build Coastguard Worker void FactoryLoader<T>::closeFactory() {
215*4d7e907cSAndroid Build Coastguard Worker delete mFactory;
216*4d7e907cSAndroid Build Coastguard Worker mFactory = NULL;
217*4d7e907cSAndroid Build Coastguard Worker mLibrary.clear();
218*4d7e907cSAndroid Build Coastguard Worker }
219*4d7e907cSAndroid Build Coastguard Worker
220*4d7e907cSAndroid Build Coastguard Worker } // namespace implementation
221*4d7e907cSAndroid Build Coastguard Worker } // namespace V1_1
222*4d7e907cSAndroid Build Coastguard Worker } // namespace cas
223*4d7e907cSAndroid Build Coastguard Worker } // namespace hardware
224*4d7e907cSAndroid Build Coastguard Worker } // namespace android
225*4d7e907cSAndroid Build Coastguard Worker
226*4d7e907cSAndroid Build Coastguard Worker #endif // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
227