blob: 0b05bfcae1a3d875b388df3891abd9ac638f5cbc [file] [log] [blame]
Henry Fang9bed3dc2019-10-11 17:30:15 -07001/*
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
Tomasz Wasilczyk9e532812023-08-29 15:04:50 +000020#include <android-base/strings.h>
Henry Fang9bed3dc2019-10-11 17:30:15 -070021#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
28using namespace std;
29
30namespace android {
31namespace hardware {
32namespace cas {
33namespace V1_1 {
34namespace implementation {
35
36using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
37
38template <class T>
39class FactoryLoader {
40 public:
41 FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
42
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
69template <class T>
70bool 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
bohub305c802021-01-30 19:14:05 -080089#ifdef __LP64__
90 String8 dirPath("/vendor/lib64/mediacas");
91#else
Henry Fang9bed3dc2019-10-11 17:30:15 -070092 String8 dirPath("/vendor/lib/mediacas");
bohub305c802021-01-30 19:14:05 -080093#endif
Tomasz Wasilczyk3e74f0b2023-08-11 16:04:23 +000094 DIR* pDir = opendir(dirPath.c_str());
Henry Fang9bed3dc2019-10-11 17:30:15 -070095
96 if (pDir == NULL) {
Tomasz Wasilczyk3e74f0b2023-08-11 16:04:23 +000097 ALOGE("Failed to open plugin directory %s", dirPath.c_str());
Henry Fang9bed3dc2019-10-11 17:30:15 -070098 return false;
99 }
100
101 struct dirent* pEntry;
102 while ((pEntry = readdir(pDir))) {
103 String8 pluginPath = dirPath + "/" + pEntry->d_name;
Tomasz Wasilczyk9e532812023-08-29 15:04:50 +0000104 if (base::EndsWith(pluginPath.c_str(), ".so")) {
Henry Fang9bed3dc2019-10-11 17:30:15 -0700105 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
120template <class T>
121bool FactoryLoader<T>::enumeratePlugins(vector<HidlCasPluginDescriptor>* results) {
122 ALOGI("enumeratePlugins");
123
124 results->clear();
125
bohub305c802021-01-30 19:14:05 -0800126#ifdef __LP64__
127 String8 dirPath("/vendor/lib64/mediacas");
128#else
Henry Fang9bed3dc2019-10-11 17:30:15 -0700129 String8 dirPath("/vendor/lib/mediacas");
bohub305c802021-01-30 19:14:05 -0800130#endif
Tomasz Wasilczyk3e74f0b2023-08-11 16:04:23 +0000131 DIR* pDir = opendir(dirPath.c_str());
Henry Fang9bed3dc2019-10-11 17:30:15 -0700132
133 if (pDir == NULL) {
Tomasz Wasilczyk3e74f0b2023-08-11 16:04:23 +0000134 ALOGE("Failed to open plugin directory %s", dirPath.c_str());
Henry Fang9bed3dc2019-10-11 17:30:15 -0700135 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;
Tomasz Wasilczyk9e532812023-08-29 15:04:50 +0000143 if (base::EndsWith(pluginPath.c_str(), ".so")) {
Henry Fang9bed3dc2019-10-11 17:30:15 -0700144 queryPluginsFromPath(pluginPath, results);
145 }
146 }
147 return true;
148}
149
150template <class T>
151bool 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
169template <class T>
170bool 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
187template <class T>
188bool 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
213template <class T>
214void 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_