| /* | |
| * Copyright (C) 2010 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #ifndef __PLUGIN_MANAGER_H__ | |
| #define __PLUGIN_MANAGER_H__ | |
| #include <dlfcn.h> | |
| #include <sys/types.h> | |
| #include <dirent.h> | |
| #include <utils/String8.h> | |
| #include <utils/Vector.h> | |
| #include <utils/KeyedVector.h> | |
| namespace android { | |
| const char* const PLUGIN_MANAGER_CREATE = "create"; | |
| const char* const PLUGIN_MANAGER_DESTROY = "destroy"; | |
| const char* const PLUGIN_EXTENSION = ".so"; | |
| /** | |
| * This is the template class for Plugin manager. | |
| * | |
| * The DrmManager uses this class to handle the plugins. | |
| * | |
| */ | |
| template<typename Type> | |
| class TPlugInManager { | |
| private: | |
| typedef void* HANDLE; | |
| typedef Type* create_t(void); | |
| typedef void destroy_t(Type*); | |
| typedef create_t* FPCREATE; | |
| typedef destroy_t* FPDESTORY; | |
| typedef struct _PlugInContainer { | |
| String8 sPath; | |
| HANDLE hHandle; | |
| FPCREATE fpCreate; | |
| FPDESTORY fpDestory; | |
| Type* pInstance; | |
| _PlugInContainer(): | |
| sPath("") | |
| ,hHandle(NULL) | |
| ,fpCreate(NULL) | |
| ,fpDestory(NULL) | |
| ,pInstance(NULL) | |
| {} | |
| } PlugInContainer; | |
| typedef KeyedVector<String8, PlugInContainer*> PlugInMap; | |
| PlugInMap m_plugInMap; | |
| typedef Vector<String8> PlugInIdList; | |
| PlugInIdList m_plugInIdList; | |
| public: | |
| /** | |
| * Load all the plug-ins in the specified directory | |
| * | |
| * @param[in] rsPlugInDirPath | |
| * Directory path which plug-ins (dynamic library) are stored | |
| * @note Plug-ins should be implemented according to the specification | |
| */ | |
| void loadPlugIns(const String8& rsPlugInDirPath) { | |
| Vector<String8> plugInFileList = getPlugInPathList(rsPlugInDirPath); | |
| if (!plugInFileList.isEmpty()) { | |
| for (unsigned int i = 0; i < plugInFileList.size(); ++i) { | |
| loadPlugIn(plugInFileList[i]); | |
| } | |
| } | |
| } | |
| /** | |
| * Unload all the plug-ins | |
| * | |
| */ | |
| void unloadPlugIns() { | |
| for (unsigned int i = 0; i < m_plugInIdList.size(); ++i) { | |
| unloadPlugIn(m_plugInIdList[i]); | |
| } | |
| m_plugInIdList.clear(); | |
| } | |
| /** | |
| * Get all the IDs of available plug-ins | |
| * | |
| * @return[in] plugInIdList | |
| * String type Vector in which all plug-in IDs are stored | |
| */ | |
| Vector<String8> getPlugInIdList() const { | |
| return m_plugInIdList; | |
| } | |
| /** | |
| * Get a plug-in reference of specified ID | |
| * | |
| * @param[in] rsPlugInId | |
| * Plug-in ID to be used | |
| * @return plugIn | |
| * Reference of specified plug-in instance | |
| */ | |
| Type& getPlugIn(const String8& rsPlugInId) { | |
| if (!contains(rsPlugInId)) { | |
| // This error case never happens | |
| } | |
| return *(m_plugInMap.valueFor(rsPlugInId)->pInstance); | |
| } | |
| public: | |
| /** | |
| * Load a plug-in stored in the specified path | |
| * | |
| * @param[in] rsPlugInPath | |
| * Plug-in (dynamic library) file path | |
| * @note Plug-in should be implemented according to the specification | |
| */ | |
| void loadPlugIn(const String8& rsPlugInPath) { | |
| if (contains(rsPlugInPath)) { | |
| return; | |
| } | |
| PlugInContainer* pPlugInContainer = new PlugInContainer(); | |
| pPlugInContainer->hHandle = dlopen(rsPlugInPath.string(), RTLD_LAZY); | |
| if (NULL == pPlugInContainer->hHandle) { | |
| delete pPlugInContainer; | |
| pPlugInContainer = NULL; | |
| return; | |
| } | |
| pPlugInContainer->sPath = rsPlugInPath; | |
| pPlugInContainer->fpCreate | |
| = (FPCREATE)dlsym(pPlugInContainer->hHandle, PLUGIN_MANAGER_CREATE); | |
| pPlugInContainer->fpDestory | |
| = (FPDESTORY)dlsym(pPlugInContainer->hHandle, PLUGIN_MANAGER_DESTROY); | |
| if (NULL != pPlugInContainer->fpCreate && NULL != pPlugInContainer->fpDestory) { | |
| pPlugInContainer->pInstance = (Type*)pPlugInContainer->fpCreate(); | |
| m_plugInIdList.add(rsPlugInPath); | |
| m_plugInMap.add(rsPlugInPath, pPlugInContainer); | |
| } else { | |
| dlclose(pPlugInContainer->hHandle); | |
| delete pPlugInContainer; | |
| pPlugInContainer = NULL; | |
| return; | |
| } | |
| } | |
| /** | |
| * Unload a plug-in stored in the specified path | |
| * | |
| * @param[in] rsPlugInPath | |
| * Plug-in (dynamic library) file path | |
| */ | |
| void unloadPlugIn(const String8& rsPlugInPath) { | |
| if (!contains(rsPlugInPath)) { | |
| return; | |
| } | |
| PlugInContainer* pPlugInContainer = m_plugInMap.valueFor(rsPlugInPath); | |
| pPlugInContainer->fpDestory(pPlugInContainer->pInstance); | |
| dlclose(pPlugInContainer->hHandle); | |
| m_plugInMap.removeItem(rsPlugInPath); | |
| delete pPlugInContainer; | |
| pPlugInContainer = NULL; | |
| } | |
| private: | |
| /** | |
| * True if TPlugInManager contains rsPlugInId | |
| */ | |
| bool contains(const String8& rsPlugInId) { | |
| return m_plugInMap.indexOfKey(rsPlugInId) != NAME_NOT_FOUND; | |
| } | |
| /** | |
| * Return file path list of plug-ins stored in the specified directory | |
| * | |
| * @param[in] rsDirPath | |
| * Directory path in which plug-ins are stored | |
| * @return plugInFileList | |
| * String type Vector in which file path of plug-ins are stored | |
| */ | |
| Vector<String8> getPlugInPathList(const String8& rsDirPath) { | |
| Vector<String8> fileList; | |
| DIR* pDir = opendir(rsDirPath.string()); | |
| struct dirent* pEntry = new dirent(); | |
| while (NULL != pDir && NULL != (pEntry = readdir(pDir))) { | |
| if (!isPlugIn(pEntry)) { | |
| continue; | |
| } | |
| String8 plugInPath; | |
| plugInPath += rsDirPath; | |
| plugInPath += "/"; | |
| plugInPath += pEntry->d_name; | |
| fileList.add(plugInPath); | |
| } | |
| if (NULL != pDir) { | |
| closedir(pDir); | |
| } | |
| delete pEntry; | |
| pEntry = NULL; | |
| return fileList; | |
| } | |
| /** | |
| * True if the input name denotes plug-in | |
| */ | |
| bool isPlugIn(const struct dirent* pEntry) const { | |
| String8 sName(pEntry->d_name); | |
| String8 extension(sName.getPathExtension()); | |
| // Note that the plug-in extension must exactly match case | |
| return extension == String8(PLUGIN_EXTENSION); | |
| } | |
| /** | |
| * True if the input entry is "." or ".." | |
| */ | |
| bool isDotOrDDot(const struct dirent* pEntry) const { | |
| String8 sName(pEntry->d_name); | |
| return "." == sName || ".." == sName; | |
| } | |
| /** | |
| * True if input entry is directory | |
| */ | |
| bool isDirectory(const struct dirent* pEntry) const { | |
| return DT_DIR == pEntry->d_type; | |
| } | |
| /** | |
| * True if input entry is regular file | |
| */ | |
| bool isRegularFile(const struct dirent* pEntry) const { | |
| return DT_REG == pEntry->d_type; | |
| } | |
| /** | |
| * True if input entry is link | |
| */ | |
| bool isLink(const struct dirent* pEntry) const { | |
| return DT_LNK == pEntry->d_type; | |
| } | |
| }; | |
| }; | |
| #endif /* __PLUGIN_MANAGER_H__ */ | |