Home | History | Annotate | Download | only in libmediaplayerservice
      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