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 (unsigned int 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 (unsigned int 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 the input entry is "." or ".." 238 */ isDotOrDDot(const struct dirent * pEntry)239 bool isDotOrDDot(const struct dirent* pEntry) const { 240 String8 sName(pEntry->d_name); 241 return "." == sName || ".." == sName; 242 } 243 244 /** 245 * True if input entry is directory 246 */ isDirectory(const struct dirent * pEntry)247 bool isDirectory(const struct dirent* pEntry) const { 248 return DT_DIR == pEntry->d_type; 249 } 250 251 /** 252 * True if input entry is regular file 253 */ isRegularFile(const struct dirent * pEntry)254 bool isRegularFile(const struct dirent* pEntry) const { 255 return DT_REG == pEntry->d_type; 256 } 257 258 /** 259 * True if input entry is link 260 */ isLink(const struct dirent * pEntry)261 bool isLink(const struct dirent* pEntry) const { 262 return DT_LNK == pEntry->d_type; 263 } 264 }; 265 266 }; 267 268 #endif /* __PLUGIN_MANAGER_H__ */ 269 270