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