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 <binder/IMemory.h> 24 #include <media/Crypto.h> 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[0]) * 16); 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 mInitCheck = ERROR_UNSUPPORTED; 138 } 139 140 bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { 141 142 // get strong pointer to open shared library 143 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); 144 if (index >= 0) { 145 mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); 146 } else { 147 index = mLibraryPathToOpenLibraryMap.add(path, NULL); 148 } 149 150 if (!mLibrary.get()) { 151 mLibrary = new SharedLibrary(path); 152 if (!*mLibrary) { 153 ALOGE("loadLibraryForScheme failed:%s", mLibrary->lastError()); 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 ALOGE("createCryptoFactory failed:%s", mLibrary->lastError()); 169 closeFactory(); 170 return false; 171 } 172 return true; 173 } 174 175 bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) { 176 Mutex::Autolock autoLock(mLock); 177 178 if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) { 179 return true; 180 } 181 182 findFactoryForScheme(uuid); 183 return (mInitCheck == OK); 184 } 185 186 status_t Crypto::createPlugin( 187 const uint8_t uuid[16], const void *data, size_t size) { 188 Mutex::Autolock autoLock(mLock); 189 190 if (mPlugin != NULL) { 191 return -EINVAL; 192 } 193 194 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 195 findFactoryForScheme(uuid); 196 } 197 198 if (mInitCheck != OK) { 199 return mInitCheck; 200 } 201 202 return mFactory->createPlugin(uuid, data, size, &mPlugin); 203 } 204 205 status_t Crypto::destroyPlugin() { 206 Mutex::Autolock autoLock(mLock); 207 208 if (mInitCheck != OK) { 209 return mInitCheck; 210 } 211 212 if (mPlugin == NULL) { 213 return -EINVAL; 214 } 215 216 delete mPlugin; 217 mPlugin = NULL; 218 219 return OK; 220 } 221 222 bool Crypto::requiresSecureDecoderComponent(const char *mime) const { 223 Mutex::Autolock autoLock(mLock); 224 225 if (mInitCheck != OK) { 226 return mInitCheck; 227 } 228 229 if (mPlugin == NULL) { 230 return -EINVAL; 231 } 232 233 return mPlugin->requiresSecureDecoderComponent(mime); 234 } 235 236 ssize_t Crypto::decrypt( 237 DestinationType dstType, 238 const uint8_t key[16], 239 const uint8_t iv[16], 240 CryptoPlugin::Mode mode, 241 const CryptoPlugin::Pattern &pattern, 242 const sp<IMemory> &sharedBuffer, size_t offset, 243 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, 244 void *dstPtr, 245 AString *errorDetailMsg) { 246 Mutex::Autolock autoLock(mLock); 247 248 if (mInitCheck != OK) { 249 return mInitCheck; 250 } 251 252 if (mPlugin == NULL) { 253 return -EINVAL; 254 } 255 256 const void *srcPtr = static_cast<uint8_t *>(sharedBuffer->pointer()) + offset; 257 258 return mPlugin->decrypt( 259 dstType != kDestinationTypeVmPointer, 260 key, iv, mode, pattern, srcPtr, subSamples, numSubSamples, dstPtr, 261 errorDetailMsg); 262 } 263 264 void Crypto::notifyResolution(uint32_t width, uint32_t height) { 265 Mutex::Autolock autoLock(mLock); 266 267 if (mInitCheck == OK && mPlugin != NULL) { 268 mPlugin->notifyResolution(width, height); 269 } 270 } 271 272 status_t Crypto::setMediaDrmSession(const Vector<uint8_t> &sessionId) { 273 Mutex::Autolock autoLock(mLock); 274 275 status_t result = NO_INIT; 276 if (mInitCheck == OK && mPlugin != NULL) { 277 result = mPlugin->setMediaDrmSession(sessionId); 278 } 279 return result; 280 } 281 282 } // namespace android 283