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 "DrmSessionClientInterface.h"
27#include "DrmSessionManager.h"
28#include <media/drm/DrmAPI.h>
29#include <media/stagefright/foundation/ADebug.h>
30#include <media/stagefright/foundation/AString.h>
31#include <media/stagefright/foundation/hexdump.h>
32#include <media/stagefright/MediaErrors.h>
33#include <binder/IServiceManager.h>
34#include <binder/IPCThreadState.h>
35
36namespace android {
37
38static inline int getCallingPid() {
39    return IPCThreadState::self()->getCallingPid();
40}
41
42static bool checkPermission(const char* permissionString) {
43#ifndef HAVE_ANDROID_OS
44    return true;
45#endif
46    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
47    bool ok = checkCallingPermission(String16(permissionString));
48    if (!ok) ALOGE("Request requires %s", permissionString);
49    return ok;
50}
51
52KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
53KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
54Mutex Drm::mMapLock;
55Mutex Drm::mLock;
56
57static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
58    if (lhs.size() < rhs.size()) {
59        return true;
60    } else if (lhs.size() > rhs.size()) {
61        return false;
62    }
63
64    return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
65}
66
67struct DrmSessionClient : public DrmSessionClientInterface {
68    DrmSessionClient(Drm* drm) : mDrm(drm) {}
69
70    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
71        sp<Drm> drm = mDrm.promote();
72        if (drm == NULL) {
73            return true;
74        }
75        status_t err = drm->closeSession(sessionId);
76        if (err != OK) {
77            return false;
78        }
79        drm->sendEvent(DrmPlugin::kDrmPluginEventSessionReclaimed, 0, &sessionId, NULL);
80        return true;
81    }
82
83protected:
84    virtual ~DrmSessionClient() {}
85
86private:
87    wp<Drm> mDrm;
88
89    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
90};
91
92Drm::Drm()
93    : mInitCheck(NO_INIT),
94      mDrmSessionClient(new DrmSessionClient(this)),
95      mListener(NULL),
96      mFactory(NULL),
97      mPlugin(NULL) {
98}
99
100Drm::~Drm() {
101    DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
102    delete mPlugin;
103    mPlugin = NULL;
104    closeFactory();
105}
106
107void Drm::closeFactory() {
108    delete mFactory;
109    mFactory = NULL;
110    mLibrary.clear();
111}
112
113status_t Drm::initCheck() const {
114    return mInitCheck;
115}
116
117status_t Drm::setListener(const sp<IDrmClient>& listener)
118{
119    Mutex::Autolock lock(mEventLock);
120    if (mListener != NULL){
121        IInterface::asBinder(mListener)->unlinkToDeath(this);
122    }
123    if (listener != NULL) {
124        IInterface::asBinder(listener)->linkToDeath(this);
125    }
126    mListener = listener;
127    return NO_ERROR;
128}
129
130void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
131                    Vector<uint8_t> const *sessionId,
132                    Vector<uint8_t> const *data)
133{
134    mEventLock.lock();
135    sp<IDrmClient> listener = mListener;
136    mEventLock.unlock();
137
138    if (listener != NULL) {
139        Parcel obj;
140        writeByteArray(obj, sessionId);
141        writeByteArray(obj, data);
142
143        Mutex::Autolock lock(mNotifyLock);
144        listener->notify(eventType, extra, &obj);
145    }
146}
147
148void Drm::sendExpirationUpdate(Vector<uint8_t> const *sessionId,
149                               int64_t expiryTimeInMS)
150{
151    mEventLock.lock();
152    sp<IDrmClient> listener = mListener;
153    mEventLock.unlock();
154
155    if (listener != NULL) {
156        Parcel obj;
157        writeByteArray(obj, sessionId);
158        obj.writeInt64(expiryTimeInMS);
159
160        Mutex::Autolock lock(mNotifyLock);
161        listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
162    }
163}
164
165void Drm::sendKeysChange(Vector<uint8_t> const *sessionId,
166                         Vector<DrmPlugin::KeyStatus> const *keyStatusList,
167                         bool hasNewUsableKey)
168{
169    mEventLock.lock();
170    sp<IDrmClient> listener = mListener;
171    mEventLock.unlock();
172
173    if (listener != NULL) {
174        Parcel obj;
175        writeByteArray(obj, sessionId);
176
177        size_t nkeys = keyStatusList->size();
178        obj.writeInt32(keyStatusList->size());
179        for (size_t i = 0; i < nkeys; ++i) {
180            const DrmPlugin::KeyStatus *keyStatus = &keyStatusList->itemAt(i);
181            writeByteArray(obj, &keyStatus->mKeyId);
182            obj.writeInt32(keyStatus->mType);
183        }
184        obj.writeInt32(hasNewUsableKey);
185
186        Mutex::Autolock lock(mNotifyLock);
187        listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
188    }
189}
190
191/*
192 * Search the plugins directory for a plugin that supports the scheme
193 * specified by uuid
194 *
195 * If found:
196 *    mLibrary holds a strong pointer to the dlopen'd library
197 *    mFactory is set to the library's factory method
198 *    mInitCheck is set to OK
199 *
200 * If not found:
201 *    mLibrary is cleared and mFactory are set to NULL
202 *    mInitCheck is set to an error (!OK)
203 */
204void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
205
206    closeFactory();
207
208    // lock static maps
209    Mutex::Autolock autoLock(mMapLock);
210
211    // first check cache
212    Vector<uint8_t> uuidVector;
213    uuidVector.appendArray(uuid, sizeof(uuid[0]) * 16);
214    ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
215    if (index >= 0) {
216        if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
217            mInitCheck = OK;
218            return;
219        } else {
220            ALOGE("Failed to load from cached library path!");
221            mInitCheck = ERROR_UNSUPPORTED;
222            return;
223        }
224    }
225
226    // no luck, have to search
227    String8 dirPath("/vendor/lib/mediadrm");
228    DIR* pDir = opendir(dirPath.string());
229
230    if (pDir == NULL) {
231        mInitCheck = ERROR_UNSUPPORTED;
232        ALOGE("Failed to open plugin directory %s", dirPath.string());
233        return;
234    }
235
236
237    struct dirent* pEntry;
238    while ((pEntry = readdir(pDir))) {
239
240        String8 pluginPath = dirPath + "/" + pEntry->d_name;
241
242        if (pluginPath.getPathExtension() == ".so") {
243
244            if (loadLibraryForScheme(pluginPath, uuid)) {
245                mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
246                mInitCheck = OK;
247                closedir(pDir);
248                return;
249            }
250        }
251    }
252
253    closedir(pDir);
254
255    ALOGE("Failed to find drm plugin");
256    mInitCheck = ERROR_UNSUPPORTED;
257}
258
259bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
260
261    // get strong pointer to open shared library
262    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
263    if (index >= 0) {
264        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
265    } else {
266        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
267    }
268
269    if (!mLibrary.get()) {
270        mLibrary = new SharedLibrary(path);
271        if (!*mLibrary) {
272            return false;
273        }
274
275        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
276    }
277
278    typedef DrmFactory *(*CreateDrmFactoryFunc)();
279
280    CreateDrmFactoryFunc createDrmFactory =
281        (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
282
283    if (createDrmFactory == NULL ||
284        (mFactory = createDrmFactory()) == NULL ||
285        !mFactory->isCryptoSchemeSupported(uuid)) {
286        closeFactory();
287        return false;
288    }
289    return true;
290}
291
292bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
293
294    Mutex::Autolock autoLock(mLock);
295
296    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
297        findFactoryForScheme(uuid);
298        if (mInitCheck != OK) {
299            return false;
300        }
301    }
302
303    if (mimeType != "") {
304        return mFactory->isContentTypeSupported(mimeType);
305    }
306
307    return true;
308}
309
310status_t Drm::createPlugin(const uint8_t uuid[16]) {
311    Mutex::Autolock autoLock(mLock);
312
313    if (mPlugin != NULL) {
314        return -EINVAL;
315    }
316
317    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
318        findFactoryForScheme(uuid);
319    }
320
321    if (mInitCheck != OK) {
322        return mInitCheck;
323    }
324
325    status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
326    mPlugin->setListener(this);
327    return result;
328}
329
330status_t Drm::destroyPlugin() {
331    Mutex::Autolock autoLock(mLock);
332
333    if (mInitCheck != OK) {
334        return mInitCheck;
335    }
336
337    if (mPlugin == NULL) {
338        return -EINVAL;
339    }
340
341    delete mPlugin;
342    mPlugin = NULL;
343
344    return OK;
345}
346
347status_t Drm::openSession(Vector<uint8_t> &sessionId) {
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    status_t err = mPlugin->openSession(sessionId);
359    if (err == ERROR_DRM_RESOURCE_BUSY) {
360        bool retry = false;
361        mLock.unlock();
362        // reclaimSession may call back to closeSession, since mLock is shared between Drm
363        // instances, we should unlock here to avoid deadlock.
364        retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
365        mLock.lock();
366        if (mInitCheck != OK) {
367            return mInitCheck;
368        }
369
370        if (mPlugin == NULL) {
371            return -EINVAL;
372        }
373        if (retry) {
374            err = mPlugin->openSession(sessionId);
375        }
376    }
377    if (err == OK) {
378        DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId);
379    }
380    return err;
381}
382
383status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
384    Mutex::Autolock autoLock(mLock);
385
386    if (mInitCheck != OK) {
387        return mInitCheck;
388    }
389
390    if (mPlugin == NULL) {
391        return -EINVAL;
392    }
393
394    status_t err = mPlugin->closeSession(sessionId);
395    if (err == OK) {
396        DrmSessionManager::Instance()->removeSession(sessionId);
397    }
398    return err;
399}
400
401status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
402                            Vector<uint8_t> const &initData,
403                            String8 const &mimeType, DrmPlugin::KeyType keyType,
404                            KeyedVector<String8, String8> const &optionalParameters,
405                            Vector<uint8_t> &request, String8 &defaultUrl,
406                            DrmPlugin::KeyRequestType *keyRequestType) {
407    Mutex::Autolock autoLock(mLock);
408
409    if (mInitCheck != OK) {
410        return mInitCheck;
411    }
412
413    if (mPlugin == NULL) {
414        return -EINVAL;
415    }
416
417    DrmSessionManager::Instance()->useSession(sessionId);
418
419    return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
420                                  optionalParameters, request, defaultUrl,
421                                  keyRequestType);
422}
423
424status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
425                                 Vector<uint8_t> const &response,
426                                 Vector<uint8_t> &keySetId) {
427    Mutex::Autolock autoLock(mLock);
428
429    if (mInitCheck != OK) {
430        return mInitCheck;
431    }
432
433    if (mPlugin == NULL) {
434        return -EINVAL;
435    }
436
437    DrmSessionManager::Instance()->useSession(sessionId);
438
439    return mPlugin->provideKeyResponse(sessionId, response, keySetId);
440}
441
442status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
443    Mutex::Autolock autoLock(mLock);
444
445    if (mInitCheck != OK) {
446        return mInitCheck;
447    }
448
449    if (mPlugin == NULL) {
450        return -EINVAL;
451    }
452
453    return mPlugin->removeKeys(keySetId);
454}
455
456status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
457                          Vector<uint8_t> const &keySetId) {
458    Mutex::Autolock autoLock(mLock);
459
460    if (mInitCheck != OK) {
461        return mInitCheck;
462    }
463
464    if (mPlugin == NULL) {
465        return -EINVAL;
466    }
467
468    DrmSessionManager::Instance()->useSession(sessionId);
469
470    return mPlugin->restoreKeys(sessionId, keySetId);
471}
472
473status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
474                             KeyedVector<String8, String8> &infoMap) const {
475    Mutex::Autolock autoLock(mLock);
476
477    if (mInitCheck != OK) {
478        return mInitCheck;
479    }
480
481    if (mPlugin == NULL) {
482        return -EINVAL;
483    }
484
485    DrmSessionManager::Instance()->useSession(sessionId);
486
487    return mPlugin->queryKeyStatus(sessionId, infoMap);
488}
489
490status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority,
491                                  Vector<uint8_t> &request, String8 &defaultUrl) {
492    Mutex::Autolock autoLock(mLock);
493
494    if (mInitCheck != OK) {
495        return mInitCheck;
496    }
497
498    if (mPlugin == NULL) {
499        return -EINVAL;
500    }
501
502    return mPlugin->getProvisionRequest(certType, certAuthority,
503                                        request, defaultUrl);
504}
505
506status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response,
507                                       Vector<uint8_t> &certificate,
508                                       Vector<uint8_t> &wrappedKey) {
509    Mutex::Autolock autoLock(mLock);
510
511    if (mInitCheck != OK) {
512        return mInitCheck;
513    }
514
515    if (mPlugin == NULL) {
516        return -EINVAL;
517    }
518
519    return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
520}
521
522status_t Drm::unprovisionDevice() {
523    Mutex::Autolock autoLock(mLock);
524
525    if (mInitCheck != OK) {
526        return mInitCheck;
527    }
528
529    if (mPlugin == NULL) {
530        return -EINVAL;
531    }
532
533    if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
534        return -EPERM;
535    }
536
537    return mPlugin->unprovisionDevice();
538}
539
540status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
541    Mutex::Autolock autoLock(mLock);
542
543    if (mInitCheck != OK) {
544        return mInitCheck;
545    }
546
547    if (mPlugin == NULL) {
548        return -EINVAL;
549    }
550
551    return mPlugin->getSecureStops(secureStops);
552}
553
554status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
555    Mutex::Autolock autoLock(mLock);
556
557    if (mInitCheck != OK) {
558        return mInitCheck;
559    }
560
561    if (mPlugin == NULL) {
562        return -EINVAL;
563    }
564
565    return mPlugin->getSecureStop(ssid, secureStop);
566}
567
568status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
569    Mutex::Autolock autoLock(mLock);
570
571    if (mInitCheck != OK) {
572        return mInitCheck;
573    }
574
575    if (mPlugin == NULL) {
576        return -EINVAL;
577    }
578
579    return mPlugin->releaseSecureStops(ssRelease);
580}
581
582status_t Drm::releaseAllSecureStops() {
583    Mutex::Autolock autoLock(mLock);
584
585    if (mInitCheck != OK) {
586        return mInitCheck;
587    }
588
589    if (mPlugin == NULL) {
590        return -EINVAL;
591    }
592
593    return mPlugin->releaseAllSecureStops();
594}
595
596status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
597    Mutex::Autolock autoLock(mLock);
598
599    if (mInitCheck != OK) {
600        return mInitCheck;
601    }
602
603    if (mPlugin == NULL) {
604        return -EINVAL;
605    }
606
607    return mPlugin->getPropertyString(name, value);
608}
609
610status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
611    Mutex::Autolock autoLock(mLock);
612
613    if (mInitCheck != OK) {
614        return mInitCheck;
615    }
616
617    if (mPlugin == NULL) {
618        return -EINVAL;
619    }
620
621    return mPlugin->getPropertyByteArray(name, value);
622}
623
624status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
625    Mutex::Autolock autoLock(mLock);
626
627    if (mInitCheck != OK) {
628        return mInitCheck;
629    }
630
631    if (mPlugin == NULL) {
632        return -EINVAL;
633    }
634
635    return mPlugin->setPropertyString(name, value);
636}
637
638status_t Drm::setPropertyByteArray(String8 const &name,
639                                   Vector<uint8_t> const &value ) const {
640    Mutex::Autolock autoLock(mLock);
641
642    if (mInitCheck != OK) {
643        return mInitCheck;
644    }
645
646    if (mPlugin == NULL) {
647        return -EINVAL;
648    }
649
650    return mPlugin->setPropertyByteArray(name, value);
651}
652
653
654status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
655                                 String8 const &algorithm) {
656    Mutex::Autolock autoLock(mLock);
657
658    if (mInitCheck != OK) {
659        return mInitCheck;
660    }
661
662    if (mPlugin == NULL) {
663        return -EINVAL;
664    }
665
666    DrmSessionManager::Instance()->useSession(sessionId);
667
668    return mPlugin->setCipherAlgorithm(sessionId, algorithm);
669}
670
671status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
672                              String8 const &algorithm) {
673    Mutex::Autolock autoLock(mLock);
674
675    if (mInitCheck != OK) {
676        return mInitCheck;
677    }
678
679    if (mPlugin == NULL) {
680        return -EINVAL;
681    }
682
683    DrmSessionManager::Instance()->useSession(sessionId);
684
685    return mPlugin->setMacAlgorithm(sessionId, algorithm);
686}
687
688status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
689                      Vector<uint8_t> const &keyId,
690                      Vector<uint8_t> const &input,
691                      Vector<uint8_t> const &iv,
692                      Vector<uint8_t> &output) {
693    Mutex::Autolock autoLock(mLock);
694
695    if (mInitCheck != OK) {
696        return mInitCheck;
697    }
698
699    if (mPlugin == NULL) {
700        return -EINVAL;
701    }
702
703    DrmSessionManager::Instance()->useSession(sessionId);
704
705    return mPlugin->encrypt(sessionId, keyId, input, iv, output);
706}
707
708status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
709                      Vector<uint8_t> const &keyId,
710                      Vector<uint8_t> const &input,
711                      Vector<uint8_t> const &iv,
712                      Vector<uint8_t> &output) {
713    Mutex::Autolock autoLock(mLock);
714
715    if (mInitCheck != OK) {
716        return mInitCheck;
717    }
718
719    if (mPlugin == NULL) {
720        return -EINVAL;
721    }
722
723    DrmSessionManager::Instance()->useSession(sessionId);
724
725    return mPlugin->decrypt(sessionId, keyId, input, iv, output);
726}
727
728status_t Drm::sign(Vector<uint8_t> const &sessionId,
729                   Vector<uint8_t> const &keyId,
730                   Vector<uint8_t> const &message,
731                   Vector<uint8_t> &signature) {
732    Mutex::Autolock autoLock(mLock);
733
734    if (mInitCheck != OK) {
735        return mInitCheck;
736    }
737
738    if (mPlugin == NULL) {
739        return -EINVAL;
740    }
741
742    DrmSessionManager::Instance()->useSession(sessionId);
743
744    return mPlugin->sign(sessionId, keyId, message, signature);
745}
746
747status_t Drm::verify(Vector<uint8_t> const &sessionId,
748                     Vector<uint8_t> const &keyId,
749                     Vector<uint8_t> const &message,
750                     Vector<uint8_t> const &signature,
751                     bool &match) {
752    Mutex::Autolock autoLock(mLock);
753
754    if (mInitCheck != OK) {
755        return mInitCheck;
756    }
757
758    if (mPlugin == NULL) {
759        return -EINVAL;
760    }
761
762    DrmSessionManager::Instance()->useSession(sessionId);
763
764    return mPlugin->verify(sessionId, keyId, message, signature, match);
765}
766
767status_t Drm::signRSA(Vector<uint8_t> const &sessionId,
768                      String8 const &algorithm,
769                      Vector<uint8_t> const &message,
770                      Vector<uint8_t> const &wrappedKey,
771                      Vector<uint8_t> &signature) {
772    Mutex::Autolock autoLock(mLock);
773
774    if (mInitCheck != OK) {
775        return mInitCheck;
776    }
777
778    if (mPlugin == NULL) {
779        return -EINVAL;
780    }
781
782    if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
783        return -EPERM;
784    }
785
786    DrmSessionManager::Instance()->useSession(sessionId);
787
788    return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
789}
790
791void Drm::binderDied(const wp<IBinder> &the_late_who __unused)
792{
793    mEventLock.lock();
794    mListener.clear();
795    mEventLock.unlock();
796
797    Mutex::Autolock autoLock(mLock);
798    delete mPlugin;
799    mPlugin = NULL;
800    closeFactory();
801}
802
803void Drm::writeByteArray(Parcel &obj, Vector<uint8_t> const *array)
804{
805    if (array && array->size()) {
806        obj.writeInt32(array->size());
807        obj.write(array->array(), array->size());
808    } else {
809        obj.writeInt32(0);
810    }
811}
812
813}  // namespace android
814