/* * Copyright (C) 2019 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 ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ #define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ #include #include #include #include #include #include "SharedLibrary.h" using namespace std; namespace android { namespace hardware { namespace cas { namespace V1_1 { namespace implementation { using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor; template class FactoryLoader { public: FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {} virtual ~FactoryLoader() { closeFactory(); } bool findFactoryForScheme(int32_t CA_system_id, sp* library = NULL, T** factory = NULL); bool enumeratePlugins(vector* results); private: typedef T* (*CreateFactoryFunc)(); Mutex mMapLock; T* mFactory; const char* mCreateFactoryFuncName; sp mLibrary; KeyedVector mCASystemIdToLibraryPathMap; KeyedVector> mLibraryPathToOpenLibraryMap; bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, sp* library, T** factory); bool queryPluginsFromPath(const String8& path, vector* results); bool openFactory(const String8& path); void closeFactory(); }; template bool FactoryLoader::findFactoryForScheme(int32_t CA_system_id, sp* library, T** factory) { if (library != NULL) { library->clear(); } 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 bool FactoryLoader::enumeratePlugins(vector* 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 bool FactoryLoader::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, sp* 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 bool FactoryLoader::queryPluginsFromPath(const String8& path, vector* results) { closeFactory(); vector descriptors; if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) { closeFactory(); return false; } for (auto it = descriptors.begin(); it != descriptors.end(); it++) { results->push_back( HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()}); } return true; } template bool FactoryLoader::openFactory(const String8& path) { // get strong pointer to open shared library ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); if (index >= 0) { mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); } else { index = mLibraryPathToOpenLibraryMap.add(path, NULL); } if (!mLibrary.get()) { mLibrary = new 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 void FactoryLoader::closeFactory() { delete mFactory; mFactory = NULL; mLibrary.clear(); } } // namespace implementation } // namespace V1_1 } // namespace cas } // namespace hardware } // namespace android #endif // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_