/*
* 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;
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 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__ */