Drm.cpp revision 9cf69e0fc110f17c28e988ed0f9bf91abfaf710d
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    return mFactory->isContentTypeSupported(mimeType);
226}
227
228status_t Drm::createPlugin(const uint8_t uuid[16]) {
229    Mutex::Autolock autoLock(mLock);
230
231    if (mPlugin != NULL) {
232        return -EINVAL;
233    }
234
235    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
236        findFactoryForScheme(uuid);
237    }
238
239    if (mInitCheck != OK) {
240        return mInitCheck;
241    }
242
243    status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
244    mPlugin->setListener(this);
245    return result;
246}
247
248status_t Drm::destroyPlugin() {
249    Mutex::Autolock autoLock(mLock);
250
251    if (mInitCheck != OK) {
252        return mInitCheck;
253    }
254
255    if (mPlugin == NULL) {
256        return -EINVAL;
257    }
258
259    delete mPlugin;
260    mPlugin = NULL;
261
262    return OK;
263}
264
265status_t Drm::openSession(Vector<uint8_t> &sessionId) {
266    Mutex::Autolock autoLock(mLock);
267
268    if (mInitCheck != OK) {
269        return mInitCheck;
270    }
271
272    if (mPlugin == NULL) {
273        return -EINVAL;
274    }
275
276    return mPlugin->openSession(sessionId);
277}
278
279status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
280    Mutex::Autolock autoLock(mLock);
281
282    if (mInitCheck != OK) {
283        return mInitCheck;
284    }
285
286    if (mPlugin == NULL) {
287        return -EINVAL;
288    }
289
290    return mPlugin->closeSession(sessionId);
291}
292
293status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
294                            Vector<uint8_t> const &initData,
295                            String8 const &mimeType, DrmPlugin::KeyType keyType,
296                            KeyedVector<String8, String8> const &optionalParameters,
297                            Vector<uint8_t> &request, String8 &defaultUrl) {
298    Mutex::Autolock autoLock(mLock);
299
300    if (mInitCheck != OK) {
301        return mInitCheck;
302    }
303
304    if (mPlugin == NULL) {
305        return -EINVAL;
306    }
307
308    return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
309                                  optionalParameters, request, defaultUrl);
310}
311
312status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
313                                 Vector<uint8_t> const &response,
314                                 Vector<uint8_t> &keySetId) {
315    Mutex::Autolock autoLock(mLock);
316
317    if (mInitCheck != OK) {
318        return mInitCheck;
319    }
320
321    if (mPlugin == NULL) {
322        return -EINVAL;
323    }
324
325    return mPlugin->provideKeyResponse(sessionId, response, keySetId);
326}
327
328status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
329    Mutex::Autolock autoLock(mLock);
330
331    if (mInitCheck != OK) {
332        return mInitCheck;
333    }
334
335    if (mPlugin == NULL) {
336        return -EINVAL;
337    }
338
339    return mPlugin->removeKeys(keySetId);
340}
341
342status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
343                          Vector<uint8_t> const &keySetId) {
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    return mPlugin->restoreKeys(sessionId, keySetId);
355}
356
357status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
358                             KeyedVector<String8, String8> &infoMap) const {
359    Mutex::Autolock autoLock(mLock);
360
361    if (mInitCheck != OK) {
362        return mInitCheck;
363    }
364
365    if (mPlugin == NULL) {
366        return -EINVAL;
367    }
368
369    return mPlugin->queryKeyStatus(sessionId, infoMap);
370}
371
372status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
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    return mPlugin->getProvisionRequest(request, defaultUrl);
384}
385
386status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
387    Mutex::Autolock autoLock(mLock);
388
389    if (mInitCheck != OK) {
390        return mInitCheck;
391    }
392
393    if (mPlugin == NULL) {
394        return -EINVAL;
395    }
396
397    return mPlugin->provideProvisionResponse(response);
398}
399
400
401status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
402    Mutex::Autolock autoLock(mLock);
403
404    if (mInitCheck != OK) {
405        return mInitCheck;
406    }
407
408    if (mPlugin == NULL) {
409        return -EINVAL;
410    }
411
412    return mPlugin->getSecureStops(secureStops);
413}
414
415status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
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    return mPlugin->releaseSecureStops(ssRelease);
427}
428
429status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
430    Mutex::Autolock autoLock(mLock);
431
432    if (mInitCheck != OK) {
433        return mInitCheck;
434    }
435
436    if (mPlugin == NULL) {
437        return -EINVAL;
438    }
439
440    return mPlugin->getPropertyString(name, value);
441}
442
443status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
444    Mutex::Autolock autoLock(mLock);
445
446    if (mInitCheck != OK) {
447        return mInitCheck;
448    }
449
450    if (mPlugin == NULL) {
451        return -EINVAL;
452    }
453
454    return mPlugin->getPropertyByteArray(name, value);
455}
456
457status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
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    return mPlugin->setPropertyString(name, value);
469}
470
471status_t Drm::setPropertyByteArray(String8 const &name,
472                                   Vector<uint8_t> const &value ) const {
473    Mutex::Autolock autoLock(mLock);
474
475    if (mInitCheck != OK) {
476        return mInitCheck;
477    }
478
479    if (mPlugin == NULL) {
480        return -EINVAL;
481    }
482
483    return mPlugin->setPropertyByteArray(name, value);
484}
485
486
487status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
488                                 String8 const &algorithm) {
489    Mutex::Autolock autoLock(mLock);
490
491    if (mInitCheck != OK) {
492        return mInitCheck;
493    }
494
495    if (mPlugin == NULL) {
496        return -EINVAL;
497    }
498
499    return mPlugin->setCipherAlgorithm(sessionId, algorithm);
500}
501
502status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
503                              String8 const &algorithm) {
504    Mutex::Autolock autoLock(mLock);
505
506    if (mInitCheck != OK) {
507        return mInitCheck;
508    }
509
510    if (mPlugin == NULL) {
511        return -EINVAL;
512    }
513
514    return mPlugin->setMacAlgorithm(sessionId, algorithm);
515}
516
517status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
518                      Vector<uint8_t> const &keyId,
519                      Vector<uint8_t> const &input,
520                      Vector<uint8_t> const &iv,
521                      Vector<uint8_t> &output) {
522    Mutex::Autolock autoLock(mLock);
523
524    if (mInitCheck != OK) {
525        return mInitCheck;
526    }
527
528    if (mPlugin == NULL) {
529        return -EINVAL;
530    }
531
532    return mPlugin->encrypt(sessionId, keyId, input, iv, output);
533}
534
535status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
536                      Vector<uint8_t> const &keyId,
537                      Vector<uint8_t> const &input,
538                      Vector<uint8_t> const &iv,
539                      Vector<uint8_t> &output) {
540    Mutex::Autolock autoLock(mLock);
541
542    if (mInitCheck != OK) {
543        return mInitCheck;
544    }
545
546    if (mPlugin == NULL) {
547        return -EINVAL;
548    }
549
550    return mPlugin->decrypt(sessionId, keyId, input, iv, output);
551}
552
553status_t Drm::sign(Vector<uint8_t> const &sessionId,
554                   Vector<uint8_t> const &keyId,
555                   Vector<uint8_t> const &message,
556                   Vector<uint8_t> &signature) {
557    Mutex::Autolock autoLock(mLock);
558
559    if (mInitCheck != OK) {
560        return mInitCheck;
561    }
562
563    if (mPlugin == NULL) {
564        return -EINVAL;
565    }
566
567    return mPlugin->sign(sessionId, keyId, message, signature);
568}
569
570status_t Drm::verify(Vector<uint8_t> const &sessionId,
571                     Vector<uint8_t> const &keyId,
572                     Vector<uint8_t> const &message,
573                     Vector<uint8_t> const &signature,
574                     bool &match) {
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->verify(sessionId, keyId, message, signature, match);
586}
587
588void Drm::binderDied(const wp<IBinder> &the_late_who)
589{
590    delete mPlugin;
591    mPlugin = NULL;
592    closeFactory();
593    mListener.clear();
594}
595
596}  // namespace android
597