blob: 943f761033102d2351d4157b38b986e08a28fbf6 [file] [log] [blame]
Chong Zhanga4f67512017-04-24 17:18:25 -07001/*
2 * Copyright (C) 2017 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_0_FACTORY_LOADER_H_
18#define ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_
19
20#include <dirent.h>
21#include <dlfcn.h>
22#include "SharedLibrary.h"
23#include <utils/KeyedVector.h>
24#include <utils/Mutex.h>
25#include <media/cas/CasAPI.h>
26
27using namespace std;
28
29namespace android {
30namespace hardware {
31namespace cas {
32namespace V1_0 {
33namespace implementation {
34
35template <class T>
36class FactoryLoader {
37public:
38 FactoryLoader(const char *name) :
39 mFactory(NULL), mCreateFactoryFuncName(name) {}
40
41 virtual ~FactoryLoader() { closeFactory(); }
42
43 bool findFactoryForScheme(
44 int32_t CA_system_id,
45 sp<SharedLibrary> *library = NULL,
46 T** factory = NULL);
47
Steven Moreland2b537f72019-04-24 12:58:30 -070048 bool enumeratePlugins(hidl_vec<HidlCasPluginDescriptor>* results);
Chong Zhanga4f67512017-04-24 17:18:25 -070049
Steven Moreland2b537f72019-04-24 12:58:30 -070050 private:
Chong Zhanga4f67512017-04-24 17:18:25 -070051 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(
61 const String8 &path,
62 int32_t CA_system_id,
63 sp<SharedLibrary> *library,
64 T** factory);
65
Steven Moreland2b537f72019-04-24 12:58:30 -070066 bool queryPluginsFromPath(const String8& path, hidl_vec<HidlCasPluginDescriptor>* results);
Chong Zhanga4f67512017-04-24 17:18:25 -070067
68 bool openFactory(const String8 &path);
69 void closeFactory();
70};
71
72template <class T>
73bool FactoryLoader<T>::findFactoryForScheme(
74 int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) {
75 if (library != NULL) {
76 library->clear();
77 }
78 if (factory != NULL) {
79 *factory = NULL;
80 }
81
82 Mutex::Autolock autoLock(mMapLock);
83
84 // first check cache
85 ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
86 if (index >= 0) {
87 return loadFactoryForSchemeFromPath(
88 mCASystemIdToLibraryPathMap[index],
89 CA_system_id, library, factory);
90 }
91
92 // no luck, have to search
93 String8 dirPath("/vendor/lib/mediacas");
94 DIR* pDir = opendir(dirPath.string());
95
96 if (pDir == NULL) {
97 ALOGE("Failed to open plugin directory %s", dirPath.string());
98 return false;
99 }
100
101 struct dirent* pEntry;
102 while ((pEntry = readdir(pDir))) {
103 String8 pluginPath = dirPath + "/" + pEntry->d_name;
104 if (pluginPath.getPathExtension() == ".so") {
105 if (loadFactoryForSchemeFromPath(
106 pluginPath, CA_system_id, library, factory)) {
107 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
108 closedir(pDir);
109
110 return true;
111 }
112 }
113 }
114
115 closedir(pDir);
116
117 ALOGE("Failed to find plugin");
118 return false;
119}
120
121template <class T>
Steven Moreland2b537f72019-04-24 12:58:30 -0700122bool FactoryLoader<T>::enumeratePlugins(hidl_vec<HidlCasPluginDescriptor>* results) {
Chong Zhanga4f67512017-04-24 17:18:25 -0700123 ALOGI("enumeratePlugins");
124
Chong Zhanga4f67512017-04-24 17:18:25 -0700125 String8 dirPath("/vendor/lib/mediacas");
126 DIR* pDir = opendir(dirPath.string());
127
128 if (pDir == NULL) {
129 ALOGE("Failed to open plugin directory %s", dirPath.string());
130 return false;
131 }
132
133 Mutex::Autolock autoLock(mMapLock);
134
135 struct dirent* pEntry;
136 while ((pEntry = readdir(pDir))) {
137 String8 pluginPath = dirPath + "/" + pEntry->d_name;
138 if (pluginPath.getPathExtension() == ".so") {
139 queryPluginsFromPath(pluginPath, results);
140 }
141 }
142 return true;
143}
144
145template <class T>
146bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
147 const String8 &path, int32_t CA_system_id,
148 sp<SharedLibrary> *library, T** factory) {
149 closeFactory();
150
151 if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
152 closeFactory();
153 return false;
154 }
155
156 if (library != NULL) {
157 *library = mLibrary;
158 }
159 if (factory != NULL) {
160 *factory = mFactory;
161 }
162 return true;
163}
164
165template <class T>
Steven Moreland2b537f72019-04-24 12:58:30 -0700166bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
167 hidl_vec<HidlCasPluginDescriptor>* results) {
Chong Zhanga4f67512017-04-24 17:18:25 -0700168 closeFactory();
169
170 vector<CasPluginDescriptor> descriptors;
171 if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
172 closeFactory();
173 return false;
174 }
175
Steven Moreland2b537f72019-04-24 12:58:30 -0700176 results->resize(descriptors.size());
177
178 if (results->size() >= SIZE_MAX / sizeof(HidlCasPluginDescriptor)) {
179 return false;
Chong Zhanga4f67512017-04-24 17:18:25 -0700180 }
Steven Moreland2b537f72019-04-24 12:58:30 -0700181 memset(results->data(), 0, results->size() * sizeof(HidlCasPluginDescriptor));
182
183 for (size_t i = 0; i < results->size(); i++) {
184 HidlCasPluginDescriptor& descriptor = (*results)[i];
185 descriptor.caSystemId = descriptors[i].CA_system_id;
186 descriptor.name = descriptors[i].name.c_str();
187 }
188
Chong Zhanga4f67512017-04-24 17:18:25 -0700189 return true;
190}
191
192template <class T>
193bool FactoryLoader<T>::openFactory(const String8 &path) {
194 // get strong pointer to open shared library
195 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
196 if (index >= 0) {
197 mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
198 } else {
199 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
200 }
201
202 if (!mLibrary.get()) {
203 mLibrary = new SharedLibrary(path);
204 if (!*mLibrary) {
205 return false;
206 }
207
208 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
209 }
210
211 CreateFactoryFunc createFactory =
212 (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
213 if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
214 return false;
215 }
216 return true;
217}
218
219template <class T>
220void FactoryLoader<T>::closeFactory() {
221 delete mFactory;
222 mFactory = NULL;
223 mLibrary.clear();
224}
225
226} // namespace implementation
227} // namespace V1_0
228} // namespace cas
229} // namespace hardware
230} // namespace android
231
232#endif // ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_