Home | History | Annotate | Download | only in libmediaplayerservice
      1 /*
      2  * Copyright (C) 2013 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 "Drm"
     19 #include <utils/Log.h>
     20 
     21 #include <dirent.h>
     22 #include <dlfcn.h>
     23 
     24 #include "Drm.h"
     25 
     26 #include <media/drm/DrmAPI.h>
     27 #include <media/stagefright/foundation/ADebug.h>
     28 #include <media/stagefright/foundation/AString.h>
     29 #include <media/stagefright/foundation/hexdump.h>
     30 #include <media/stagefright/MediaErrors.h>
     31 
     32 namespace android {
     33 
     34 KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
     35 KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
     36 Mutex Drm::mMapLock;
     37 
     38 static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
     39     if (lhs.size() < rhs.size()) {
     40         return true;
     41     } else if (lhs.size() > rhs.size()) {
     42         return false;
     43     }
     44 
     45     return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
     46 }
     47 
     48 Drm::Drm()
     49     : mInitCheck(NO_INIT),
     50       mListener(NULL),
     51       mFactory(NULL),
     52       mPlugin(NULL) {
     53 }
     54 
     55 Drm::~Drm() {
     56     delete mPlugin;
     57     mPlugin = NULL;
     58     closeFactory();
     59 }
     60 
     61 void Drm::closeFactory() {
     62     delete mFactory;
     63     mFactory = NULL;
     64     mLibrary.clear();
     65 }
     66 
     67 status_t Drm::initCheck() const {
     68     return mInitCheck;
     69 }
     70 
     71 status_t Drm::setListener(const sp<IDrmClient>& listener)
     72 {
     73     Mutex::Autolock lock(mEventLock);
     74     if (mListener != NULL){
     75         mListener->asBinder()->unlinkToDeath(this);
     76     }
     77     if (listener != NULL) {
     78         listener->asBinder()->linkToDeath(this);
     79     }
     80     mListener = listener;
     81     return NO_ERROR;
     82 }
     83 
     84 void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
     85                     Vector<uint8_t> const *sessionId,
     86                     Vector<uint8_t> const *data)
     87 {
     88     mEventLock.lock();
     89     sp<IDrmClient> listener = mListener;
     90     mEventLock.unlock();
     91 
     92     if (listener != NULL) {
     93         Parcel obj;
     94         if (sessionId && sessionId->size()) {
     95             obj.writeInt32(sessionId->size());
     96             obj.write(sessionId->array(), sessionId->size());
     97         } else {
     98             obj.writeInt32(0);
     99         }
    100 
    101         if (data && data->size()) {
    102             obj.writeInt32(data->size());
    103             obj.write(data->array(), data->size());
    104         } else {
    105             obj.writeInt32(0);
    106         }
    107 
    108         Mutex::Autolock lock(mNotifyLock);
    109         listener->notify(eventType, extra, &obj);
    110     }
    111 }
    112 
    113 /*
    114  * Search the plugins directory for a plugin that supports the scheme
    115  * specified by uuid
    116  *
    117  * If found:
    118  *    mLibrary holds a strong pointer to the dlopen'd library
    119  *    mFactory is set to the library's factory method
    120  *    mInitCheck is set to OK
    121  *
    122  * If not found:
    123  *    mLibrary is cleared and mFactory are set to NULL
    124  *    mInitCheck is set to an error (!OK)
    125  */
    126 void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
    127 
    128     closeFactory();
    129 
    130     // lock static maps
    131     Mutex::Autolock autoLock(mMapLock);
    132 
    133     // first check cache
    134     Vector<uint8_t> uuidVector;
    135     uuidVector.appendArray(uuid, sizeof(uuid));
    136     ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
    137     if (index >= 0) {
    138         if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
    139             mInitCheck = OK;
    140             return;
    141         } else {
    142             ALOGE("Failed to load from cached library path!");
    143             mInitCheck = ERROR_UNSUPPORTED;
    144             return;
    145         }
    146     }
    147 
    148     // no luck, have to search
    149     String8 dirPath("/vendor/lib/mediadrm");
    150     DIR* pDir = opendir(dirPath.string());
    151 
    152     if (pDir == NULL) {
    153         mInitCheck = ERROR_UNSUPPORTED;
    154         ALOGE("Failed to open plugin directory %s", dirPath.string());
    155         return;
    156     }
    157 
    158 
    159     struct dirent* pEntry;
    160     while ((pEntry = readdir(pDir))) {
    161 
    162         String8 pluginPath = dirPath + "/" + pEntry->d_name;
    163 
    164         if (pluginPath.getPathExtension() == ".so") {
    165 
    166             if (loadLibraryForScheme(pluginPath, uuid)) {
    167                 mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
    168                 mInitCheck = OK;
    169                 closedir(pDir);
    170                 return;
    171             }
    172         }
    173     }
    174 
    175     closedir(pDir);
    176 
    177     ALOGE("Failed to find drm plugin");
    178     mInitCheck = ERROR_UNSUPPORTED;
    179 }
    180 
    181 bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
    182 
    183     // get strong pointer to open shared library
    184     ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
    185     if (index >= 0) {
    186         mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
    187     } else {
    188         index = mLibraryPathToOpenLibraryMap.add(path, NULL);
    189     }
    190 
    191     if (!mLibrary.get()) {
    192         mLibrary = new SharedLibrary(path);
    193         if (!*mLibrary) {
    194             return false;
    195         }
    196 
    197         mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
    198     }
    199 
    200     typedef DrmFactory *(*CreateDrmFactoryFunc)();
    201 
    202     CreateDrmFactoryFunc createDrmFactory =
    203         (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
    204 
    205     if (createDrmFactory == NULL ||
    206         (mFactory = createDrmFactory()) == NULL ||
    207         !mFactory->isCryptoSchemeSupported(uuid)) {
    208         closeFactory();
    209         return false;
    210     }
    211     return true;
    212 }
    213 
    214 bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
    215 
    216     Mutex::Autolock autoLock(mLock);
    217 
    218     if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
    219         findFactoryForScheme(uuid);
    220         if (mInitCheck != OK) {
    221             return false;
    222         }
    223     }
    224 
    225     if (mimeType != "") {
    226         return mFactory->isContentTypeSupported(mimeType);
    227     }
    228 
    229     return true;
    230 }
    231 
    232 status_t Drm::createPlugin(const uint8_t uuid[16]) {
    233     Mutex::Autolock autoLock(mLock);
    234 
    235     if (mPlugin != NULL) {
    236         return -EINVAL;
    237     }
    238 
    239     if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
    240         findFactoryForScheme(uuid);
    241     }
    242 
    243     if (mInitCheck != OK) {
    244         return mInitCheck;
    245     }
    246 
    247     status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
    248     mPlugin->setListener(this);
    249     return result;
    250 }
    251 
    252 status_t Drm::destroyPlugin() {
    253     Mutex::Autolock autoLock(mLock);
    254 
    255     if (mInitCheck != OK) {
    256         return mInitCheck;
    257     }
    258 
    259     if (mPlugin == NULL) {
    260         return -EINVAL;
    261     }
    262 
    263     delete mPlugin;
    264     mPlugin = NULL;
    265 
    266     return OK;
    267 }
    268 
    269 status_t Drm::openSession(Vector<uint8_t> &sessionId) {
    270     Mutex::Autolock autoLock(mLock);
    271 
    272     if (mInitCheck != OK) {
    273         return mInitCheck;
    274     }
    275 
    276     if (mPlugin == NULL) {
    277         return -EINVAL;
    278     }
    279 
    280     return mPlugin->openSession(sessionId);
    281 }
    282 
    283 status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
    284     Mutex::Autolock autoLock(mLock);
    285 
    286     if (mInitCheck != OK) {
    287         return mInitCheck;
    288     }
    289 
    290     if (mPlugin == NULL) {
    291         return -EINVAL;
    292     }
    293 
    294     return mPlugin->closeSession(sessionId);
    295 }
    296 
    297 status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
    298                             Vector<uint8_t> const &initData,
    299                             String8 const &mimeType, DrmPlugin::KeyType keyType,
    300                             KeyedVector<String8, String8> const &optionalParameters,
    301                             Vector<uint8_t> &request, String8 &defaultUrl) {
    302     Mutex::Autolock autoLock(mLock);
    303 
    304     if (mInitCheck != OK) {
    305         return mInitCheck;
    306     }
    307 
    308     if (mPlugin == NULL) {
    309         return -EINVAL;
    310     }
    311 
    312     return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
    313                                   optionalParameters, request, defaultUrl);
    314 }
    315 
    316 status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
    317                                  Vector<uint8_t> const &response,
    318                                  Vector<uint8_t> &keySetId) {
    319     Mutex::Autolock autoLock(mLock);
    320 
    321     if (mInitCheck != OK) {
    322         return mInitCheck;
    323     }
    324 
    325     if (mPlugin == NULL) {
    326         return -EINVAL;
    327     }
    328 
    329     return mPlugin->provideKeyResponse(sessionId, response, keySetId);
    330 }
    331 
    332 status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
    333     Mutex::Autolock autoLock(mLock);
    334 
    335     if (mInitCheck != OK) {
    336         return mInitCheck;
    337     }
    338 
    339     if (mPlugin == NULL) {
    340         return -EINVAL;
    341     }
    342 
    343     return mPlugin->removeKeys(keySetId);
    344 }
    345 
    346 status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
    347                           Vector<uint8_t> const &keySetId) {
    348     Mutex::Autolock autoLock(mLock);
    349 
    350     if (mInitCheck != OK) {
    351         return mInitCheck;
    352     }
    353 
    354     if (mPlugin == NULL) {
    355         return -EINVAL;
    356     }
    357 
    358     return mPlugin->restoreKeys(sessionId, keySetId);
    359 }
    360 
    361 status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
    362                              KeyedVector<String8, String8> &infoMap) const {
    363     Mutex::Autolock autoLock(mLock);
    364 
    365     if (mInitCheck != OK) {
    366         return mInitCheck;
    367     }
    368 
    369     if (mPlugin == NULL) {
    370         return -EINVAL;
    371     }
    372 
    373     return mPlugin->queryKeyStatus(sessionId, infoMap);
    374 }
    375 
    376 status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
    377     Mutex::Autolock autoLock(mLock);
    378 
    379     if (mInitCheck != OK) {
    380         return mInitCheck;
    381     }
    382 
    383     if (mPlugin == NULL) {
    384         return -EINVAL;
    385     }
    386 
    387     return mPlugin->getProvisionRequest(request, defaultUrl);
    388 }
    389 
    390 status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
    391     Mutex::Autolock autoLock(mLock);
    392 
    393     if (mInitCheck != OK) {
    394         return mInitCheck;
    395     }
    396 
    397     if (mPlugin == NULL) {
    398         return -EINVAL;
    399     }
    400 
    401     return mPlugin->provideProvisionResponse(response);
    402 }
    403 
    404 
    405 status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
    406     Mutex::Autolock autoLock(mLock);
    407 
    408     if (mInitCheck != OK) {
    409         return mInitCheck;
    410     }
    411 
    412     if (mPlugin == NULL) {
    413         return -EINVAL;
    414     }
    415 
    416     return mPlugin->getSecureStops(secureStops);
    417 }
    418 
    419 status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
    420     Mutex::Autolock autoLock(mLock);
    421 
    422     if (mInitCheck != OK) {
    423         return mInitCheck;
    424     }
    425 
    426     if (mPlugin == NULL) {
    427         return -EINVAL;
    428     }
    429 
    430     return mPlugin->releaseSecureStops(ssRelease);
    431 }
    432 
    433 status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
    434     Mutex::Autolock autoLock(mLock);
    435 
    436     if (mInitCheck != OK) {
    437         return mInitCheck;
    438     }
    439 
    440     if (mPlugin == NULL) {
    441         return -EINVAL;
    442     }
    443 
    444     return mPlugin->getPropertyString(name, value);
    445 }
    446 
    447 status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
    448     Mutex::Autolock autoLock(mLock);
    449 
    450     if (mInitCheck != OK) {
    451         return mInitCheck;
    452     }
    453 
    454     if (mPlugin == NULL) {
    455         return -EINVAL;
    456     }
    457 
    458     return mPlugin->getPropertyByteArray(name, value);
    459 }
    460 
    461 status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
    462     Mutex::Autolock autoLock(mLock);
    463 
    464     if (mInitCheck != OK) {
    465         return mInitCheck;
    466     }
    467 
    468     if (mPlugin == NULL) {
    469         return -EINVAL;
    470     }
    471 
    472     return mPlugin->setPropertyString(name, value);
    473 }
    474 
    475 status_t Drm::setPropertyByteArray(String8 const &name,
    476                                    Vector<uint8_t> const &value ) const {
    477     Mutex::Autolock autoLock(mLock);
    478 
    479     if (mInitCheck != OK) {
    480         return mInitCheck;
    481     }
    482 
    483     if (mPlugin == NULL) {
    484         return -EINVAL;
    485     }
    486 
    487     return mPlugin->setPropertyByteArray(name, value);
    488 }
    489 
    490 
    491 status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
    492                                  String8 const &algorithm) {
    493     Mutex::Autolock autoLock(mLock);
    494 
    495     if (mInitCheck != OK) {
    496         return mInitCheck;
    497     }
    498 
    499     if (mPlugin == NULL) {
    500         return -EINVAL;
    501     }
    502 
    503     return mPlugin->setCipherAlgorithm(sessionId, algorithm);
    504 }
    505 
    506 status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
    507                               String8 const &algorithm) {
    508     Mutex::Autolock autoLock(mLock);
    509 
    510     if (mInitCheck != OK) {
    511         return mInitCheck;
    512     }
    513 
    514     if (mPlugin == NULL) {
    515         return -EINVAL;
    516     }
    517 
    518     return mPlugin->setMacAlgorithm(sessionId, algorithm);
    519 }
    520 
    521 status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
    522                       Vector<uint8_t> const &keyId,
    523                       Vector<uint8_t> const &input,
    524                       Vector<uint8_t> const &iv,
    525                       Vector<uint8_t> &output) {
    526     Mutex::Autolock autoLock(mLock);
    527 
    528     if (mInitCheck != OK) {
    529         return mInitCheck;
    530     }
    531 
    532     if (mPlugin == NULL) {
    533         return -EINVAL;
    534     }
    535 
    536     return mPlugin->encrypt(sessionId, keyId, input, iv, output);
    537 }
    538 
    539 status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
    540                       Vector<uint8_t> const &keyId,
    541                       Vector<uint8_t> const &input,
    542                       Vector<uint8_t> const &iv,
    543                       Vector<uint8_t> &output) {
    544     Mutex::Autolock autoLock(mLock);
    545 
    546     if (mInitCheck != OK) {
    547         return mInitCheck;
    548     }
    549 
    550     if (mPlugin == NULL) {
    551         return -EINVAL;
    552     }
    553 
    554     return mPlugin->decrypt(sessionId, keyId, input, iv, output);
    555 }
    556 
    557 status_t Drm::sign(Vector<uint8_t> const &sessionId,
    558                    Vector<uint8_t> const &keyId,
    559                    Vector<uint8_t> const &message,
    560                    Vector<uint8_t> &signature) {
    561     Mutex::Autolock autoLock(mLock);
    562 
    563     if (mInitCheck != OK) {
    564         return mInitCheck;
    565     }
    566 
    567     if (mPlugin == NULL) {
    568         return -EINVAL;
    569     }
    570 
    571     return mPlugin->sign(sessionId, keyId, message, signature);
    572 }
    573 
    574 status_t Drm::verify(Vector<uint8_t> const &sessionId,
    575                      Vector<uint8_t> const &keyId,
    576                      Vector<uint8_t> const &message,
    577                      Vector<uint8_t> const &signature,
    578                      bool &match) {
    579     Mutex::Autolock autoLock(mLock);
    580 
    581     if (mInitCheck != OK) {
    582         return mInitCheck;
    583     }
    584 
    585     if (mPlugin == NULL) {
    586         return -EINVAL;
    587     }
    588 
    589     return mPlugin->verify(sessionId, keyId, message, signature, match);
    590 }
    591 
    592 void Drm::binderDied(const wp<IBinder> &the_late_who)
    593 {
    594     delete mPlugin;
    595     mPlugin = NULL;
    596     closeFactory();
    597     mListener.clear();
    598 }
    599 
    600 }  // namespace android
    601