blob: eebcb799045c071261c078357b77760f01425ec9 [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
376status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
377 Mutex::Autolock autoLock(mLock);
378
379 if (mInitCheck != OK) {
380 return mInitCheck;
381 }
382
383 if (mPlugin == NULL) {
384 return -EINVAL;
385 }
386
387 return mPlugin->getProvisionRequest(request, defaultUrl);
388}
389
390status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
391 Mutex::Autolock autoLock(mLock);
392
393 if (mInitCheck != OK) {
394 return mInitCheck;
395 }
396
397 if (mPlugin == NULL) {
398 return -EINVAL;
399 }
400
401 return mPlugin->provideProvisionResponse(response);
402}
403
404
405status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
406 Mutex::Autolock autoLock(mLock);
407
408 if (mInitCheck != OK) {
409 return mInitCheck;
410 }
411
412 if (mPlugin == NULL) {
413 return -EINVAL;
414 }
415
416 return mPlugin->getSecureStops(secureStops);
417}
418
419status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
420 Mutex::Autolock autoLock(mLock);
421
422 if (mInitCheck != OK) {
423 return mInitCheck;
424 }
425
426 if (mPlugin == NULL) {
427 return -EINVAL;
428 }
429
430 return mPlugin->releaseSecureStops(ssRelease);
431}
432
433status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
434 Mutex::Autolock autoLock(mLock);
435
436 if (mInitCheck != OK) {
437 return mInitCheck;
438 }
439
440 if (mPlugin == NULL) {
441 return -EINVAL;
442 }
443
444 return mPlugin->getPropertyString(name, value);
445}
446
447status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
448 Mutex::Autolock autoLock(mLock);
449
450 if (mInitCheck != OK) {
451 return mInitCheck;
452 }
453
454 if (mPlugin == NULL) {
455 return -EINVAL;
456 }
457
458 return mPlugin->getPropertyByteArray(name, value);
459}
460
461status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
462 Mutex::Autolock autoLock(mLock);
463
464 if (mInitCheck != OK) {
465 return mInitCheck;
466 }
467
468 if (mPlugin == NULL) {
469 return -EINVAL;
470 }
471
472 return mPlugin->setPropertyString(name, value);
473}
474
475status_t Drm::setPropertyByteArray(String8 const &name,
476 Vector<uint8_t> const &value ) const {
477 Mutex::Autolock autoLock(mLock);
478
479 if (mInitCheck != OK) {
480 return mInitCheck;
481 }
482
483 if (mPlugin == NULL) {
484 return -EINVAL;
485 }
486
487 return mPlugin->setPropertyByteArray(name, value);
488}
489
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700490
491status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
492 String8 const &algorithm) {
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->setCipherAlgorithm(sessionId, algorithm);
504}
505
506status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
507 String8 const &algorithm) {
508 Mutex::Autolock autoLock(mLock);
509
510 if (mInitCheck != OK) {
511 return mInitCheck;
512 }
513
514 if (mPlugin == NULL) {
515 return -EINVAL;
516 }
517
518 return mPlugin->setMacAlgorithm(sessionId, algorithm);
519}
520
521status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
522 Vector<uint8_t> const &keyId,
523 Vector<uint8_t> const &input,
524 Vector<uint8_t> const &iv,
525 Vector<uint8_t> &output) {
526 Mutex::Autolock autoLock(mLock);
527
528 if (mInitCheck != OK) {
529 return mInitCheck;
530 }
531
532 if (mPlugin == NULL) {
533 return -EINVAL;
534 }
535
536 return mPlugin->encrypt(sessionId, keyId, input, iv, output);
537}
538
539status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
540 Vector<uint8_t> const &keyId,
541 Vector<uint8_t> const &input,
542 Vector<uint8_t> const &iv,
543 Vector<uint8_t> &output) {
544 Mutex::Autolock autoLock(mLock);
545
546 if (mInitCheck != OK) {
547 return mInitCheck;
548 }
549
550 if (mPlugin == NULL) {
551 return -EINVAL;
552 }
553
554 return mPlugin->decrypt(sessionId, keyId, input, iv, output);
555}
556
557status_t Drm::sign(Vector<uint8_t> const &sessionId,
558 Vector<uint8_t> const &keyId,
559 Vector<uint8_t> const &message,
560 Vector<uint8_t> &signature) {
561 Mutex::Autolock autoLock(mLock);
562
563 if (mInitCheck != OK) {
564 return mInitCheck;
565 }
566
567 if (mPlugin == NULL) {
568 return -EINVAL;
569 }
570
571 return mPlugin->sign(sessionId, keyId, message, signature);
572}
573
574status_t Drm::verify(Vector<uint8_t> const &sessionId,
575 Vector<uint8_t> const &keyId,
576 Vector<uint8_t> const &message,
577 Vector<uint8_t> const &signature,
578 bool &match) {
579 Mutex::Autolock autoLock(mLock);
580
581 if (mInitCheck != OK) {
582 return mInitCheck;
583 }
584
585 if (mPlugin == NULL) {
586 return -EINVAL;
587 }
588
589 return mPlugin->verify(sessionId, keyId, message, signature, match);
590}
591
Jeff Tinker3d3f67f2013-07-03 15:38:58 -0700592void Drm::binderDied(const wp<IBinder> &the_late_who)
593{
594 delete mPlugin;
595 mPlugin = NULL;
596 closeFactory();
597 mListener.clear();
598}
599
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800600} // namespace android