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