blob: ac948a6a160a3887fb1cbcc7ea7525b7fd1ec928 [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>
Jeff Tinker81e0bd42014-04-02 16:41:38 -070031#include <binder/IServiceManager.h>
32#include <binder/IPCThreadState.h>
Jeff Tinkercc82dc62013-02-08 10:18:35 -080033
34namespace android {
35
Jeff Tinker81e0bd42014-04-02 16:41:38 -070036static bool checkPermission(const char* permissionString) {
37#ifndef HAVE_ANDROID_OS
38 return true;
39#endif
40 if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
41 bool ok = checkCallingPermission(String16(permissionString));
42 if (!ok) ALOGE("Request requires %s", permissionString);
43 return ok;
44}
45
Jeff Tinkercc82dc62013-02-08 10:18:35 -080046KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
47KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
48Mutex Drm::mMapLock;
Jeff Tinkerd3831762015-04-22 15:58:16 -070049Mutex Drm::mLock;
Jeff Tinkercc82dc62013-02-08 10:18:35 -080050
51static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
52 if (lhs.size() < rhs.size()) {
53 return true;
54 } else if (lhs.size() > rhs.size()) {
55 return false;
56 }
57
58 return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
59}
60
61Drm::Drm()
62 : mInitCheck(NO_INIT),
Jeff Tinker0cb126a2013-04-02 13:08:05 -070063 mListener(NULL),
Jeff Tinkercc82dc62013-02-08 10:18:35 -080064 mFactory(NULL),
65 mPlugin(NULL) {
66}
67
68Drm::~Drm() {
69 delete mPlugin;
70 mPlugin = NULL;
71 closeFactory();
72}
73
74void Drm::closeFactory() {
75 delete mFactory;
76 mFactory = NULL;
77 mLibrary.clear();
78}
79
80status_t Drm::initCheck() const {
81 return mInitCheck;
82}
83
Jeff Tinker0cb126a2013-04-02 13:08:05 -070084status_t Drm::setListener(const sp<IDrmClient>& listener)
85{
86 Mutex::Autolock lock(mEventLock);
Jeff Tinker3d3f67f2013-07-03 15:38:58 -070087 if (mListener != NULL){
88 mListener->asBinder()->unlinkToDeath(this);
89 }
90 if (listener != NULL) {
91 listener->asBinder()->linkToDeath(this);
92 }
Jeff Tinker0cb126a2013-04-02 13:08:05 -070093 mListener = listener;
94 return NO_ERROR;
95}
96
97void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
98 Vector<uint8_t> const *sessionId,
99 Vector<uint8_t> const *data)
100{
101 mEventLock.lock();
102 sp<IDrmClient> listener = mListener;
103 mEventLock.unlock();
104
105 if (listener != NULL) {
106 Parcel obj;
107 if (sessionId && sessionId->size()) {
108 obj.writeInt32(sessionId->size());
109 obj.write(sessionId->array(), sessionId->size());
110 } else {
111 obj.writeInt32(0);
112 }
113
114 if (data && data->size()) {
115 obj.writeInt32(data->size());
116 obj.write(data->array(), data->size());
117 } else {
118 obj.writeInt32(0);
119 }
120
121 Mutex::Autolock lock(mNotifyLock);
122 listener->notify(eventType, extra, &obj);
123 }
124}
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800125
126/*
127 * Search the plugins directory for a plugin that supports the scheme
128 * specified by uuid
129 *
130 * If found:
131 * mLibrary holds a strong pointer to the dlopen'd library
132 * mFactory is set to the library's factory method
133 * mInitCheck is set to OK
134 *
135 * If not found:
136 * mLibrary is cleared and mFactory are set to NULL
137 * mInitCheck is set to an error (!OK)
138 */
139void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
140
141 closeFactory();
142
143 // lock static maps
144 Mutex::Autolock autoLock(mMapLock);
145
146 // first check cache
147 Vector<uint8_t> uuidVector;
148 uuidVector.appendArray(uuid, sizeof(uuid));
149 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
150 if (index >= 0) {
151 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
152 mInitCheck = OK;
153 return;
154 } else {
155 ALOGE("Failed to load from cached library path!");
156 mInitCheck = ERROR_UNSUPPORTED;
157 return;
158 }
159 }
160
161 // no luck, have to search
162 String8 dirPath("/vendor/lib/mediadrm");
163 DIR* pDir = opendir(dirPath.string());
164
165 if (pDir == NULL) {
166 mInitCheck = ERROR_UNSUPPORTED;
167 ALOGE("Failed to open plugin directory %s", dirPath.string());
168 return;
169 }
170
171
172 struct dirent* pEntry;
173 while ((pEntry = readdir(pDir))) {
174
175 String8 pluginPath = dirPath + "/" + pEntry->d_name;
176
177 if (pluginPath.getPathExtension() == ".so") {
178
179 if (loadLibraryForScheme(pluginPath, uuid)) {
180 mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
181 mInitCheck = OK;
182 closedir(pDir);
183 return;
184 }
185 }
186 }
187
188 closedir(pDir);
189
190 ALOGE("Failed to find drm plugin");
191 mInitCheck = ERROR_UNSUPPORTED;
192}
193
194bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
195
196 // get strong pointer to open shared library
197 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
198 if (index >= 0) {
199 mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
200 } else {
201 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
202 }
203
204 if (!mLibrary.get()) {
205 mLibrary = new SharedLibrary(path);
206 if (!*mLibrary) {
207 return false;
208 }
209
210 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
211 }
212
213 typedef DrmFactory *(*CreateDrmFactoryFunc)();
214
215 CreateDrmFactoryFunc createDrmFactory =
216 (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
217
218 if (createDrmFactory == NULL ||
219 (mFactory = createDrmFactory()) == NULL ||
220 !mFactory->isCryptoSchemeSupported(uuid)) {
221 closeFactory();
222 return false;
223 }
224 return true;
225}
226
Jeff Tinker9cf69e02013-08-21 11:59:23 -0700227bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
228
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800229 Mutex::Autolock autoLock(mLock);
230
Jeff Tinker9cf69e02013-08-21 11:59:23 -0700231 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
232 findFactoryForScheme(uuid);
233 if (mInitCheck != OK) {
234 return false;
235 }
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800236 }
237
Jeff Tinkeree7e77d2013-08-28 16:40:41 -0700238 if (mimeType != "") {
239 return mFactory->isContentTypeSupported(mimeType);
240 }
241
242 return true;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800243}
244
245status_t Drm::createPlugin(const uint8_t uuid[16]) {
246 Mutex::Autolock autoLock(mLock);
247
248 if (mPlugin != NULL) {
249 return -EINVAL;
250 }
251
252 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
253 findFactoryForScheme(uuid);
254 }
255
256 if (mInitCheck != OK) {
257 return mInitCheck;
258 }
259
Jeff Tinker0cb126a2013-04-02 13:08:05 -0700260 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
261 mPlugin->setListener(this);
262 return result;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800263}
264
265status_t Drm::destroyPlugin() {
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 delete mPlugin;
277 mPlugin = NULL;
278
279 return OK;
280}
281
282status_t Drm::openSession(Vector<uint8_t> &sessionId) {
283 Mutex::Autolock autoLock(mLock);
284
285 if (mInitCheck != OK) {
286 return mInitCheck;
287 }
288
289 if (mPlugin == NULL) {
290 return -EINVAL;
291 }
292
293 return mPlugin->openSession(sessionId);
294}
295
296status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
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->closeSession(sessionId);
308}
309
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700310status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
311 Vector<uint8_t> const &initData,
312 String8 const &mimeType, DrmPlugin::KeyType keyType,
313 KeyedVector<String8, String8> const &optionalParameters,
314 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800315 Mutex::Autolock autoLock(mLock);
316
317 if (mInitCheck != OK) {
318 return mInitCheck;
319 }
320
321 if (mPlugin == NULL) {
322 return -EINVAL;
323 }
324
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700325 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
326 optionalParameters, request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800327}
328
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700329status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
330 Vector<uint8_t> const &response,
331 Vector<uint8_t> &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800332 Mutex::Autolock autoLock(mLock);
333
334 if (mInitCheck != OK) {
335 return mInitCheck;
336 }
337
338 if (mPlugin == NULL) {
339 return -EINVAL;
340 }
341
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700342 return mPlugin->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800343}
344
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700345status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800346 Mutex::Autolock autoLock(mLock);
347
348 if (mInitCheck != OK) {
349 return mInitCheck;
350 }
351
352 if (mPlugin == NULL) {
353 return -EINVAL;
354 }
355
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700356 return mPlugin->removeKeys(keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800357}
358
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700359status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
360 Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800361 Mutex::Autolock autoLock(mLock);
362
363 if (mInitCheck != OK) {
364 return mInitCheck;
365 }
366
367 if (mPlugin == NULL) {
368 return -EINVAL;
369 }
370
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700371 return mPlugin->restoreKeys(sessionId, keySetId);
372}
373
374status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
375 KeyedVector<String8, String8> &infoMap) const {
376 Mutex::Autolock autoLock(mLock);
377
378 if (mInitCheck != OK) {
379 return mInitCheck;
380 }
381
382 if (mPlugin == NULL) {
383 return -EINVAL;
384 }
385
386 return mPlugin->queryKeyStatus(sessionId, infoMap);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800387}
388
Jeff Tinker68d9d712014-03-04 13:21:31 -0800389status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority,
390 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800391 Mutex::Autolock autoLock(mLock);
392
393 if (mInitCheck != OK) {
394 return mInitCheck;
395 }
396
397 if (mPlugin == NULL) {
398 return -EINVAL;
399 }
400
Jeff Tinker68d9d712014-03-04 13:21:31 -0800401 return mPlugin->getProvisionRequest(certType, certAuthority,
402 request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800403}
404
Jeff Tinker68d9d712014-03-04 13:21:31 -0800405status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response,
406 Vector<uint8_t> &certificate,
407 Vector<uint8_t> &wrappedKey) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800408 Mutex::Autolock autoLock(mLock);
409
410 if (mInitCheck != OK) {
411 return mInitCheck;
412 }
413
414 if (mPlugin == NULL) {
415 return -EINVAL;
416 }
417
Jeff Tinker68d9d712014-03-04 13:21:31 -0800418 return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800419}
420
Jeff Tinker68b15552014-04-30 10:19:03 -0700421status_t Drm::unprovisionDevice() {
422 Mutex::Autolock autoLock(mLock);
423
424 if (mInitCheck != OK) {
425 return mInitCheck;
426 }
427
428 if (mPlugin == NULL) {
429 return -EINVAL;
430 }
431
432 if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
433 return -EPERM;
434 }
435
436 return mPlugin->unprovisionDevice();
437}
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800438
439status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
440 Mutex::Autolock autoLock(mLock);
441
442 if (mInitCheck != OK) {
443 return mInitCheck;
444 }
445
446 if (mPlugin == NULL) {
447 return -EINVAL;
448 }
449
450 return mPlugin->getSecureStops(secureStops);
451}
452
Jeff Tinker3c1285e2014-10-31 00:55:16 -0700453status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
454 Mutex::Autolock autoLock(mLock);
455
456 if (mInitCheck != OK) {
457 return mInitCheck;
458 }
459
460 if (mPlugin == NULL) {
461 return -EINVAL;
462 }
463
464 return mPlugin->getSecureStop(ssid, secureStop);
465}
466
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800467status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
468 Mutex::Autolock autoLock(mLock);
469
470 if (mInitCheck != OK) {
471 return mInitCheck;
472 }
473
474 if (mPlugin == NULL) {
475 return -EINVAL;
476 }
477
478 return mPlugin->releaseSecureStops(ssRelease);
479}
480
Jeff Tinker3c1285e2014-10-31 00:55:16 -0700481status_t Drm::releaseAllSecureStops() {
482 Mutex::Autolock autoLock(mLock);
483
484 if (mInitCheck != OK) {
485 return mInitCheck;
486 }
487
488 if (mPlugin == NULL) {
489 return -EINVAL;
490 }
491
492 return mPlugin->releaseAllSecureStops();
493}
494
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800495status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
496 Mutex::Autolock autoLock(mLock);
497
498 if (mInitCheck != OK) {
499 return mInitCheck;
500 }
501
502 if (mPlugin == NULL) {
503 return -EINVAL;
504 }
505
506 return mPlugin->getPropertyString(name, value);
507}
508
509status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
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->getPropertyByteArray(name, value);
521}
522
523status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
524 Mutex::Autolock autoLock(mLock);
525
526 if (mInitCheck != OK) {
527 return mInitCheck;
528 }
529
530 if (mPlugin == NULL) {
531 return -EINVAL;
532 }
533
534 return mPlugin->setPropertyString(name, value);
535}
536
537status_t Drm::setPropertyByteArray(String8 const &name,
538 Vector<uint8_t> const &value ) const {
539 Mutex::Autolock autoLock(mLock);
540
541 if (mInitCheck != OK) {
542 return mInitCheck;
543 }
544
545 if (mPlugin == NULL) {
546 return -EINVAL;
547 }
548
549 return mPlugin->setPropertyByteArray(name, value);
550}
551
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700552
553status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
554 String8 const &algorithm) {
555 Mutex::Autolock autoLock(mLock);
556
557 if (mInitCheck != OK) {
558 return mInitCheck;
559 }
560
561 if (mPlugin == NULL) {
562 return -EINVAL;
563 }
564
565 return mPlugin->setCipherAlgorithm(sessionId, algorithm);
566}
567
568status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
569 String8 const &algorithm) {
570 Mutex::Autolock autoLock(mLock);
571
572 if (mInitCheck != OK) {
573 return mInitCheck;
574 }
575
576 if (mPlugin == NULL) {
577 return -EINVAL;
578 }
579
580 return mPlugin->setMacAlgorithm(sessionId, algorithm);
581}
582
583status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
584 Vector<uint8_t> const &keyId,
585 Vector<uint8_t> const &input,
586 Vector<uint8_t> const &iv,
587 Vector<uint8_t> &output) {
588 Mutex::Autolock autoLock(mLock);
589
590 if (mInitCheck != OK) {
591 return mInitCheck;
592 }
593
594 if (mPlugin == NULL) {
595 return -EINVAL;
596 }
597
598 return mPlugin->encrypt(sessionId, keyId, input, iv, output);
599}
600
601status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
602 Vector<uint8_t> const &keyId,
603 Vector<uint8_t> const &input,
604 Vector<uint8_t> const &iv,
605 Vector<uint8_t> &output) {
606 Mutex::Autolock autoLock(mLock);
607
608 if (mInitCheck != OK) {
609 return mInitCheck;
610 }
611
612 if (mPlugin == NULL) {
613 return -EINVAL;
614 }
615
616 return mPlugin->decrypt(sessionId, keyId, input, iv, output);
617}
618
619status_t Drm::sign(Vector<uint8_t> const &sessionId,
620 Vector<uint8_t> const &keyId,
621 Vector<uint8_t> const &message,
622 Vector<uint8_t> &signature) {
623 Mutex::Autolock autoLock(mLock);
624
625 if (mInitCheck != OK) {
626 return mInitCheck;
627 }
628
629 if (mPlugin == NULL) {
630 return -EINVAL;
631 }
632
633 return mPlugin->sign(sessionId, keyId, message, signature);
634}
635
636status_t Drm::verify(Vector<uint8_t> const &sessionId,
637 Vector<uint8_t> const &keyId,
638 Vector<uint8_t> const &message,
639 Vector<uint8_t> const &signature,
640 bool &match) {
641 Mutex::Autolock autoLock(mLock);
642
643 if (mInitCheck != OK) {
644 return mInitCheck;
645 }
646
647 if (mPlugin == NULL) {
648 return -EINVAL;
649 }
650
651 return mPlugin->verify(sessionId, keyId, message, signature, match);
652}
653
Jeff Tinker68d9d712014-03-04 13:21:31 -0800654status_t Drm::signRSA(Vector<uint8_t> const &sessionId,
655 String8 const &algorithm,
656 Vector<uint8_t> const &message,
657 Vector<uint8_t> const &wrappedKey,
658 Vector<uint8_t> &signature) {
659 Mutex::Autolock autoLock(mLock);
660
661 if (mInitCheck != OK) {
662 return mInitCheck;
663 }
664
665 if (mPlugin == NULL) {
666 return -EINVAL;
667 }
668
Jeff Tinker81e0bd42014-04-02 16:41:38 -0700669 if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
670 return -EPERM;
671 }
672
Jeff Tinker68d9d712014-03-04 13:21:31 -0800673 return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
674}
675
Jeff Tinker3d3f67f2013-07-03 15:38:58 -0700676void Drm::binderDied(const wp<IBinder> &the_late_who)
677{
Jeff Tinker4dbc8cc2014-11-16 11:52:03 -0800678 mEventLock.lock();
679 mListener.clear();
680 mEventLock.unlock();
681
682 Mutex::Autolock autoLock(mLock);
Jeff Tinker3d3f67f2013-07-03 15:38:58 -0700683 delete mPlugin;
684 mPlugin = NULL;
685 closeFactory();
Jeff Tinker3d3f67f2013-07-03 15:38:58 -0700686}
687
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800688} // namespace android