1 /* 2 * Copyright (C) 2012 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 //#define LOG_NDEBUG 0 18 #define LOG_TAG "Crypto" 19 #include <utils/Log.h> 20 #include <dirent.h> 21 #include <dlfcn.h> 22 23 #include "Crypto.h" 24 25 #include <media/hardware/CryptoAPI.h> 26 #include <media/stagefright/foundation/ADebug.h> 27 #include <media/stagefright/foundation/AString.h> 28 #include <media/stagefright/foundation/hexdump.h> 29 #include <media/stagefright/MediaErrors.h> 30 31 namespace android { 32 33 KeyedVector<Vector<uint8_t>, String8> Crypto::mUUIDToLibraryPathMap; 34 KeyedVector<String8, wp<SharedLibrary> > Crypto::mLibraryPathToOpenLibraryMap; 35 Mutex Crypto::mMapLock; 36 37 static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) { 38 if (lhs.size() < rhs.size()) { 39 return true; 40 } else if (lhs.size() > rhs.size()) { 41 return false; 42 } 43 44 return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0; 45 } 46 47 Crypto::Crypto() 48 : mInitCheck(NO_INIT), 49 mFactory(NULL), 50 mPlugin(NULL) { 51 } 52 53 Crypto::~Crypto() { 54 delete mPlugin; 55 mPlugin = NULL; 56 closeFactory(); 57 } 58 59 void Crypto::closeFactory() { 60 delete mFactory; 61 mFactory = NULL; 62 mLibrary.clear(); 63 } 64 65 status_t Crypto::initCheck() const { 66 return mInitCheck; 67 } 68 69 /* 70 * Search the plugins directory for a plugin that supports the scheme 71 * specified by uuid 72 * 73 * If found: 74 * mLibrary holds a strong pointer to the dlopen'd library 75 * mFactory is set to the library's factory method 76 * mInitCheck is set to OK 77 * 78 * If not found: 79 * mLibrary is cleared and mFactory are set to NULL 80 * mInitCheck is set to an error (!OK) 81 */ 82 void Crypto::findFactoryForScheme(const uint8_t uuid[16]) { 83 84 closeFactory(); 85 86 // lock static maps 87 Mutex::Autolock autoLock(mMapLock); 88 89 // first check cache 90 Vector<uint8_t> uuidVector; 91 uuidVector.appendArray(uuid, sizeof(uuid)); 92 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector); 93 if (index >= 0) { 94 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) { 95 mInitCheck = OK; 96 return; 97 } else { 98 ALOGE("Failed to load from cached library path!"); 99 mInitCheck = ERROR_UNSUPPORTED; 100 return; 101 } 102 } 103 104 // no luck, have to search 105 String8 dirPath("/vendor/lib/mediadrm"); 106 String8 pluginPath; 107 108 DIR* pDir = opendir(dirPath.string()); 109 if (pDir) { 110 struct dirent* pEntry; 111 while ((pEntry = readdir(pDir))) { 112 113 pluginPath = dirPath + "/" + pEntry->d_name; 114 115 if (pluginPath.getPathExtension() == ".so") { 116 117 if (loadLibraryForScheme(pluginPath, uuid)) { 118 mUUIDToLibraryPathMap.add(uuidVector, pluginPath); 119 mInitCheck = OK; 120 closedir(pDir); 121 return; 122 } 123 } 124 } 125 126 closedir(pDir); 127 } 128 129 // try the legacy libdrmdecrypt.so 130 pluginPath = "libdrmdecrypt.so"; 131 if (loadLibraryForScheme(pluginPath, uuid)) { 132 mUUIDToLibraryPathMap.add(uuidVector, pluginPath); 133 mInitCheck = OK; 134 return; 135 } 136 137 ALOGE("Failed to find crypto plugin"); 138 mInitCheck = ERROR_UNSUPPORTED; 139 } 140 141 bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { 142 143 // get strong pointer to open shared library 144 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); 145 if (index >= 0) { 146 mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); 147 } else { 148 index = mLibraryPathToOpenLibraryMap.add(path, NULL); 149 } 150 151 if (!mLibrary.get()) { 152 mLibrary = new SharedLibrary(path); 153 if (!*mLibrary) { 154 return false; 155 } 156 157 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); 158 } 159 160 typedef CryptoFactory *(*CreateCryptoFactoryFunc)(); 161 162 CreateCryptoFactoryFunc createCryptoFactory = 163 (CreateCryptoFactoryFunc)mLibrary->lookup("createCryptoFactory"); 164 165 if (createCryptoFactory == NULL || 166 (mFactory = createCryptoFactory()) == NULL || 167 !mFactory->isCryptoSchemeSupported(uuid)) { 168 closeFactory(); 169 return false; 170 } 171 return true; 172 } 173 174 bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) { 175 Mutex::Autolock autoLock(mLock); 176 177 if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) { 178 return true; 179 } 180 181 findFactoryForScheme(uuid); 182 return (mInitCheck == OK); 183 } 184 185 status_t Crypto::createPlugin( 186 const uint8_t uuid[16], const void *data, size_t size) { 187 Mutex::Autolock autoLock(mLock); 188 189 if (mPlugin != NULL) { 190 return -EINVAL; 191 } 192 193 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 194 findFactoryForScheme(uuid); 195 } 196 197 if (mInitCheck != OK) { 198 return mInitCheck; 199 } 200 201 return mFactory->createPlugin(uuid, data, size, &mPlugin); 202 } 203 204 status_t Crypto::destroyPlugin() { 205 Mutex::Autolock autoLock(mLock); 206 207 if (mInitCheck != OK) { 208 return mInitCheck; 209 } 210 211 if (mPlugin == NULL) { 212 return -EINVAL; 213 } 214 215 delete mPlugin; 216 mPlugin = NULL; 217 218 return OK; 219 } 220 221 bool Crypto::requiresSecureDecoderComponent(const char *mime) const { 222 Mutex::Autolock autoLock(mLock); 223 224 if (mInitCheck != OK) { 225 return mInitCheck; 226 } 227 228 if (mPlugin == NULL) { 229 return -EINVAL; 230 } 231 232 return mPlugin->requiresSecureDecoderComponent(mime); 233 } 234 235 ssize_t Crypto::decrypt( 236 bool secure, 237 const uint8_t key[16], 238 const uint8_t iv[16], 239 CryptoPlugin::Mode mode, 240 const void *srcPtr, 241 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, 242 void *dstPtr, 243 AString *errorDetailMsg) { 244 Mutex::Autolock autoLock(mLock); 245 246 if (mInitCheck != OK) { 247 return mInitCheck; 248 } 249 250 if (mPlugin == NULL) { 251 return -EINVAL; 252 } 253 254 return mPlugin->decrypt( 255 secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr, 256 errorDetailMsg); 257 } 258 259 } // namespace android 260