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