blob: 2a8b2c61313a1d625850ef845409adff73bb33cf [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;
49
50static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
51 if (lhs.size() < rhs.size()) {
52 return true;
53 } else if (lhs.size() > rhs.size()) {
54 return false;
55 }
56
57 return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
58}
59
60Drm::Drm()
61 : mInitCheck(NO_INIT),
Jeff Tinker0cb126a2013-04-02 13:08:05 -070062 mListener(NULL),
Jeff Tinkercc82dc62013-02-08 10:18:35 -080063 mFactory(NULL),
64 mPlugin(NULL) {
65}
66
67Drm::~Drm() {
68 delete mPlugin;
69 mPlugin = NULL;
70 closeFactory();
71}
72
73void Drm::closeFactory() {
74 delete mFactory;
75 mFactory = NULL;
76 mLibrary.clear();
77}
78
79status_t Drm::initCheck() const {
80 return mInitCheck;
81}
82
Jeff Tinker0cb126a2013-04-02 13:08:05 -070083status_t Drm::setListener(const sp<IDrmClient>& listener)
84{
85 Mutex::Autolock lock(mEventLock);
Jeff Tinker3d3f67f2013-07-03 15:38:58 -070086 if (mListener != NULL){
87 mListener->asBinder()->unlinkToDeath(this);
88 }
89 if (listener != NULL) {
90 listener->asBinder()->linkToDeath(this);
91 }
Jeff Tinker0cb126a2013-04-02 13:08:05 -070092 mListener = listener;
93 return NO_ERROR;
94}
95
96void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
97 Vector<uint8_t> const *sessionId,
98 Vector<uint8_t> const *data)
99{
100 mEventLock.lock();
101 sp<IDrmClient> listener = mListener;
102 mEventLock.unlock();
103
104 if (listener != NULL) {
105 Parcel obj;
106 if (sessionId && sessionId->size()) {
107 obj.writeInt32(sessionId->size());
108 obj.write(sessionId->array(), sessionId->size());
109 } else {
110 obj.writeInt32(0);
111 }
112
113 if (data && data->size()) {
114 obj.writeInt32(data->size());
115 obj.write(data->array(), data->size());
116 } else {
117 obj.writeInt32(0);
118 }
119
120 Mutex::Autolock lock(mNotifyLock);
121 listener->notify(eventType, extra, &obj);
122 }
123}
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800124
125/*
126 * Search the plugins directory for a plugin that supports the scheme
127 * specified by uuid
128 *
129 * If found:
130 * mLibrary holds a strong pointer to the dlopen'd library
131 * mFactory is set to the library's factory method
132 * mInitCheck is set to OK
133 *
134 * If not found:
135 * mLibrary is cleared and mFactory are set to NULL
136 * mInitCheck is set to an error (!OK)
137 */
138void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
139
140 closeFactory();
141
142 // lock static maps
143 Mutex::Autolock autoLock(mMapLock);
144
145 // first check cache
146 Vector<uint8_t> uuidVector;
147 uuidVector.appendArray(uuid, sizeof(uuid));
148 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
149 if (index >= 0) {
150 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
151 mInitCheck = OK;
152 return;
153 } else {
154 ALOGE("Failed to load from cached library path!");
155 mInitCheck = ERROR_UNSUPPORTED;
156 return;
157 }
158 }
159
160 // no luck, have to search
161 String8 dirPath("/vendor/lib/mediadrm");
162 DIR* pDir = opendir(dirPath.string());
163
164 if (pDir == NULL) {
165 mInitCheck = ERROR_UNSUPPORTED;
166 ALOGE("Failed to open plugin directory %s", dirPath.string());
167 return;
168 }
169
170
171 struct dirent* pEntry;
172 while ((pEntry = readdir(pDir))) {
173
174 String8 pluginPath = dirPath + "/" + pEntry->d_name;
175
176 if (pluginPath.getPathExtension() == ".so") {
177
178 if (loadLibraryForScheme(pluginPath, uuid)) {
179 mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
180 mInitCheck = OK;
181 closedir(pDir);
182 return;
183 }
184 }
185 }
186
187 closedir(pDir);
188
189 ALOGE("Failed to find drm plugin");
190 mInitCheck = ERROR_UNSUPPORTED;
191}
192
193bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
194
195 // get strong pointer to open shared library
196 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
197 if (index >= 0) {
198 mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
199 } else {
200 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
201 }
202
203 if (!mLibrary.get()) {
204 mLibrary = new SharedLibrary(path);
205 if (!*mLibrary) {
206 return false;
207 }
208
209 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
210 }
211
212 typedef DrmFactory *(*CreateDrmFactoryFunc)();
213
214 CreateDrmFactoryFunc createDrmFactory =
215 (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
216
217 if (createDrmFactory == NULL ||
218 (mFactory = createDrmFactory()) == NULL ||
219 !mFactory->isCryptoSchemeSupported(uuid)) {
220 closeFactory();
221 return false;
222 }
223 return true;
224}
225
Jeff Tinker9cf69e02013-08-21 11:59:23 -0700226bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
227
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800228 Mutex::Autolock autoLock(mLock);
229
Jeff Tinker9cf69e02013-08-21 11:59:23 -0700230 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
231 findFactoryForScheme(uuid);
232 if (mInitCheck != OK) {
233 return false;
234 }
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800235 }
236
Jeff Tinkeree7e77d2013-08-28 16:40:41 -0700237 if (mimeType != "") {
238 return mFactory->isContentTypeSupported(mimeType);
239 }
240
241 return true;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800242}
243
244status_t Drm::createPlugin(const uint8_t uuid[16]) {
245 Mutex::Autolock autoLock(mLock);
246
247 if (mPlugin != NULL) {
248 return -EINVAL;
249 }
250
251 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
252 findFactoryForScheme(uuid);
253 }
254
255 if (mInitCheck != OK) {
256 return mInitCheck;
257 }
258
Jeff Tinker0cb126a2013-04-02 13:08:05 -0700259 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
260 mPlugin->setListener(this);
261 return result;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800262}
263
264status_t Drm::destroyPlugin() {
265 Mutex::Autolock autoLock(mLock);
266
267 if (mInitCheck != OK) {
268 return mInitCheck;
269 }
270
271 if (mPlugin == NULL) {
272 return -EINVAL;
273 }
274
275 delete mPlugin;
276 mPlugin = NULL;
277
278 return OK;
279}
280
281status_t Drm::openSession(Vector<uint8_t> &sessionId) {
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->openSession(sessionId);
293}
294
295status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
296 Mutex::Autolock autoLock(mLock);
297
298 if (mInitCheck != OK) {
299 return mInitCheck;
300 }
301
302 if (mPlugin == NULL) {
303 return -EINVAL;
304 }
305
306 return mPlugin->closeSession(sessionId);
307}
308
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700309status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
310 Vector<uint8_t> const &initData,
311 String8 const &mimeType, DrmPlugin::KeyType keyType,
312 KeyedVector<String8, String8> const &optionalParameters,
313 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800314 Mutex::Autolock autoLock(mLock);
315
316 if (mInitCheck != OK) {
317 return mInitCheck;
318 }
319
320 if (mPlugin == NULL) {
321 return -EINVAL;
322 }
323
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700324 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
325 optionalParameters, request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800326}
327
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700328status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
329 Vector<uint8_t> const &response,
330 Vector<uint8_t> &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800331 Mutex::Autolock autoLock(mLock);
332
333 if (mInitCheck != OK) {
334 return mInitCheck;
335 }
336
337 if (mPlugin == NULL) {
338 return -EINVAL;
339 }
340
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700341 return mPlugin->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800342}
343
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700344status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800345 Mutex::Autolock autoLock(mLock);
346
347 if (mInitCheck != OK) {
348 return mInitCheck;
349 }
350
351 if (mPlugin == NULL) {
352 return -EINVAL;
353 }
354
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700355 return mPlugin->removeKeys(keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800356}
357
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700358status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
359 Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800360 Mutex::Autolock autoLock(mLock);
361
362 if (mInitCheck != OK) {
363 return mInitCheck;
364 }
365
366 if (mPlugin == NULL) {
367 return -EINVAL;
368 }
369
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700370 return mPlugin->restoreKeys(sessionId, keySetId);
371}
372
373status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
374 KeyedVector<String8, String8> &infoMap) const {
375 Mutex::Autolock autoLock(mLock);
376
377 if (mInitCheck != OK) {
378 return mInitCheck;
379 }
380
381 if (mPlugin == NULL) {
382 return -EINVAL;
383 }
384
385 return mPlugin->queryKeyStatus(sessionId, infoMap);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800386}
387
Jeff Tinker68d9d712014-03-04 13:21:31 -0800388status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority,
389 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800390 Mutex::Autolock autoLock(mLock);
391
392 if (mInitCheck != OK) {
393 return mInitCheck;
394 }
395
396 if (mPlugin == NULL) {
397 return -EINVAL;
398 }
399
Jeff Tinker68d9d712014-03-04 13:21:31 -0800400 return mPlugin->getProvisionRequest(certType, certAuthority,
401 request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800402}
403
Jeff Tinker68d9d712014-03-04 13:21:31 -0800404status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response,
405 Vector<uint8_t> &certificate,
406 Vector<uint8_t> &wrappedKey) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800407 Mutex::Autolock autoLock(mLock);
408
409 if (mInitCheck != OK) {
410 return mInitCheck;
411 }
412
413 if (mPlugin == NULL) {
414 return -EINVAL;
415 }
416
Jeff Tinker68d9d712014-03-04 13:21:31 -0800417 return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800418}
419
Jeff Tinker68b15552014-04-30 10:19:03 -0700420status_t Drm::unprovisionDevice() {
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 if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
432 return -EPERM;
433 }
434
435 return mPlugin->unprovisionDevice();
436}
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800437
438status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
439 Mutex::Autolock autoLock(mLock);
440
441 if (mInitCheck != OK) {
442 return mInitCheck;
443 }
444
445 if (mPlugin == NULL) {
446 return -EINVAL;
447 }
448
449 return mPlugin->getSecureStops(secureStops);
450}
451
Jeff Tinker3c1285e2014-10-31 00:55:16 -0700452status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
453 Mutex::Autolock autoLock(mLock);
454
455 if (mInitCheck != OK) {
456 return mInitCheck;
457 }
458
459 if (mPlugin == NULL) {
460 return -EINVAL;
461 }
462
463 return mPlugin->getSecureStop(ssid, secureStop);
464}
465
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800466status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
467 Mutex::Autolock autoLock(mLock);
468
469 if (mInitCheck != OK) {
470 return mInitCheck;
471 }
472
473 if (mPlugin == NULL) {
474 return -EINVAL;
475 }
476
477 return mPlugin->releaseSecureStops(ssRelease);
478}
479
Jeff Tinker3c1285e2014-10-31 00:55:16 -0700480status_t Drm::releaseAllSecureStops() {
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->releaseAllSecureStops();
492}
493
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800494status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
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->getPropertyString(name, value);
506}
507
508status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
509 Mutex::Autolock autoLock(mLock);
510
511 if (mInitCheck != OK) {
512 return mInitCheck;
513 }
514
515 if (mPlugin == NULL) {
516 return -EINVAL;
517 }
518
519 return mPlugin->getPropertyByteArray(name, value);
520}
521
522status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
523 Mutex::Autolock autoLock(mLock);
524
525 if (mInitCheck != OK) {
526 return mInitCheck;
527 }
528
529 if (mPlugin == NULL) {
530 return -EINVAL;
531 }
532
533 return mPlugin->setPropertyString(name, value);
534}
535
536status_t Drm::setPropertyByteArray(String8 const &name,
537 Vector<uint8_t> const &value ) const {
538 Mutex::Autolock autoLock(mLock);
539
540 if (mInitCheck != OK) {
541 return mInitCheck;
542 }
543
544 if (mPlugin == NULL) {
545 return -EINVAL;
546 }
547
548 return mPlugin->setPropertyByteArray(name, value);
549}
550
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700551
552status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
553 String8 const &algorithm) {
554 Mutex::Autolock autoLock(mLock);
555
556 if (mInitCheck != OK) {
557 return mInitCheck;
558 }
559
560 if (mPlugin == NULL) {
561 return -EINVAL;
562 }
563
564 return mPlugin->setCipherAlgorithm(sessionId, algorithm);
565}
566
567status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
568 String8 const &algorithm) {
569 Mutex::Autolock autoLock(mLock);
570
571 if (mInitCheck != OK) {
572 return mInitCheck;
573 }
574
575 if (mPlugin == NULL) {
576 return -EINVAL;
577 }
578
579 return mPlugin->setMacAlgorithm(sessionId, algorithm);
580}
581
582status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
583 Vector<uint8_t> const &keyId,
584 Vector<uint8_t> const &input,
585 Vector<uint8_t> const &iv,
586 Vector<uint8_t> &output) {
587 Mutex::Autolock autoLock(mLock);
588
589 if (mInitCheck != OK) {
590 return mInitCheck;
591 }
592
593 if (mPlugin == NULL) {
594 return -EINVAL;
595 }
596
597 return mPlugin->encrypt(sessionId, keyId, input, iv, output);
598}
599
600status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
601 Vector<uint8_t> const &keyId,
602 Vector<uint8_t> const &input,
603 Vector<uint8_t> const &iv,
604 Vector<uint8_t> &output) {
605 Mutex::Autolock autoLock(mLock);
606
607 if (mInitCheck != OK) {
608 return mInitCheck;
609 }
610
611 if (mPlugin == NULL) {
612 return -EINVAL;
613 }
614
615 return mPlugin->decrypt(sessionId, keyId, input, iv, output);
616}
617
618status_t Drm::sign(Vector<uint8_t> const &sessionId,
619 Vector<uint8_t> const &keyId,
620 Vector<uint8_t> const &message,
621 Vector<uint8_t> &signature) {
622 Mutex::Autolock autoLock(mLock);
623
624 if (mInitCheck != OK) {
625 return mInitCheck;
626 }
627
628 if (mPlugin == NULL) {
629 return -EINVAL;
630 }
631
632 return mPlugin->sign(sessionId, keyId, message, signature);
633}
634
635status_t Drm::verify(Vector<uint8_t> const &sessionId,
636 Vector<uint8_t> const &keyId,
637 Vector<uint8_t> const &message,
638 Vector<uint8_t> const &signature,
639 bool &match) {
640 Mutex::Autolock autoLock(mLock);
641
642 if (mInitCheck != OK) {
643 return mInitCheck;
644 }
645
646 if (mPlugin == NULL) {
647 return -EINVAL;
648 }
649
650 return mPlugin->verify(sessionId, keyId, message, signature, match);
651}
652
Jeff Tinker68d9d712014-03-04 13:21:31 -0800653status_t Drm::signRSA(Vector<uint8_t> const &sessionId,
654 String8 const &algorithm,
655 Vector<uint8_t> const &message,
656 Vector<uint8_t> const &wrappedKey,
657 Vector<uint8_t> &signature) {
658 Mutex::Autolock autoLock(mLock);
659
660 if (mInitCheck != OK) {
661 return mInitCheck;
662 }
663
664 if (mPlugin == NULL) {
665 return -EINVAL;
666 }
667
Jeff Tinker81e0bd42014-04-02 16:41:38 -0700668 if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
669 return -EPERM;
670 }
671
Jeff Tinker68d9d712014-03-04 13:21:31 -0800672 return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
673}
674
Jeff Tinker3d3f67f2013-07-03 15:38:58 -0700675void Drm::binderDied(const wp<IBinder> &the_late_who)
676{
677 delete mPlugin;
678 mPlugin = NULL;
679 closeFactory();
680 mListener.clear();
681}
682
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800683} // namespace android