blob: f90b109718d42d19e59931e7ad1aa74dc600fda4 [file] [log] [blame]
/*
* Copyright (C) 2022 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.
*/
#include <dirent.h>
#include <dlfcn.h>
#include <media/cas/CasAPI.h>
#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
#include "SharedLibrary.h"
using namespace std;
namespace aidl {
namespace android {
namespace hardware {
namespace cas {
using namespace ::android;
template <class T>
class FactoryLoader {
public:
FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
virtual ~FactoryLoader() { closeFactory(); }
bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
T** factory = NULL);
bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
private:
typedef T* (*CreateFactoryFunc)();
Mutex mMapLock;
T* mFactory;
const char* mCreateFactoryFuncName;
shared_ptr<SharedLibrary> mLibrary;
KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
shared_ptr<SharedLibrary>* library, T** factory);
bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
bool openFactory(const String8& path);
void closeFactory();
};
template <class T>
bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
shared_ptr<SharedLibrary>* library, T** factory) {
if (library != NULL) {
library->reset();
}
if (factory != NULL) {
*factory = NULL;
}
Mutex::Autolock autoLock(mMapLock);
// first check cache
ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
if (index >= 0) {
return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
library, factory);
}
// no luck, have to search
#ifdef __LP64__
String8 dirPath("/vendor/lib64/mediacas");
#else
String8 dirPath("/vendor/lib/mediacas");
#endif
DIR* pDir = opendir(dirPath.string());
if (pDir == NULL) {
ALOGE("Failed to open plugin directory %s", dirPath.string());
return false;
}
struct dirent* pEntry;
while ((pEntry = readdir(pDir))) {
String8 pluginPath = dirPath + "/" + pEntry->d_name;
if (pluginPath.getPathExtension() == ".so") {
if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
closedir(pDir);
return true;
}
}
}
closedir(pDir);
ALOGE("Failed to find plugin");
return false;
}
template <class T>
bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
ALOGI("enumeratePlugins");
results->clear();
#ifdef __LP64__
String8 dirPath("/vendor/lib64/mediacas");
#else
String8 dirPath("/vendor/lib/mediacas");
#endif
DIR* pDir = opendir(dirPath.string());
if (pDir == NULL) {
ALOGE("Failed to open plugin directory %s", dirPath.string());
return false;
}
Mutex::Autolock autoLock(mMapLock);
struct dirent* pEntry;
while ((pEntry = readdir(pDir))) {
String8 pluginPath = dirPath + "/" + pEntry->d_name;
if (pluginPath.getPathExtension() == ".so") {
queryPluginsFromPath(pluginPath, results);
}
}
return true;
}
template <class T>
bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
shared_ptr<SharedLibrary>* library,
T** factory) {
closeFactory();
if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
closeFactory();
return false;
}
if (library != NULL) {
*library = mLibrary;
}
if (factory != NULL) {
*factory = mFactory;
}
return true;
}
template <class T>
bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
vector<AidlCasPluginDescriptor>* results) {
closeFactory();
vector<CasPluginDescriptor> descriptors;
if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
closeFactory();
return false;
}
for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
results->push_back(
AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
}
return true;
}
template <class T>
bool FactoryLoader<T>::openFactory(const String8& path) {
// get strong pointer to open shared library
ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
if (index >= 0) {
mLibrary = mLibraryPathToOpenLibraryMap[index];
} else {
index = mLibraryPathToOpenLibraryMap.add(path, NULL);
}
if (!mLibrary.get()) {
mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
if (!*mLibrary) {
return false;
}
mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
}
CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
return false;
}
return true;
}
template <class T>
void FactoryLoader<T>::closeFactory() {
delete mFactory;
mFactory = NULL;
mLibrary.reset();
}
} // namespace cas
} // namespace hardware
} // namespace android
} // namespace aidl