Drm.cpp revision 68d9d71a792deed75d32fe13febc07c9c12c8449
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
32namespace android {
33
34KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
35KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
36Mutex Drm::mMapLock;
37
38static 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
48Drm::Drm()
49    : mInitCheck(NO_INIT),
50      mListener(NULL),
51      mFactory(NULL),
52      mPlugin(NULL) {
53}
54
55Drm::~Drm() {
56    delete mPlugin;
57    mPlugin = NULL;
58    closeFactory();
59}
60
61void Drm::closeFactory() {
62    delete mFactory;
63    mFactory = NULL;
64    mLibrary.clear();
65}
66
67status_t Drm::initCheck() const {
68    return mInitCheck;
69}
70
71status_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
84void 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 */
126void 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
181bool 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
214bool 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
232status_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
252status_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
269status_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
283status_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
297status_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
316status_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
332status_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
346status_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
361status_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
376status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority,
377                                  Vector<uint8_t> &request, String8 &defaultUrl) {
378    Mutex::Autolock autoLock(mLock);
379
380    if (mInitCheck != OK) {
381        return mInitCheck;
382    }
383
384    if (mPlugin == NULL) {
385        return -EINVAL;
386    }
387
388    return mPlugin->getProvisionRequest(certType, certAuthority,
389                                        request, defaultUrl);
390}
391
392status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response,
393                                       Vector<uint8_t> &certificate,
394                                       Vector<uint8_t> &wrappedKey) {
395    Mutex::Autolock autoLock(mLock);
396
397    if (mInitCheck != OK) {
398        return mInitCheck;
399    }
400
401    if (mPlugin == NULL) {
402        return -EINVAL;
403    }
404
405    return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
406}
407
408
409status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
410    Mutex::Autolock autoLock(mLock);
411
412    if (mInitCheck != OK) {
413        return mInitCheck;
414    }
415
416    if (mPlugin == NULL) {
417        return -EINVAL;
418    }
419
420    return mPlugin->getSecureStops(secureStops);
421}
422
423status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
424    Mutex::Autolock autoLock(mLock);
425
426    if (mInitCheck != OK) {
427        return mInitCheck;
428    }
429
430    if (mPlugin == NULL) {
431        return -EINVAL;
432    }
433
434    return mPlugin->releaseSecureStops(ssRelease);
435}
436
437status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
438    Mutex::Autolock autoLock(mLock);
439
440    if (mInitCheck != OK) {
441        return mInitCheck;
442    }
443
444    if (mPlugin == NULL) {
445        return -EINVAL;
446    }
447
448    return mPlugin->getPropertyString(name, value);
449}
450
451status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
452    Mutex::Autolock autoLock(mLock);
453
454    if (mInitCheck != OK) {
455        return mInitCheck;
456    }
457
458    if (mPlugin == NULL) {
459        return -EINVAL;
460    }
461
462    return mPlugin->getPropertyByteArray(name, value);
463}
464
465status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
466    Mutex::Autolock autoLock(mLock);
467
468    if (mInitCheck != OK) {
469        return mInitCheck;
470    }
471
472    if (mPlugin == NULL) {
473        return -EINVAL;
474    }
475
476    return mPlugin->setPropertyString(name, value);
477}
478
479status_t Drm::setPropertyByteArray(String8 const &name,
480                                   Vector<uint8_t> const &value ) const {
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->setPropertyByteArray(name, value);
492}
493
494
495status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
496                                 String8 const &algorithm) {
497    Mutex::Autolock autoLock(mLock);
498
499    if (mInitCheck != OK) {
500        return mInitCheck;
501    }
502
503    if (mPlugin == NULL) {
504        return -EINVAL;
505    }
506
507    return mPlugin->setCipherAlgorithm(sessionId, algorithm);
508}
509
510status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
511                              String8 const &algorithm) {
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    return mPlugin->setMacAlgorithm(sessionId, algorithm);
523}
524
525status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
526                      Vector<uint8_t> const &keyId,
527                      Vector<uint8_t> const &input,
528                      Vector<uint8_t> const &iv,
529                      Vector<uint8_t> &output) {
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->encrypt(sessionId, keyId, input, iv, output);
541}
542
543status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
544                      Vector<uint8_t> const &keyId,
545                      Vector<uint8_t> const &input,
546                      Vector<uint8_t> const &iv,
547                      Vector<uint8_t> &output) {
548    Mutex::Autolock autoLock(mLock);
549
550    if (mInitCheck != OK) {
551        return mInitCheck;
552    }
553
554    if (mPlugin == NULL) {
555        return -EINVAL;
556    }
557
558    return mPlugin->decrypt(sessionId, keyId, input, iv, output);
559}
560
561status_t Drm::sign(Vector<uint8_t> const &sessionId,
562                   Vector<uint8_t> const &keyId,
563                   Vector<uint8_t> const &message,
564                   Vector<uint8_t> &signature) {
565    Mutex::Autolock autoLock(mLock);
566
567    if (mInitCheck != OK) {
568        return mInitCheck;
569    }
570
571    if (mPlugin == NULL) {
572        return -EINVAL;
573    }
574
575    return mPlugin->sign(sessionId, keyId, message, signature);
576}
577
578status_t Drm::verify(Vector<uint8_t> const &sessionId,
579                     Vector<uint8_t> const &keyId,
580                     Vector<uint8_t> const &message,
581                     Vector<uint8_t> const &signature,
582                     bool &match) {
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->verify(sessionId, keyId, message, signature, match);
594}
595
596status_t Drm::signRSA(Vector<uint8_t> const &sessionId,
597                      String8 const &algorithm,
598                      Vector<uint8_t> const &message,
599                      Vector<uint8_t> const &wrappedKey,
600                      Vector<uint8_t> &signature) {
601    Mutex::Autolock autoLock(mLock);
602
603    if (mInitCheck != OK) {
604        return mInitCheck;
605    }
606
607    if (mPlugin == NULL) {
608        return -EINVAL;
609    }
610
611    return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
612}
613
614void Drm::binderDied(const wp<IBinder> &the_late_who)
615{
616    delete mPlugin;
617    mPlugin = NULL;
618    closeFactory();
619    mListener.clear();
620}
621
622}  // namespace android
623