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     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         bool secure,
    238         const uint8_t key[16],
    239         const uint8_t iv[16],
    240         CryptoPlugin::Mode mode,
    241         const void *srcPtr,
    242         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
    243         void *dstPtr,
    244         AString *errorDetailMsg) {
    245     Mutex::Autolock autoLock(mLock);
    246 
    247     if (mInitCheck != OK) {
    248         return mInitCheck;
    249     }
    250 
    251     if (mPlugin == NULL) {
    252         return -EINVAL;
    253     }
    254 
    255     return mPlugin->decrypt(
    256             secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr,
    257             errorDetailMsg);
    258 }
    259 
    260 void Crypto::notifyResolution(uint32_t width, uint32_t height) {
    261     Mutex::Autolock autoLock(mLock);
    262 
    263     if (mInitCheck == OK && mPlugin != NULL) {
    264         mPlugin->notifyResolution(width, height);
    265     }
    266 }
    267 
    268 }  // namespace android
    269