Drm.cpp revision 2fb561a6fe9bca79c50a81e90fc4bb4eb18af0be
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        retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
362        if (retry) {
363            err = mPlugin->openSession(sessionId);
364        }
365    }
366    if (err == OK) {
367        DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId);
368    }
369    return err;
370}
371
372status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
373    Mutex::Autolock autoLock(mLock);
374
375    if (mInitCheck != OK) {
376        return mInitCheck;
377    }
378
379    if (mPlugin == NULL) {
380        return -EINVAL;
381    }
382
383    status_t err = mPlugin->closeSession(sessionId);
384    if (err == OK) {
385        DrmSessionManager::Instance()->removeSession(sessionId);
386    }
387    return err;
388}
389
390status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
391                            Vector<uint8_t> const &initData,
392                            String8 const &mimeType, DrmPlugin::KeyType keyType,
393                            KeyedVector<String8, String8> const &optionalParameters,
394                            Vector<uint8_t> &request, String8 &defaultUrl,
395                            DrmPlugin::KeyRequestType *keyRequestType) {
396    Mutex::Autolock autoLock(mLock);
397
398    if (mInitCheck != OK) {
399        return mInitCheck;
400    }
401
402    if (mPlugin == NULL) {
403        return -EINVAL;
404    }
405
406    DrmSessionManager::Instance()->useSession(sessionId);
407
408    return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
409                                  optionalParameters, request, defaultUrl,
410                                  keyRequestType);
411}
412
413status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
414                                 Vector<uint8_t> const &response,
415                                 Vector<uint8_t> &keySetId) {
416    Mutex::Autolock autoLock(mLock);
417
418    if (mInitCheck != OK) {
419        return mInitCheck;
420    }
421
422    if (mPlugin == NULL) {
423        return -EINVAL;
424    }
425
426    DrmSessionManager::Instance()->useSession(sessionId);
427
428    return mPlugin->provideKeyResponse(sessionId, response, keySetId);
429}
430
431status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
432    Mutex::Autolock autoLock(mLock);
433
434    if (mInitCheck != OK) {
435        return mInitCheck;
436    }
437
438    if (mPlugin == NULL) {
439        return -EINVAL;
440    }
441
442    return mPlugin->removeKeys(keySetId);
443}
444
445status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
446                          Vector<uint8_t> const &keySetId) {
447    Mutex::Autolock autoLock(mLock);
448
449    if (mInitCheck != OK) {
450        return mInitCheck;
451    }
452
453    if (mPlugin == NULL) {
454        return -EINVAL;
455    }
456
457    DrmSessionManager::Instance()->useSession(sessionId);
458
459    return mPlugin->restoreKeys(sessionId, keySetId);
460}
461
462status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
463                             KeyedVector<String8, String8> &infoMap) const {
464    Mutex::Autolock autoLock(mLock);
465
466    if (mInitCheck != OK) {
467        return mInitCheck;
468    }
469
470    if (mPlugin == NULL) {
471        return -EINVAL;
472    }
473
474    DrmSessionManager::Instance()->useSession(sessionId);
475
476    return mPlugin->queryKeyStatus(sessionId, infoMap);
477}
478
479status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority,
480                                  Vector<uint8_t> &request, String8 &defaultUrl) {
481    Mutex::Autolock autoLock(mLock);
482
483    if (mInitCheck != OK) {
484        return mInitCheck;
485    }
486
487    if (mPlugin == NULL) {
488        return -EINVAL;
489    }
490
491    return mPlugin->getProvisionRequest(certType, certAuthority,
492                                        request, defaultUrl);
493}
494
495status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response,
496                                       Vector<uint8_t> &certificate,
497                                       Vector<uint8_t> &wrappedKey) {
498    Mutex::Autolock autoLock(mLock);
499
500    if (mInitCheck != OK) {
501        return mInitCheck;
502    }
503
504    if (mPlugin == NULL) {
505        return -EINVAL;
506    }
507
508    return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
509}
510
511status_t Drm::unprovisionDevice() {
512    Mutex::Autolock autoLock(mLock);
513
514    if (mInitCheck != OK) {
515        return mInitCheck;
516    }
517
518    if (mPlugin == NULL) {
519        return -EINVAL;
520    }
521
522    if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
523        return -EPERM;
524    }
525
526    return mPlugin->unprovisionDevice();
527}
528
529status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
530    Mutex::Autolock autoLock(mLock);
531
532    if (mInitCheck != OK) {
533        return mInitCheck;
534    }
535
536    if (mPlugin == NULL) {
537        return -EINVAL;
538    }
539
540    return mPlugin->getSecureStops(secureStops);
541}
542
543status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
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->getSecureStop(ssid, secureStop);
555}
556
557status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
558    Mutex::Autolock autoLock(mLock);
559
560    if (mInitCheck != OK) {
561        return mInitCheck;
562    }
563
564    if (mPlugin == NULL) {
565        return -EINVAL;
566    }
567
568    return mPlugin->releaseSecureStops(ssRelease);
569}
570
571status_t Drm::releaseAllSecureStops() {
572    Mutex::Autolock autoLock(mLock);
573
574    if (mInitCheck != OK) {
575        return mInitCheck;
576    }
577
578    if (mPlugin == NULL) {
579        return -EINVAL;
580    }
581
582    return mPlugin->releaseAllSecureStops();
583}
584
585status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
586    Mutex::Autolock autoLock(mLock);
587
588    if (mInitCheck != OK) {
589        return mInitCheck;
590    }
591
592    if (mPlugin == NULL) {
593        return -EINVAL;
594    }
595
596    return mPlugin->getPropertyString(name, value);
597}
598
599status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
600    Mutex::Autolock autoLock(mLock);
601
602    if (mInitCheck != OK) {
603        return mInitCheck;
604    }
605
606    if (mPlugin == NULL) {
607        return -EINVAL;
608    }
609
610    return mPlugin->getPropertyByteArray(name, value);
611}
612
613status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
614    Mutex::Autolock autoLock(mLock);
615
616    if (mInitCheck != OK) {
617        return mInitCheck;
618    }
619
620    if (mPlugin == NULL) {
621        return -EINVAL;
622    }
623
624    return mPlugin->setPropertyString(name, value);
625}
626
627status_t Drm::setPropertyByteArray(String8 const &name,
628                                   Vector<uint8_t> const &value ) const {
629    Mutex::Autolock autoLock(mLock);
630
631    if (mInitCheck != OK) {
632        return mInitCheck;
633    }
634
635    if (mPlugin == NULL) {
636        return -EINVAL;
637    }
638
639    return mPlugin->setPropertyByteArray(name, value);
640}
641
642
643status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
644                                 String8 const &algorithm) {
645    Mutex::Autolock autoLock(mLock);
646
647    if (mInitCheck != OK) {
648        return mInitCheck;
649    }
650
651    if (mPlugin == NULL) {
652        return -EINVAL;
653    }
654
655    DrmSessionManager::Instance()->useSession(sessionId);
656
657    return mPlugin->setCipherAlgorithm(sessionId, algorithm);
658}
659
660status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
661                              String8 const &algorithm) {
662    Mutex::Autolock autoLock(mLock);
663
664    if (mInitCheck != OK) {
665        return mInitCheck;
666    }
667
668    if (mPlugin == NULL) {
669        return -EINVAL;
670    }
671
672    DrmSessionManager::Instance()->useSession(sessionId);
673
674    return mPlugin->setMacAlgorithm(sessionId, algorithm);
675}
676
677status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
678                      Vector<uint8_t> const &keyId,
679                      Vector<uint8_t> const &input,
680                      Vector<uint8_t> const &iv,
681                      Vector<uint8_t> &output) {
682    Mutex::Autolock autoLock(mLock);
683
684    if (mInitCheck != OK) {
685        return mInitCheck;
686    }
687
688    if (mPlugin == NULL) {
689        return -EINVAL;
690    }
691
692    DrmSessionManager::Instance()->useSession(sessionId);
693
694    return mPlugin->encrypt(sessionId, keyId, input, iv, output);
695}
696
697status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
698                      Vector<uint8_t> const &keyId,
699                      Vector<uint8_t> const &input,
700                      Vector<uint8_t> const &iv,
701                      Vector<uint8_t> &output) {
702    Mutex::Autolock autoLock(mLock);
703
704    if (mInitCheck != OK) {
705        return mInitCheck;
706    }
707
708    if (mPlugin == NULL) {
709        return -EINVAL;
710    }
711
712    DrmSessionManager::Instance()->useSession(sessionId);
713
714    return mPlugin->decrypt(sessionId, keyId, input, iv, output);
715}
716
717status_t Drm::sign(Vector<uint8_t> const &sessionId,
718                   Vector<uint8_t> const &keyId,
719                   Vector<uint8_t> const &message,
720                   Vector<uint8_t> &signature) {
721    Mutex::Autolock autoLock(mLock);
722
723    if (mInitCheck != OK) {
724        return mInitCheck;
725    }
726
727    if (mPlugin == NULL) {
728        return -EINVAL;
729    }
730
731    DrmSessionManager::Instance()->useSession(sessionId);
732
733    return mPlugin->sign(sessionId, keyId, message, signature);
734}
735
736status_t Drm::verify(Vector<uint8_t> const &sessionId,
737                     Vector<uint8_t> const &keyId,
738                     Vector<uint8_t> const &message,
739                     Vector<uint8_t> const &signature,
740                     bool &match) {
741    Mutex::Autolock autoLock(mLock);
742
743    if (mInitCheck != OK) {
744        return mInitCheck;
745    }
746
747    if (mPlugin == NULL) {
748        return -EINVAL;
749    }
750
751    DrmSessionManager::Instance()->useSession(sessionId);
752
753    return mPlugin->verify(sessionId, keyId, message, signature, match);
754}
755
756status_t Drm::signRSA(Vector<uint8_t> const &sessionId,
757                      String8 const &algorithm,
758                      Vector<uint8_t> const &message,
759                      Vector<uint8_t> const &wrappedKey,
760                      Vector<uint8_t> &signature) {
761    Mutex::Autolock autoLock(mLock);
762
763    if (mInitCheck != OK) {
764        return mInitCheck;
765    }
766
767    if (mPlugin == NULL) {
768        return -EINVAL;
769    }
770
771    if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
772        return -EPERM;
773    }
774
775    DrmSessionManager::Instance()->useSession(sessionId);
776
777    return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
778}
779
780void Drm::binderDied(const wp<IBinder> &the_late_who __unused)
781{
782    mEventLock.lock();
783    mListener.clear();
784    mEventLock.unlock();
785
786    Mutex::Autolock autoLock(mLock);
787    delete mPlugin;
788    mPlugin = NULL;
789    closeFactory();
790}
791
792void Drm::writeByteArray(Parcel &obj, Vector<uint8_t> const *array)
793{
794    if (array && array->size()) {
795        obj.writeInt32(array->size());
796        obj.write(array->array(), array->size());
797    } else {
798        obj.writeInt32(0);
799    }
800}
801
802}  // namespace android
803