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