blob: 862d5570e6cdd695f0703223e04ec876f168266d [file] [log] [blame]
Henry Fang3e3cbb72019-01-31 22:46:57 +00001/*
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 <dirent.h>
21#include <dlfcn.h>
22#include <media/cas/CasAPI.h>
23#include <utils/KeyedVector.h>
24#include <utils/Mutex.h>
25#include "SharedLibrary.h"
26
27using namespace std;
28
29namespace android {
30namespace hardware {
31namespace cas {
32namespace V1_1 {
33namespace implementation {
34
35using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
36
37template <class T>
38class FactoryLoader {
39 public:
40 FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
41
42 virtual ~FactoryLoader() { closeFactory(); }
43
44 bool findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library = NULL,
45 T** factory = NULL);
46
Steven Moreland2b537f72019-04-24 12:58:30 -070047 bool enumeratePlugins(hidl_vec<HidlCasPluginDescriptor>* results);
Henry Fang3e3cbb72019-01-31 22:46:57 +000048
Steven Moreland2b537f72019-04-24 12:58:30 -070049 private:
Henry Fang3e3cbb72019-01-31 22:46:57 +000050 typedef T* (*CreateFactoryFunc)();
51
52 Mutex mMapLock;
53 T* mFactory;
54 const char* mCreateFactoryFuncName;
55 sp<SharedLibrary> mLibrary;
56 KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
57 KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
58
59 bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
60 sp<SharedLibrary>* library, T** factory);
61
Steven Moreland2b537f72019-04-24 12:58:30 -070062 bool queryPluginsFromPath(const String8& path, hidl_vec<HidlCasPluginDescriptor>* results);
Henry Fang3e3cbb72019-01-31 22:46:57 +000063
64 bool openFactory(const String8& path);
65 void closeFactory();
66};
67
68template <class T>
69bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library,
70 T** factory) {
71 if (library != NULL) {
72 library->clear();
73 }
74 if (factory != NULL) {
75 *factory = NULL;
76 }
77
78 Mutex::Autolock autoLock(mMapLock);
79
80 // first check cache
81 ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
82 if (index >= 0) {
83 return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
84 library, factory);
85 }
86
87 // no luck, have to search
88 String8 dirPath("/vendor/lib/mediacas");
89 DIR* pDir = opendir(dirPath.string());
90
91 if (pDir == NULL) {
92 ALOGE("Failed to open plugin directory %s", dirPath.string());
93 return false;
94 }
95
96 struct dirent* pEntry;
97 while ((pEntry = readdir(pDir))) {
98 String8 pluginPath = dirPath + "/" + pEntry->d_name;
99 if (pluginPath.getPathExtension() == ".so") {
100 if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
101 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
102 closedir(pDir);
103
104 return true;
105 }
106 }
107 }
108
109 closedir(pDir);
110
111 ALOGE("Failed to find plugin");
112 return false;
113}
114
115template <class T>
Steven Moreland2b537f72019-04-24 12:58:30 -0700116bool FactoryLoader<T>::enumeratePlugins(hidl_vec<HidlCasPluginDescriptor>* results) {
Henry Fang3e3cbb72019-01-31 22:46:57 +0000117 ALOGI("enumeratePlugins");
118
Henry Fang3e3cbb72019-01-31 22:46:57 +0000119 String8 dirPath("/vendor/lib/mediacas");
120 DIR* pDir = opendir(dirPath.string());
121
122 if (pDir == NULL) {
123 ALOGE("Failed to open plugin directory %s", dirPath.string());
124 return false;
125 }
126
127 Mutex::Autolock autoLock(mMapLock);
128
129 struct dirent* pEntry;
130 while ((pEntry = readdir(pDir))) {
131 String8 pluginPath = dirPath + "/" + pEntry->d_name;
132 if (pluginPath.getPathExtension() == ".so") {
133 queryPluginsFromPath(pluginPath, results);
134 }
135 }
136 return true;
137}
138
139template <class T>
140bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
141 sp<SharedLibrary>* library, T** factory) {
142 closeFactory();
143
144 if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
145 closeFactory();
146 return false;
147 }
148
149 if (library != NULL) {
150 *library = mLibrary;
151 }
152 if (factory != NULL) {
153 *factory = mFactory;
154 }
155 return true;
156}
157
158template <class T>
159bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
Steven Moreland2b537f72019-04-24 12:58:30 -0700160 hidl_vec<HidlCasPluginDescriptor>* results) {
Henry Fang3e3cbb72019-01-31 22:46:57 +0000161 closeFactory();
162
163 vector<CasPluginDescriptor> descriptors;
164 if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
165 closeFactory();
166 return false;
167 }
168
Steven Moreland2b537f72019-04-24 12:58:30 -0700169 results->resize(descriptors.size());
170
171 if (results->size() >= SIZE_MAX / sizeof(HidlCasPluginDescriptor)) {
172 return false;
Henry Fang3e3cbb72019-01-31 22:46:57 +0000173 }
Steven Moreland2b537f72019-04-24 12:58:30 -0700174 memset(results->data(), 0, results->size() * sizeof(HidlCasPluginDescriptor));
175
176 for (size_t i = 0; i < results->size(); i++) {
177 HidlCasPluginDescriptor& descriptor = (*results)[i];
178 descriptor.caSystemId = descriptors[i].CA_system_id;
179 descriptor.name = descriptors[i].name.c_str();
180 }
181
Henry Fang3e3cbb72019-01-31 22:46:57 +0000182 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].promote();
191 } else {
192 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
193 }
194
195 if (!mLibrary.get()) {
196 mLibrary = new 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.clear();
216}
217
218} // namespace implementation
219} // namespace V1_1
220} // namespace cas
221} // namespace hardware
222} // namespace android
223
224#endif // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_