blob: 8a60b78e626a556277adda980bf092b1d76299b4 [file] [log] [blame]
aimitakeshi27ed8ad2010-07-29 10:12:27 +09001/*
2 * Copyright (C) 2010 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 __PLUGIN_MANAGER_H__
18#define __PLUGIN_MANAGER_H__
19
20#include <dlfcn.h>
21#include <sys/types.h>
22#include <dirent.h>
23
24#include <utils/String8.h>
25#include <utils/Vector.h>
26#include <utils/KeyedVector.h>
27
Tomasz Wasilczyk259940c2023-08-23 03:29:56 +000028#include <filesystem>
29
aimitakeshi27ed8ad2010-07-29 10:12:27 +090030namespace android {
31
32const char* const PLUGIN_MANAGER_CREATE = "create";
33const char* const PLUGIN_MANAGER_DESTROY = "destroy";
34const char* const PLUGIN_EXTENSION = ".so";
35
36/**
37 * This is the template class for Plugin manager.
38 *
39 * The DrmManager uses this class to handle the plugins.
40 *
41 */
42template<typename Type>
43class TPlugInManager {
44private:
45 typedef void* HANDLE;
46 typedef Type* create_t(void);
47 typedef void destroy_t(Type*);
48 typedef create_t* FPCREATE;
49 typedef destroy_t* FPDESTORY;
50
51 typedef struct _PlugInContainer {
52 String8 sPath;
53 HANDLE hHandle;
54 FPCREATE fpCreate;
55 FPDESTORY fpDestory;
56 Type* pInstance;
57
58 _PlugInContainer():
59 sPath("")
60 ,hHandle(NULL)
61 ,fpCreate(NULL)
62 ,fpDestory(NULL)
63 ,pInstance(NULL)
64 {}
65 } PlugInContainer;
66
67 typedef KeyedVector<String8, PlugInContainer*> PlugInMap;
68 PlugInMap m_plugInMap;
69
70 typedef Vector<String8> PlugInIdList;
71 PlugInIdList m_plugInIdList;
72
73public:
74 /**
75 * Load all the plug-ins in the specified directory
76 *
77 * @param[in] rsPlugInDirPath
78 * Directory path which plug-ins (dynamic library) are stored
79 * @note Plug-ins should be implemented according to the specification
80 */
81 void loadPlugIns(const String8& rsPlugInDirPath) {
82 Vector<String8> plugInFileList = getPlugInPathList(rsPlugInDirPath);
83
84 if (!plugInFileList.isEmpty()) {
Mark Salyzyn3ab368e2014-04-15 14:55:53 -070085 for (size_t i = 0; i < plugInFileList.size(); ++i) {
aimitakeshi27ed8ad2010-07-29 10:12:27 +090086 loadPlugIn(plugInFileList[i]);
87 }
88 }
89 }
90
91 /**
92 * Unload all the plug-ins
93 *
94 */
95 void unloadPlugIns() {
Mark Salyzyn3ab368e2014-04-15 14:55:53 -070096 for (size_t i = 0; i < m_plugInIdList.size(); ++i) {
aimitakeshi27ed8ad2010-07-29 10:12:27 +090097 unloadPlugIn(m_plugInIdList[i]);
98 }
99 m_plugInIdList.clear();
100 }
101
102 /**
103 * Get all the IDs of available plug-ins
104 *
105 * @return[in] plugInIdList
106 * String type Vector in which all plug-in IDs are stored
107 */
108 Vector<String8> getPlugInIdList() const {
109 return m_plugInIdList;
110 }
111
112 /**
113 * Get a plug-in reference of specified ID
114 *
115 * @param[in] rsPlugInId
116 * Plug-in ID to be used
117 * @return plugIn
118 * Reference of specified plug-in instance
119 */
120 Type& getPlugIn(const String8& rsPlugInId) {
121 if (!contains(rsPlugInId)) {
122 // This error case never happens
123 }
124 return *(m_plugInMap.valueFor(rsPlugInId)->pInstance);
125 }
126
127public:
128 /**
129 * Load a plug-in stored in the specified path
130 *
131 * @param[in] rsPlugInPath
132 * Plug-in (dynamic library) file path
133 * @note Plug-in should be implemented according to the specification
134 */
135 void loadPlugIn(const String8& rsPlugInPath) {
136 if (contains(rsPlugInPath)) {
137 return;
138 }
139
140 PlugInContainer* pPlugInContainer = new PlugInContainer();
141
Tomasz Wasilczyk09977ff2023-08-11 15:52:22 +0000142 pPlugInContainer->hHandle = dlopen(rsPlugInPath.c_str(), RTLD_LAZY);
aimitakeshi27ed8ad2010-07-29 10:12:27 +0900143
144 if (NULL == pPlugInContainer->hHandle) {
145 delete pPlugInContainer;
146 pPlugInContainer = NULL;
147 return;
148 }
149
150 pPlugInContainer->sPath = rsPlugInPath;
151 pPlugInContainer->fpCreate
152 = (FPCREATE)dlsym(pPlugInContainer->hHandle, PLUGIN_MANAGER_CREATE);
153 pPlugInContainer->fpDestory
154 = (FPDESTORY)dlsym(pPlugInContainer->hHandle, PLUGIN_MANAGER_DESTROY);
155
156 if (NULL != pPlugInContainer->fpCreate && NULL != pPlugInContainer->fpDestory) {
157 pPlugInContainer->pInstance = (Type*)pPlugInContainer->fpCreate();
158 m_plugInIdList.add(rsPlugInPath);
159 m_plugInMap.add(rsPlugInPath, pPlugInContainer);
160 } else {
161 dlclose(pPlugInContainer->hHandle);
162 delete pPlugInContainer;
163 pPlugInContainer = NULL;
164 return;
165 }
166 }
167
168 /**
169 * Unload a plug-in stored in the specified path
170 *
171 * @param[in] rsPlugInPath
172 * Plug-in (dynamic library) file path
173 */
174 void unloadPlugIn(const String8& rsPlugInPath) {
175 if (!contains(rsPlugInPath)) {
176 return;
177 }
178
179 PlugInContainer* pPlugInContainer = m_plugInMap.valueFor(rsPlugInPath);
180 pPlugInContainer->fpDestory(pPlugInContainer->pInstance);
181 dlclose(pPlugInContainer->hHandle);
182
183 m_plugInMap.removeItem(rsPlugInPath);
184 delete pPlugInContainer;
185 pPlugInContainer = NULL;
186 }
187
188private:
189 /**
190 * True if TPlugInManager contains rsPlugInId
191 */
192 bool contains(const String8& rsPlugInId) {
193 return m_plugInMap.indexOfKey(rsPlugInId) != NAME_NOT_FOUND;
194 }
195
196 /**
197 * Return file path list of plug-ins stored in the specified directory
198 *
199 * @param[in] rsDirPath
200 * Directory path in which plug-ins are stored
201 * @return plugInFileList
202 * String type Vector in which file path of plug-ins are stored
203 */
204 Vector<String8> getPlugInPathList(const String8& rsDirPath) {
205 Vector<String8> fileList;
Tomasz Wasilczyk09977ff2023-08-11 15:52:22 +0000206 DIR* pDir = opendir(rsDirPath.c_str());
Gloria Wangc10ce332011-06-15 10:27:52 -0700207 struct dirent* pEntry;
aimitakeshi27ed8ad2010-07-29 10:12:27 +0900208
209 while (NULL != pDir && NULL != (pEntry = readdir(pDir))) {
210 if (!isPlugIn(pEntry)) {
211 continue;
212 }
213 String8 plugInPath;
214 plugInPath += rsDirPath;
215 plugInPath += "/";
216 plugInPath += pEntry->d_name;
217
218 fileList.add(plugInPath);
219 }
220
221 if (NULL != pDir) {
222 closedir(pDir);
223 }
aimitakeshi27ed8ad2010-07-29 10:12:27 +0900224
225 return fileList;
226 }
227
228 /**
229 * True if the input name denotes plug-in
230 */
231 bool isPlugIn(const struct dirent* pEntry) const {
Tomasz Wasilczyk259940c2023-08-23 03:29:56 +0000232 const auto extension = std::filesystem::path(pEntry->d_name).extension();
Glenn Kasten41b3d3b2011-03-14 11:32:29 -0700233 // Note that the plug-in extension must exactly match case
Tomasz Wasilczyk259940c2023-08-23 03:29:56 +0000234 return extension.string() == PLUGIN_EXTENSION;
aimitakeshi27ed8ad2010-07-29 10:12:27 +0900235 }
236
237 /**
aimitakeshi27ed8ad2010-07-29 10:12:27 +0900238 * True if input entry is directory
239 */
240 bool isDirectory(const struct dirent* pEntry) const {
241 return DT_DIR == pEntry->d_type;
242 }
243
244 /**
245 * True if input entry is regular file
246 */
247 bool isRegularFile(const struct dirent* pEntry) const {
248 return DT_REG == pEntry->d_type;
249 }
250
251 /**
252 * True if input entry is link
253 */
254 bool isLink(const struct dirent* pEntry) const {
255 return DT_LNK == pEntry->d_type;
256 }
257};
258
259};
260
261#endif /* __PLUGIN_MANAGER_H__ */
262