Home | History | Annotate | Download | only in mediadrm
      1 /*
      2  * Copyright (C) 2017 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 MEDIA_CAS_LOADER_H_
     18 #define MEDIA_CAS_LOADER_H_
     19 
     20 #include <dirent.h>
     21 #include <dlfcn.h>
     22 #include <media/SharedLibrary.h>
     23 #include <utils/KeyedVector.h>
     24 #include <utils/Mutex.h>
     25 
     26 namespace android {
     27 using namespace std;
     28 using namespace media;
     29 using namespace MediaCas;
     30 
     31 template <class T>
     32 class FactoryLoader {
     33 public:
     34     FactoryLoader(const char *name) :
     35         mFactory(NULL), mCreateFactoryFuncName(name) {}
     36 
     37     virtual ~FactoryLoader() { closeFactory(); }
     38 
     39     bool findFactoryForScheme(
     40             int32_t CA_system_id,
     41             sp<SharedLibrary> *library = NULL,
     42             T** factory = NULL);
     43 
     44     bool enumeratePlugins(vector<ParcelableCasPluginDescriptor>* results);
     45 
     46 private:
     47     typedef T*(*CreateFactoryFunc)();
     48 
     49     Mutex mMapLock;
     50     T* mFactory;
     51     const char *mCreateFactoryFuncName;
     52     sp<SharedLibrary> mLibrary;
     53     KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
     54     KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
     55 
     56     bool loadFactoryForSchemeFromPath(
     57             const String8 &path,
     58             int32_t CA_system_id,
     59             sp<SharedLibrary> *library,
     60             T** factory);
     61 
     62     bool queryPluginsFromPath(
     63             const String8 &path,
     64             vector<ParcelableCasPluginDescriptor>* results);
     65 
     66     bool openFactory(const String8 &path);
     67     void closeFactory();
     68 };
     69 
     70 template <class T>
     71 bool FactoryLoader<T>::findFactoryForScheme(
     72         int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) {
     73     if (library != NULL) {
     74         library->clear();
     75     }
     76     if (factory != NULL) {
     77         *factory = NULL;
     78     }
     79 
     80     Mutex::Autolock autoLock(mMapLock);
     81 
     82     // first check cache
     83     ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
     84     if (index >= 0) {
     85         return loadFactoryForSchemeFromPath(
     86                 mCASystemIdToLibraryPathMap[index],
     87                 CA_system_id, library, factory);
     88     }
     89 
     90     // no luck, have to search
     91     String8 dirPath("/system/lib/mediacas");
     92     DIR* pDir = opendir(dirPath.string());
     93 
     94     if (pDir == NULL) {
     95         ALOGE("Failed to open plugin directory %s", dirPath.string());
     96         return false;
     97     }
     98 
     99     struct dirent* pEntry;
    100     while ((pEntry = readdir(pDir))) {
    101         String8 pluginPath = dirPath + "/" + pEntry->d_name;
    102         if (pluginPath.getPathExtension() == ".so") {
    103             if (loadFactoryForSchemeFromPath(
    104                     pluginPath, CA_system_id, library, factory)) {
    105                 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
    106                 closedir(pDir);
    107 
    108                 return true;
    109             }
    110         }
    111     }
    112 
    113     closedir(pDir);
    114 
    115     ALOGE("Failed to find plugin");
    116     return false;
    117 }
    118 
    119 template <class T>
    120 bool FactoryLoader<T>::enumeratePlugins(
    121         vector<ParcelableCasPluginDescriptor>* results) {
    122     ALOGI("enumeratePlugins");
    123 
    124     results->clear();
    125 
    126     String8 dirPath("/system/lib/mediacas");
    127     DIR* pDir = opendir(dirPath.string());
    128 
    129     if (pDir == NULL) {
    130         ALOGE("Failed to open plugin directory %s", dirPath.string());
    131         return false;
    132     }
    133 
    134     Mutex::Autolock autoLock(mMapLock);
    135 
    136     struct dirent* pEntry;
    137     while ((pEntry = readdir(pDir))) {
    138         String8 pluginPath = dirPath + "/" + pEntry->d_name;
    139         if (pluginPath.getPathExtension() == ".so") {
    140             queryPluginsFromPath(pluginPath, results);
    141         }
    142     }
    143     return true;
    144 }
    145 
    146 template <class T>
    147 bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
    148         const String8 &path, int32_t CA_system_id,
    149         sp<SharedLibrary> *library, T** factory) {
    150     closeFactory();
    151 
    152     if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
    153         closeFactory();
    154         return false;
    155     }
    156 
    157     if (library != NULL) {
    158         *library = mLibrary;
    159     }
    160     if (factory != NULL) {
    161         *factory = mFactory;
    162     }
    163     return true;
    164 }
    165 
    166 template <class T>
    167 bool FactoryLoader<T>::queryPluginsFromPath(
    168         const String8 &path, vector<ParcelableCasPluginDescriptor>* results) {
    169     closeFactory();
    170 
    171     vector<CasPluginDescriptor> descriptors;
    172     if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
    173         closeFactory();
    174         return false;
    175     }
    176 
    177     for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
    178         results->push_back(ParcelableCasPluginDescriptor(
    179                 it->CA_system_id, it->name));
    180     }
    181     return true;
    182 }
    183 
    184 template <class T>
    185 bool FactoryLoader<T>::openFactory(const String8 &path) {
    186     // get strong pointer to open shared library
    187     ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
    188     if (index >= 0) {
    189         mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
    190     } else {
    191         index = mLibraryPathToOpenLibraryMap.add(path, NULL);
    192     }
    193 
    194     if (!mLibrary.get()) {
    195         mLibrary = new SharedLibrary(path);
    196         if (!*mLibrary) {
    197             return false;
    198         }
    199 
    200         mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
    201     }
    202 
    203     CreateFactoryFunc createFactory =
    204         (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
    205     if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
    206         return false;
    207     }
    208     return true;
    209 }
    210 
    211 template <class T>
    212 void FactoryLoader<T>::closeFactory() {
    213     delete mFactory;
    214     mFactory = NULL;
    215     mLibrary.clear();
    216 }
    217 
    218 } // namespace android
    219 
    220 #endif // MEDIA_CAS_LOADER_H_
    221