blob: bc3d715fdafd3761edf473da95fe00cde5fbf24b [file] [log] [blame]
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +05301/*
2 * Copyright (C) 2022 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
Tomasz Wasilczyk7c52bb12023-08-23 15:07:31 +000017#include <android-base/strings.h>
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +053018#include <dirent.h>
19#include <dlfcn.h>
20#include <media/cas/CasAPI.h>
21#include <utils/KeyedVector.h>
22#include <utils/Mutex.h>
23#include "SharedLibrary.h"
24
25using namespace std;
26
27namespace aidl {
28namespace android {
29namespace hardware {
30namespace cas {
31
32using namespace ::android;
33
34template <class T>
35class FactoryLoader {
36 public:
37 FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
38
39 virtual ~FactoryLoader() { closeFactory(); }
40
41 bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
42 T** factory = NULL);
43
44 bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
45
46 private:
47 typedef T* (*CreateFactoryFunc)();
48
49 Mutex mMapLock;
50 T* mFactory;
51 const char* mCreateFactoryFuncName;
52 shared_ptr<SharedLibrary> mLibrary;
53 KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
54 KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
55
56 bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
57 shared_ptr<SharedLibrary>* library, T** factory);
58
59 bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
60
61 bool openFactory(const String8& path);
62 void closeFactory();
63};
64
65template <class T>
66bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
67 shared_ptr<SharedLibrary>* library, T** factory) {
68 if (library != NULL) {
69 library->reset();
70 }
71 if (factory != NULL) {
72 *factory = NULL;
73 }
74
75 Mutex::Autolock autoLock(mMapLock);
76
77 // first check cache
78 ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
79 if (index >= 0) {
80 return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
81 library, factory);
82 }
83
84 // no luck, have to search
85#ifdef __LP64__
86 String8 dirPath("/vendor/lib64/mediacas");
87#else
88 String8 dirPath("/vendor/lib/mediacas");
89#endif
Tomasz Wasilczyk3e74f0b2023-08-11 16:04:23 +000090 DIR* pDir = opendir(dirPath.c_str());
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +053091
92 if (pDir == NULL) {
Tomasz Wasilczyk3e74f0b2023-08-11 16:04:23 +000093 ALOGE("Failed to open plugin directory %s", dirPath.c_str());
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +053094 return false;
95 }
96
97 struct dirent* pEntry;
98 while ((pEntry = readdir(pDir))) {
99 String8 pluginPath = dirPath + "/" + pEntry->d_name;
Tomasz Wasilczyk7c52bb12023-08-23 15:07:31 +0000100 if (base::EndsWith(pluginPath.c_str(), ".so")) {
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +0530101 if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
102 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
103 closedir(pDir);
104
105 return true;
106 }
107 }
108 }
109
110 closedir(pDir);
111
112 ALOGE("Failed to find plugin");
113 return false;
114}
115
116template <class T>
117bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
118 ALOGI("enumeratePlugins");
119
120 results->clear();
121
122#ifdef __LP64__
123 String8 dirPath("/vendor/lib64/mediacas");
124#else
125 String8 dirPath("/vendor/lib/mediacas");
126#endif
Tomasz Wasilczyk3e74f0b2023-08-11 16:04:23 +0000127 DIR* pDir = opendir(dirPath.c_str());
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +0530128
129 if (pDir == NULL) {
Tomasz Wasilczyk3e74f0b2023-08-11 16:04:23 +0000130 ALOGE("Failed to open plugin directory %s", dirPath.c_str());
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +0530131 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;
Tomasz Wasilczyk7c52bb12023-08-23 15:07:31 +0000139 if (base::EndsWith(pluginPath.c_str(), ".so")) {
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +0530140 queryPluginsFromPath(pluginPath, results);
141 }
142 }
Shraddha Basantwani09edb572023-01-31 14:03:08 +0530143 closedir(pDir);
Shraddha Basantwani6545b4e2022-09-21 16:26:19 +0530144 return true;
145}
146
147template <class T>
148bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
149 shared_ptr<SharedLibrary>* library,
150 T** factory) {
151 closeFactory();
152
153 if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
154 closeFactory();
155 return false;
156 }
157
158 if (library != NULL) {
159 *library = mLibrary;
160 }
161 if (factory != NULL) {
162 *factory = mFactory;
163 }
164 return true;
165}
166
167template <class T>
168bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
169 vector<AidlCasPluginDescriptor>* results) {
170 closeFactory();
171
172 vector<CasPluginDescriptor> descriptors;
173 if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
174 closeFactory();
175 return false;
176 }
177
178 for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
179 results->push_back(
180 AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
181 }
182 return true;
183}
184
185template <class T>
186bool FactoryLoader<T>::openFactory(const String8& path) {
187 // get strong pointer to open shared library
188 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
189 if (index >= 0) {
190 mLibrary = mLibraryPathToOpenLibraryMap[index];
191 } else {
192 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
193 }
194
195 if (!mLibrary.get()) {
196 mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
197 if (!*mLibrary) {
198 return false;
199 }
200
201 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
202 }
203
204 CreateFactoryFunc createFactory = (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.reset();
216}
217
218} // namespace cas
219} // namespace hardware
220} // namespace android
221} // namespace aidl