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 #include <filesystem> 29 30 namespace android { 31 32 const char* const PLUGIN_MANAGER_CREATE = "create"; 33 const char* const PLUGIN_MANAGER_DESTROY = "destroy"; 34 const 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 */ 42 template<typename Type> 43 class TPlugInManager { 44 private: 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 _PlugInContainer_PlugInContainer58 _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 73 public: 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 */ loadPlugIns(const String8 & rsPlugInDirPath)81 void loadPlugIns(const String8& rsPlugInDirPath) { 82 Vector<String8> plugInFileList = getPlugInPathList(rsPlugInDirPath); 83 84 if (!plugInFileList.isEmpty()) { 85 for (size_t i = 0; i < plugInFileList.size(); ++i) { 86 loadPlugIn(plugInFileList[i]); 87 } 88 } 89 } 90 91 /** 92 * Unload all the plug-ins 93 * 94 */ unloadPlugIns()95 void unloadPlugIns() { 96 for (size_t i = 0; i < m_plugInIdList.size(); ++i) { 97 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 */ getPlugInIdList()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 */ getPlugIn(const String8 & rsPlugInId)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 127 public: 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 */ loadPlugIn(const String8 & rsPlugInPath)135 void loadPlugIn(const String8& rsPlugInPath) { 136 if (contains(rsPlugInPath)) { 137 return; 138 } 139 140 PlugInContainer* pPlugInContainer = new PlugInContainer(); 141 142 pPlugInContainer->hHandle = dlopen(rsPlugInPath.c_str(), RTLD_LAZY); 143 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 */ unloadPlugIn(const String8 & rsPlugInPath)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 188 private: 189 /** 190 * True if TPlugInManager contains rsPlugInId 191 */ contains(const String8 & rsPlugInId)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 */ getPlugInPathList(const String8 & rsDirPath)204 Vector<String8> getPlugInPathList(const String8& rsDirPath) { 205 Vector<String8> fileList; 206 DIR* pDir = opendir(rsDirPath.c_str()); 207 struct dirent* pEntry; 208 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 } 224 225 return fileList; 226 } 227 228 /** 229 * True if the input name denotes plug-in 230 */ isPlugIn(const struct dirent * pEntry)231 bool isPlugIn(const struct dirent* pEntry) const { 232 const auto extension = std::filesystem::path(pEntry->d_name).extension(); 233 // Note that the plug-in extension must exactly match case 234 return extension.string() == PLUGIN_EXTENSION; 235 } 236 237 /** 238 * True if input entry is directory 239 */ isDirectory(const struct dirent * pEntry)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 */ isRegularFile(const struct dirent * pEntry)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 */ isLink(const struct dirent * pEntry)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 263