blob: 4b527d0838dd7b854ae46dc186bb59da45e2fbdb [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 Tinker9cf69e02013-08-21 11:59:23 -0700225 return mFactory->isContentTypeSupported(mimeType);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800226}
227
228status_t Drm::createPlugin(const uint8_t uuid[16]) {
229 Mutex::Autolock autoLock(mLock);
230
231 if (mPlugin != NULL) {
232 return -EINVAL;
233 }
234
235 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
236 findFactoryForScheme(uuid);
237 }
238
239 if (mInitCheck != OK) {
240 return mInitCheck;
241 }
242
Jeff Tinker0cb126a2013-04-02 13:08:05 -0700243 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
244 mPlugin->setListener(this);
245 return result;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800246}
247
248status_t Drm::destroyPlugin() {
249 Mutex::Autolock autoLock(mLock);
250
251 if (mInitCheck != OK) {
252 return mInitCheck;
253 }
254
255 if (mPlugin == NULL) {
256 return -EINVAL;
257 }
258
259 delete mPlugin;
260 mPlugin = NULL;
261
262 return OK;
263}
264
265status_t Drm::openSession(Vector<uint8_t> &sessionId) {
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 return mPlugin->openSession(sessionId);
277}
278
279status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
280 Mutex::Autolock autoLock(mLock);
281
282 if (mInitCheck != OK) {
283 return mInitCheck;
284 }
285
286 if (mPlugin == NULL) {
287 return -EINVAL;
288 }
289
290 return mPlugin->closeSession(sessionId);
291}
292
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700293status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
294 Vector<uint8_t> const &initData,
295 String8 const &mimeType, DrmPlugin::KeyType keyType,
296 KeyedVector<String8, String8> const &optionalParameters,
297 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800298 Mutex::Autolock autoLock(mLock);
299
300 if (mInitCheck != OK) {
301 return mInitCheck;
302 }
303
304 if (mPlugin == NULL) {
305 return -EINVAL;
306 }
307
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700308 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
309 optionalParameters, request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800310}
311
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700312status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
313 Vector<uint8_t> const &response,
314 Vector<uint8_t> &keySetId) {
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->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800326}
327
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700328status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800329 Mutex::Autolock autoLock(mLock);
330
331 if (mInitCheck != OK) {
332 return mInitCheck;
333 }
334
335 if (mPlugin == NULL) {
336 return -EINVAL;
337 }
338
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700339 return mPlugin->removeKeys(keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800340}
341
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700342status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
343 Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800344 Mutex::Autolock autoLock(mLock);
345
346 if (mInitCheck != OK) {
347 return mInitCheck;
348 }
349
350 if (mPlugin == NULL) {
351 return -EINVAL;
352 }
353
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700354 return mPlugin->restoreKeys(sessionId, keySetId);
355}
356
357status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
358 KeyedVector<String8, String8> &infoMap) const {
359 Mutex::Autolock autoLock(mLock);
360
361 if (mInitCheck != OK) {
362 return mInitCheck;
363 }
364
365 if (mPlugin == NULL) {
366 return -EINVAL;
367 }
368
369 return mPlugin->queryKeyStatus(sessionId, infoMap);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800370}
371
372status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
373 Mutex::Autolock autoLock(mLock);
374
375 if (mInitCheck != OK) {
376 return mInitCheck;
377 }
378
379 if (mPlugin == NULL) {
380 return -EINVAL;
381 }
382
383 return mPlugin->getProvisionRequest(request, defaultUrl);
384}
385
386status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
387 Mutex::Autolock autoLock(mLock);
388
389 if (mInitCheck != OK) {
390 return mInitCheck;
391 }
392
393 if (mPlugin == NULL) {
394 return -EINVAL;
395 }
396
397 return mPlugin->provideProvisionResponse(response);
398}
399
400
401status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
402 Mutex::Autolock autoLock(mLock);
403
404 if (mInitCheck != OK) {
405 return mInitCheck;
406 }
407
408 if (mPlugin == NULL) {
409 return -EINVAL;
410 }
411
412 return mPlugin->getSecureStops(secureStops);
413}
414
415status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
416 Mutex::Autolock autoLock(mLock);
417
418 if (mInitCheck != OK) {
419 return mInitCheck;
420 }
421
422 if (mPlugin == NULL) {
423 return -EINVAL;
424 }
425
426 return mPlugin->releaseSecureStops(ssRelease);
427}
428
429status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
430 Mutex::Autolock autoLock(mLock);
431
432 if (mInitCheck != OK) {
433 return mInitCheck;
434 }
435
436 if (mPlugin == NULL) {
437 return -EINVAL;
438 }
439
440 return mPlugin->getPropertyString(name, value);
441}
442
443status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
444 Mutex::Autolock autoLock(mLock);
445
446 if (mInitCheck != OK) {
447 return mInitCheck;
448 }
449
450 if (mPlugin == NULL) {
451 return -EINVAL;
452 }
453
454 return mPlugin->getPropertyByteArray(name, value);
455}
456
457status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
458 Mutex::Autolock autoLock(mLock);
459
460 if (mInitCheck != OK) {
461 return mInitCheck;
462 }
463
464 if (mPlugin == NULL) {
465 return -EINVAL;
466 }
467
468 return mPlugin->setPropertyString(name, value);
469}
470
471status_t Drm::setPropertyByteArray(String8 const &name,
472 Vector<uint8_t> const &value ) const {
473 Mutex::Autolock autoLock(mLock);
474
475 if (mInitCheck != OK) {
476 return mInitCheck;
477 }
478
479 if (mPlugin == NULL) {
480 return -EINVAL;
481 }
482
483 return mPlugin->setPropertyByteArray(name, value);
484}
485
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700486
487status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
488 String8 const &algorithm) {
489 Mutex::Autolock autoLock(mLock);
490
491 if (mInitCheck != OK) {
492 return mInitCheck;
493 }
494
495 if (mPlugin == NULL) {
496 return -EINVAL;
497 }
498
499 return mPlugin->setCipherAlgorithm(sessionId, algorithm);
500}
501
502status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
503 String8 const &algorithm) {
504 Mutex::Autolock autoLock(mLock);
505
506 if (mInitCheck != OK) {
507 return mInitCheck;
508 }
509
510 if (mPlugin == NULL) {
511 return -EINVAL;
512 }
513
514 return mPlugin->setMacAlgorithm(sessionId, algorithm);
515}
516
517status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
518 Vector<uint8_t> const &keyId,
519 Vector<uint8_t> const &input,
520 Vector<uint8_t> const &iv,
521 Vector<uint8_t> &output) {
522 Mutex::Autolock autoLock(mLock);
523
524 if (mInitCheck != OK) {
525 return mInitCheck;
526 }
527
528 if (mPlugin == NULL) {
529 return -EINVAL;
530 }
531
532 return mPlugin->encrypt(sessionId, keyId, input, iv, output);
533}
534
535status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
536 Vector<uint8_t> const &keyId,
537 Vector<uint8_t> const &input,
538 Vector<uint8_t> const &iv,
539 Vector<uint8_t> &output) {
540 Mutex::Autolock autoLock(mLock);
541
542 if (mInitCheck != OK) {
543 return mInitCheck;
544 }
545
546 if (mPlugin == NULL) {
547 return -EINVAL;
548 }
549
550 return mPlugin->decrypt(sessionId, keyId, input, iv, output);
551}
552
553status_t Drm::sign(Vector<uint8_t> const &sessionId,
554 Vector<uint8_t> const &keyId,
555 Vector<uint8_t> const &message,
556 Vector<uint8_t> &signature) {
557 Mutex::Autolock autoLock(mLock);
558
559 if (mInitCheck != OK) {
560 return mInitCheck;
561 }
562
563 if (mPlugin == NULL) {
564 return -EINVAL;
565 }
566
567 return mPlugin->sign(sessionId, keyId, message, signature);
568}
569
570status_t Drm::verify(Vector<uint8_t> const &sessionId,
571 Vector<uint8_t> const &keyId,
572 Vector<uint8_t> const &message,
573 Vector<uint8_t> const &signature,
574 bool &match) {
575 Mutex::Autolock autoLock(mLock);
576
577 if (mInitCheck != OK) {
578 return mInitCheck;
579 }
580
581 if (mPlugin == NULL) {
582 return -EINVAL;
583 }
584
585 return mPlugin->verify(sessionId, keyId, message, signature, match);
586}
587
Jeff Tinker3d3f67f2013-07-03 15:38:58 -0700588void Drm::binderDied(const wp<IBinder> &the_late_who)
589{
590 delete mPlugin;
591 mPlugin = NULL;
592 closeFactory();
593 mListener.clear();
594}
595
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800596} // namespace android