| /* |
| * 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> |
| |
| #include <filesystem> |
| |
| 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 (size_t i = 0; i < plugInFileList.size(); ++i) { |
| loadPlugIn(plugInFileList[i]); |
| } |
| } |
| } |
| |
| /** |
| * Unload all the plug-ins |
| * |
| */ |
| void unloadPlugIns() { |
| for (size_t 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.c_str(), 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.c_str()); |
| struct dirent* pEntry; |
| |
| 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); |
| } |
| |
| return fileList; |
| } |
| |
| /** |
| * True if the input name denotes plug-in |
| */ |
| bool isPlugIn(const struct dirent* pEntry) const { |
| const auto extension = std::filesystem::path(pEntry->d_name).extension(); |
| // Note that the plug-in extension must exactly match case |
| return extension.string() == PLUGIN_EXTENSION; |
| } |
| |
| /** |
| * 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__ */ |
| |