Home | History | Annotate | Download | only in default
      1 /*
      2  * Copyright (C) 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
     18 #define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
     19 
     20 #include <dirent.h>
     21 #include <dlfcn.h>
     22 #include <media/cas/CasAPI.h>
     23 #include <utils/KeyedVector.h>
     24 #include <utils/Mutex.h>
     25 #include "SharedLibrary.h"
     26 
     27 using namespace std;
     28 
     29 namespace android {
     30 namespace hardware {
     31 namespace cas {
     32 namespace V1_1 {
     33 namespace implementation {
     34 
     35 using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
     36 
     37 template <class T>
     38 class FactoryLoader {
     39    public:
     40     FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
     41 
     42     virtual ~FactoryLoader() { closeFactory(); }
     43 
     44     bool findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library = NULL,
     45                               T** factory = NULL);
     46 
     47     bool enumeratePlugins(vector<HidlCasPluginDescriptor>* results);
     48 
     49    private:
     50     typedef T* (*CreateFactoryFunc)();
     51 
     52     Mutex mMapLock;
     53     T* mFactory;
     54     const char* mCreateFactoryFuncName;
     55     sp<SharedLibrary> mLibrary;
     56     KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
     57     KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
     58 
     59     bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
     60                                       sp<SharedLibrary>* library, T** factory);
     61 
     62     bool queryPluginsFromPath(const String8& path, vector<HidlCasPluginDescriptor>* results);
     63 
     64     bool openFactory(const String8& path);
     65     void closeFactory();
     66 };
     67 
     68 template <class T>
     69 bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library,
     70                                             T** factory) {
     71     if (library != NULL) {
     72         library->clear();
     73     }
     74     if (factory != NULL) {
     75         *factory = NULL;
     76     }
     77 
     78     Mutex::Autolock autoLock(mMapLock);
     79 
     80     // first check cache
     81     ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
     82     if (index >= 0) {
     83         return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
     84                                             library, factory);
     85     }
     86 
     87     // no luck, have to search
     88     String8 dirPath("/vendor/lib/mediacas");
     89     DIR* pDir = opendir(dirPath.string());
     90 
     91     if (pDir == NULL) {
     92         ALOGE("Failed to open plugin directory %s", dirPath.string());
     93         return false;
     94     }
     95 
     96     struct dirent* pEntry;
     97     while ((pEntry = readdir(pDir))) {
     98         String8 pluginPath = dirPath + "/" + pEntry->d_name;
     99         if (pluginPath.getPathExtension() == ".so") {
    100             if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
    101                 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
    102                 closedir(pDir);
    103 
    104                 return true;
    105             }
    106         }
    107     }
    108 
    109     closedir(pDir);
    110 
    111     ALOGE("Failed to find plugin");
    112     return false;
    113 }
    114 
    115 template <class T>
    116 bool FactoryLoader<T>::enumeratePlugins(vector<HidlCasPluginDescriptor>* results) {
    117     ALOGI("enumeratePlugins");
    118 
    119     results->clear();
    120 
    121     String8 dirPath("/vendor/lib/mediacas");
    122     DIR* pDir = opendir(dirPath.string());
    123 
    124     if (pDir == NULL) {
    125         ALOGE("Failed to open plugin directory %s", dirPath.string());
    126         return false;
    127     }
    128 
    129     Mutex::Autolock autoLock(mMapLock);
    130 
    131     struct dirent* pEntry;
    132     while ((pEntry = readdir(pDir))) {
    133         String8 pluginPath = dirPath + "/" + pEntry->d_name;
    134         if (pluginPath.getPathExtension() == ".so") {
    135             queryPluginsFromPath(pluginPath, results);
    136         }
    137     }
    138     return true;
    139 }
    140 
    141 template <class T>
    142 bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
    143                                                     sp<SharedLibrary>* library, T** factory) {
    144     closeFactory();
    145 
    146     if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
    147         closeFactory();
    148         return false;
    149     }
    150 
    151     if (library != NULL) {
    152         *library = mLibrary;
    153     }
    154     if (factory != NULL) {
    155         *factory = mFactory;
    156     }
    157     return true;
    158 }
    159 
    160 template <class T>
    161 bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
    162                                             vector<HidlCasPluginDescriptor>* results) {
    163     closeFactory();
    164 
    165     vector<CasPluginDescriptor> descriptors;
    166     if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
    167         closeFactory();
    168         return false;
    169     }
    170 
    171     for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
    172         results->push_back(
    173                 HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
    174     }
    175     return true;
    176 }
    177 
    178 template <class T>
    179 bool FactoryLoader<T>::openFactory(const String8& path) {
    180     // get strong pointer to open shared library
    181     ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
    182     if (index >= 0) {
    183         mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
    184     } else {
    185         index = mLibraryPathToOpenLibraryMap.add(path, NULL);
    186     }
    187 
    188     if (!mLibrary.get()) {
    189         mLibrary = new SharedLibrary(path);
    190         if (!*mLibrary) {
    191             return false;
    192         }
    193 
    194         mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
    195     }
    196 
    197     CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
    198     if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
    199         return false;
    200     }
    201     return true;
    202 }
    203 
    204 template <class T>
    205 void FactoryLoader<T>::closeFactory() {
    206     delete mFactory;
    207     mFactory = NULL;
    208     mLibrary.clear();
    209 }
    210 
    211 }  // namespace implementation
    212 }  // namespace V1_1
    213 }  // namespace cas
    214 }  // namespace hardware
    215 }  // namespace android
    216 
    217 #endif  // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
    218