You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
7.2 KiB
262 lines
7.2 KiB
4 months ago
|
/*
|
||
|
* 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 (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.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;
|
||
|
|
||
|
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 {
|
||
|
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 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__ */
|
||
|
|