blob: e68d4cd6d4ca412413824075dd3ffe8cf38817f6 [file] [log] [blame]
Jeff Tinkercc82dc62013-02-08 10:18:35 -08001/*
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),
Jeff Tinker0cb126a2013-04-02 13:08:05 -070050 mListener(NULL),
Jeff Tinkercc82dc62013-02-08 10:18:35 -080051 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
Jeff Tinker0cb126a2013-04-02 13:08:05 -070071status_t Drm::setListener(const sp<IDrmClient>& listener)
72{
73 Mutex::Autolock lock(mEventLock);
Jeff Tinker3d3f67f2013-07-03 15:38:58 -070074 if (mListener != NULL){
75 mListener->asBinder()->unlinkToDeath(this);
76 }
77 if (listener != NULL) {
78 listener->asBinder()->linkToDeath(this);
79 }
Jeff Tinker0cb126a2013-04-02 13:08:05 -070080 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}
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800112
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
Jeff Tinker9cf69e02013-08-21 11:59:23 -0700214bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
215
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800216 Mutex::Autolock autoLock(mLock);
217
Jeff Tinker9cf69e02013-08-21 11:59:23 -0700218 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
219 findFactoryForScheme(uuid);
220 if (mInitCheck != OK) {
221 return false;
222 }
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800223 }
224
Jeff Tinkeree7e77d2013-08-28 16:40:41 -0700225 if (mimeType != "") {
226 return mFactory->isContentTypeSupported(mimeType);
227 }
228
229 return true;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800230}
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
Jeff Tinker0cb126a2013-04-02 13:08:05 -0700247 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
248 mPlugin->setListener(this);
249 return result;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800250}
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
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700297status_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) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800302 Mutex::Autolock autoLock(mLock);
303
304 if (mInitCheck != OK) {
305 return mInitCheck;
306 }
307
308 if (mPlugin == NULL) {
309 return -EINVAL;
310 }
311
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700312 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
313 optionalParameters, request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800314}
315
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700316status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
317 Vector<uint8_t> const &response,
318 Vector<uint8_t> &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800319 Mutex::Autolock autoLock(mLock);
320
321 if (mInitCheck != OK) {
322 return mInitCheck;
323 }
324
325 if (mPlugin == NULL) {
326 return -EINVAL;
327 }
328
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700329 return mPlugin->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800330}
331
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700332status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800333 Mutex::Autolock autoLock(mLock);
334
335 if (mInitCheck != OK) {
336 return mInitCheck;
337 }
338
339 if (mPlugin == NULL) {
340 return -EINVAL;
341 }
342
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700343 return mPlugin->removeKeys(keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800344}
345
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700346status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
347 Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800348 Mutex::Autolock autoLock(mLock);
349
350 if (mInitCheck != OK) {
351 return mInitCheck;
352 }
353
354 if (mPlugin == NULL) {
355 return -EINVAL;
356 }
357
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700358 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);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800374}
375
Jeff Tinker68d9d712014-03-04 13:21:31 -0800376status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority,
377 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800378 Mutex::Autolock autoLock(mLock);
379
380 if (mInitCheck != OK) {
381 return mInitCheck;
382 }
383
384 if (mPlugin == NULL) {
385 return -EINVAL;
386 }
387
Jeff Tinker68d9d712014-03-04 13:21:31 -0800388 return mPlugin->getProvisionRequest(certType, certAuthority,
389 request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800390}
391
Jeff Tinker68d9d712014-03-04 13:21:31 -0800392status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response,
393 Vector<uint8_t> &certificate,
394 Vector<uint8_t> &wrappedKey) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800395 Mutex::Autolock autoLock(mLock);
396
397 if (mInitCheck != OK) {
398 return mInitCheck;
399 }
400
401 if (mPlugin == NULL) {
402 return -EINVAL;
403 }
404
Jeff Tinker68d9d712014-03-04 13:21:31 -0800405 return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800406}
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
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700494
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
Jeff Tinker68d9d712014-03-04 13:21:31 -0800596status_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
Jeff Tinker3d3f67f2013-07-03 15:38:58 -0700614void Drm::binderDied(const wp<IBinder> &the_late_who)
615{
616 delete mPlugin;
617 mPlugin = NULL;
618 closeFactory();
619 mListener.clear();
620}
621
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800622} // namespace android