Drm.cpp revision 0cb126a34fe32f81c830858102471e7be2ce85b1
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    mListener = listener;
75    return NO_ERROR;
76}
77
78void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
79                    Vector<uint8_t> const *sessionId,
80                    Vector<uint8_t> const *data)
81{
82    mEventLock.lock();
83    sp<IDrmClient> listener = mListener;
84    mEventLock.unlock();
85
86    if (listener != NULL) {
87        Parcel obj;
88        if (sessionId && sessionId->size()) {
89            obj.writeInt32(sessionId->size());
90            obj.write(sessionId->array(), sessionId->size());
91        } else {
92            obj.writeInt32(0);
93        }
94
95        if (data && data->size()) {
96            obj.writeInt32(data->size());
97            obj.write(data->array(), data->size());
98        } else {
99            obj.writeInt32(0);
100        }
101
102        Mutex::Autolock lock(mNotifyLock);
103        listener->notify(eventType, extra, &obj);
104    }
105}
106
107/*
108 * Search the plugins directory for a plugin that supports the scheme
109 * specified by uuid
110 *
111 * If found:
112 *    mLibrary holds a strong pointer to the dlopen'd library
113 *    mFactory is set to the library's factory method
114 *    mInitCheck is set to OK
115 *
116 * If not found:
117 *    mLibrary is cleared and mFactory are set to NULL
118 *    mInitCheck is set to an error (!OK)
119 */
120void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
121
122    closeFactory();
123
124    // lock static maps
125    Mutex::Autolock autoLock(mMapLock);
126
127    // first check cache
128    Vector<uint8_t> uuidVector;
129    uuidVector.appendArray(uuid, sizeof(uuid));
130    ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
131    if (index >= 0) {
132        if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
133            mInitCheck = OK;
134            return;
135        } else {
136            ALOGE("Failed to load from cached library path!");
137            mInitCheck = ERROR_UNSUPPORTED;
138            return;
139        }
140    }
141
142    // no luck, have to search
143    String8 dirPath("/vendor/lib/mediadrm");
144    DIR* pDir = opendir(dirPath.string());
145
146    if (pDir == NULL) {
147        mInitCheck = ERROR_UNSUPPORTED;
148        ALOGE("Failed to open plugin directory %s", dirPath.string());
149        return;
150    }
151
152
153    struct dirent* pEntry;
154    while ((pEntry = readdir(pDir))) {
155
156        String8 pluginPath = dirPath + "/" + pEntry->d_name;
157
158        if (pluginPath.getPathExtension() == ".so") {
159
160            if (loadLibraryForScheme(pluginPath, uuid)) {
161                mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
162                mInitCheck = OK;
163                closedir(pDir);
164                return;
165            }
166        }
167    }
168
169    closedir(pDir);
170
171    ALOGE("Failed to find drm plugin");
172    mInitCheck = ERROR_UNSUPPORTED;
173}
174
175bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
176
177    // get strong pointer to open shared library
178    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
179    if (index >= 0) {
180        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
181    } else {
182        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
183    }
184
185    if (!mLibrary.get()) {
186        mLibrary = new SharedLibrary(path);
187        if (!*mLibrary) {
188            return false;
189        }
190
191        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
192    }
193
194    typedef DrmFactory *(*CreateDrmFactoryFunc)();
195
196    CreateDrmFactoryFunc createDrmFactory =
197        (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
198
199    if (createDrmFactory == NULL ||
200        (mFactory = createDrmFactory()) == NULL ||
201        !mFactory->isCryptoSchemeSupported(uuid)) {
202        closeFactory();
203        return false;
204    }
205    return true;
206}
207
208bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) {
209    Mutex::Autolock autoLock(mLock);
210
211    if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
212        return true;
213    }
214
215    findFactoryForScheme(uuid);
216    return (mInitCheck == OK);
217}
218
219status_t Drm::createPlugin(const uint8_t uuid[16]) {
220    Mutex::Autolock autoLock(mLock);
221
222    if (mPlugin != NULL) {
223        return -EINVAL;
224    }
225
226    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
227        findFactoryForScheme(uuid);
228    }
229
230    if (mInitCheck != OK) {
231        return mInitCheck;
232    }
233
234    status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
235    mPlugin->setListener(this);
236    return result;
237}
238
239status_t Drm::destroyPlugin() {
240    Mutex::Autolock autoLock(mLock);
241
242    if (mInitCheck != OK) {
243        return mInitCheck;
244    }
245
246    if (mPlugin == NULL) {
247        return -EINVAL;
248    }
249
250    delete mPlugin;
251    mPlugin = NULL;
252
253    return OK;
254}
255
256status_t Drm::openSession(Vector<uint8_t> &sessionId) {
257    Mutex::Autolock autoLock(mLock);
258
259    if (mInitCheck != OK) {
260        return mInitCheck;
261    }
262
263    if (mPlugin == NULL) {
264        return -EINVAL;
265    }
266
267    return mPlugin->openSession(sessionId);
268}
269
270status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
271    Mutex::Autolock autoLock(mLock);
272
273    if (mInitCheck != OK) {
274        return mInitCheck;
275    }
276
277    if (mPlugin == NULL) {
278        return -EINVAL;
279    }
280
281    return mPlugin->closeSession(sessionId);
282}
283
284status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
285                            Vector<uint8_t> const &initData,
286                            String8 const &mimeType, DrmPlugin::KeyType keyType,
287                            KeyedVector<String8, String8> const &optionalParameters,
288                            Vector<uint8_t> &request, String8 &defaultUrl) {
289    Mutex::Autolock autoLock(mLock);
290
291    if (mInitCheck != OK) {
292        return mInitCheck;
293    }
294
295    if (mPlugin == NULL) {
296        return -EINVAL;
297    }
298
299    return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
300                                  optionalParameters, request, defaultUrl);
301}
302
303status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
304                                 Vector<uint8_t> const &response,
305                                 Vector<uint8_t> &keySetId) {
306    Mutex::Autolock autoLock(mLock);
307
308    if (mInitCheck != OK) {
309        return mInitCheck;
310    }
311
312    if (mPlugin == NULL) {
313        return -EINVAL;
314    }
315
316    return mPlugin->provideKeyResponse(sessionId, response, keySetId);
317}
318
319status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
320    Mutex::Autolock autoLock(mLock);
321
322    if (mInitCheck != OK) {
323        return mInitCheck;
324    }
325
326    if (mPlugin == NULL) {
327        return -EINVAL;
328    }
329
330    return mPlugin->removeKeys(keySetId);
331}
332
333status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
334                          Vector<uint8_t> const &keySetId) {
335    Mutex::Autolock autoLock(mLock);
336
337    if (mInitCheck != OK) {
338        return mInitCheck;
339    }
340
341    if (mPlugin == NULL) {
342        return -EINVAL;
343    }
344
345    return mPlugin->restoreKeys(sessionId, keySetId);
346}
347
348status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
349                             KeyedVector<String8, String8> &infoMap) const {
350    Mutex::Autolock autoLock(mLock);
351
352    if (mInitCheck != OK) {
353        return mInitCheck;
354    }
355
356    if (mPlugin == NULL) {
357        return -EINVAL;
358    }
359
360    return mPlugin->queryKeyStatus(sessionId, infoMap);
361}
362
363status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
364    Mutex::Autolock autoLock(mLock);
365
366    if (mInitCheck != OK) {
367        return mInitCheck;
368    }
369
370    if (mPlugin == NULL) {
371        return -EINVAL;
372    }
373
374    return mPlugin->getProvisionRequest(request, defaultUrl);
375}
376
377status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
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->provideProvisionResponse(response);
389}
390
391
392status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
393    Mutex::Autolock autoLock(mLock);
394
395    if (mInitCheck != OK) {
396        return mInitCheck;
397    }
398
399    if (mPlugin == NULL) {
400        return -EINVAL;
401    }
402
403    return mPlugin->getSecureStops(secureStops);
404}
405
406status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
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    return mPlugin->releaseSecureStops(ssRelease);
418}
419
420status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
421    Mutex::Autolock autoLock(mLock);
422
423    if (mInitCheck != OK) {
424        return mInitCheck;
425    }
426
427    if (mPlugin == NULL) {
428        return -EINVAL;
429    }
430
431    return mPlugin->getPropertyString(name, value);
432}
433
434status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
435    Mutex::Autolock autoLock(mLock);
436
437    if (mInitCheck != OK) {
438        return mInitCheck;
439    }
440
441    if (mPlugin == NULL) {
442        return -EINVAL;
443    }
444
445    return mPlugin->getPropertyByteArray(name, value);
446}
447
448status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
449    Mutex::Autolock autoLock(mLock);
450
451    if (mInitCheck != OK) {
452        return mInitCheck;
453    }
454
455    if (mPlugin == NULL) {
456        return -EINVAL;
457    }
458
459    return mPlugin->setPropertyString(name, value);
460}
461
462status_t Drm::setPropertyByteArray(String8 const &name,
463                                   Vector<uint8_t> const &value ) 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    return mPlugin->setPropertyByteArray(name, value);
475}
476
477
478status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
479                                 String8 const &algorithm) {
480    Mutex::Autolock autoLock(mLock);
481
482    if (mInitCheck != OK) {
483        return mInitCheck;
484    }
485
486    if (mPlugin == NULL) {
487        return -EINVAL;
488    }
489
490    return mPlugin->setCipherAlgorithm(sessionId, algorithm);
491}
492
493status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
494                              String8 const &algorithm) {
495    Mutex::Autolock autoLock(mLock);
496
497    if (mInitCheck != OK) {
498        return mInitCheck;
499    }
500
501    if (mPlugin == NULL) {
502        return -EINVAL;
503    }
504
505    return mPlugin->setMacAlgorithm(sessionId, algorithm);
506}
507
508status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
509                      Vector<uint8_t> const &keyId,
510                      Vector<uint8_t> const &input,
511                      Vector<uint8_t> const &iv,
512                      Vector<uint8_t> &output) {
513    Mutex::Autolock autoLock(mLock);
514
515    if (mInitCheck != OK) {
516        return mInitCheck;
517    }
518
519    if (mPlugin == NULL) {
520        return -EINVAL;
521    }
522
523    return mPlugin->encrypt(sessionId, keyId, input, iv, output);
524}
525
526status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
527                      Vector<uint8_t> const &keyId,
528                      Vector<uint8_t> const &input,
529                      Vector<uint8_t> const &iv,
530                      Vector<uint8_t> &output) {
531    Mutex::Autolock autoLock(mLock);
532
533    if (mInitCheck != OK) {
534        return mInitCheck;
535    }
536
537    if (mPlugin == NULL) {
538        return -EINVAL;
539    }
540
541    return mPlugin->decrypt(sessionId, keyId, input, iv, output);
542}
543
544status_t Drm::sign(Vector<uint8_t> const &sessionId,
545                   Vector<uint8_t> const &keyId,
546                   Vector<uint8_t> const &message,
547                   Vector<uint8_t> &signature) {
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->sign(sessionId, keyId, message, signature);
559}
560
561status_t Drm::verify(Vector<uint8_t> const &sessionId,
562                     Vector<uint8_t> const &keyId,
563                     Vector<uint8_t> const &message,
564                     Vector<uint8_t> const &signature,
565                     bool &match) {
566    Mutex::Autolock autoLock(mLock);
567
568    if (mInitCheck != OK) {
569        return mInitCheck;
570    }
571
572    if (mPlugin == NULL) {
573        return -EINVAL;
574    }
575
576    return mPlugin->verify(sessionId, keyId, message, signature, match);
577}
578
579}  // namespace android
580