blob: f00f4886e5bc1791665092040db2b131d1a54a54 [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
214bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) {
215 Mutex::Autolock autoLock(mLock);
216
217 if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
218 return true;
219 }
220
221 findFactoryForScheme(uuid);
222 return (mInitCheck == OK);
223}
224
225status_t Drm::createPlugin(const uint8_t uuid[16]) {
226 Mutex::Autolock autoLock(mLock);
227
228 if (mPlugin != NULL) {
229 return -EINVAL;
230 }
231
232 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
233 findFactoryForScheme(uuid);
234 }
235
236 if (mInitCheck != OK) {
237 return mInitCheck;
238 }
239
Jeff Tinker0cb126a2013-04-02 13:08:05 -0700240 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
241 mPlugin->setListener(this);
242 return result;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800243}
244
245status_t Drm::destroyPlugin() {
246 Mutex::Autolock autoLock(mLock);
247
248 if (mInitCheck != OK) {
249 return mInitCheck;
250 }
251
252 if (mPlugin == NULL) {
253 return -EINVAL;
254 }
255
256 delete mPlugin;
257 mPlugin = NULL;
258
259 return OK;
260}
261
262status_t Drm::openSession(Vector<uint8_t> &sessionId) {
263 Mutex::Autolock autoLock(mLock);
264
265 if (mInitCheck != OK) {
266 return mInitCheck;
267 }
268
269 if (mPlugin == NULL) {
270 return -EINVAL;
271 }
272
273 return mPlugin->openSession(sessionId);
274}
275
276status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
277 Mutex::Autolock autoLock(mLock);
278
279 if (mInitCheck != OK) {
280 return mInitCheck;
281 }
282
283 if (mPlugin == NULL) {
284 return -EINVAL;
285 }
286
287 return mPlugin->closeSession(sessionId);
288}
289
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700290status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
291 Vector<uint8_t> const &initData,
292 String8 const &mimeType, DrmPlugin::KeyType keyType,
293 KeyedVector<String8, String8> const &optionalParameters,
294 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800295 Mutex::Autolock autoLock(mLock);
296
297 if (mInitCheck != OK) {
298 return mInitCheck;
299 }
300
301 if (mPlugin == NULL) {
302 return -EINVAL;
303 }
304
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700305 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
306 optionalParameters, request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800307}
308
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700309status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
310 Vector<uint8_t> const &response,
311 Vector<uint8_t> &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800312 Mutex::Autolock autoLock(mLock);
313
314 if (mInitCheck != OK) {
315 return mInitCheck;
316 }
317
318 if (mPlugin == NULL) {
319 return -EINVAL;
320 }
321
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700322 return mPlugin->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800323}
324
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700325status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800326 Mutex::Autolock autoLock(mLock);
327
328 if (mInitCheck != OK) {
329 return mInitCheck;
330 }
331
332 if (mPlugin == NULL) {
333 return -EINVAL;
334 }
335
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700336 return mPlugin->removeKeys(keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800337}
338
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700339status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
340 Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800341 Mutex::Autolock autoLock(mLock);
342
343 if (mInitCheck != OK) {
344 return mInitCheck;
345 }
346
347 if (mPlugin == NULL) {
348 return -EINVAL;
349 }
350
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700351 return mPlugin->restoreKeys(sessionId, keySetId);
352}
353
354status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
355 KeyedVector<String8, String8> &infoMap) const {
356 Mutex::Autolock autoLock(mLock);
357
358 if (mInitCheck != OK) {
359 return mInitCheck;
360 }
361
362 if (mPlugin == NULL) {
363 return -EINVAL;
364 }
365
366 return mPlugin->queryKeyStatus(sessionId, infoMap);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800367}
368
369status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
370 Mutex::Autolock autoLock(mLock);
371
372 if (mInitCheck != OK) {
373 return mInitCheck;
374 }
375
376 if (mPlugin == NULL) {
377 return -EINVAL;
378 }
379
380 return mPlugin->getProvisionRequest(request, defaultUrl);
381}
382
383status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
384 Mutex::Autolock autoLock(mLock);
385
386 if (mInitCheck != OK) {
387 return mInitCheck;
388 }
389
390 if (mPlugin == NULL) {
391 return -EINVAL;
392 }
393
394 return mPlugin->provideProvisionResponse(response);
395}
396
397
398status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
399 Mutex::Autolock autoLock(mLock);
400
401 if (mInitCheck != OK) {
402 return mInitCheck;
403 }
404
405 if (mPlugin == NULL) {
406 return -EINVAL;
407 }
408
409 return mPlugin->getSecureStops(secureStops);
410}
411
412status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
413 Mutex::Autolock autoLock(mLock);
414
415 if (mInitCheck != OK) {
416 return mInitCheck;
417 }
418
419 if (mPlugin == NULL) {
420 return -EINVAL;
421 }
422
423 return mPlugin->releaseSecureStops(ssRelease);
424}
425
426status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
427 Mutex::Autolock autoLock(mLock);
428
429 if (mInitCheck != OK) {
430 return mInitCheck;
431 }
432
433 if (mPlugin == NULL) {
434 return -EINVAL;
435 }
436
437 return mPlugin->getPropertyString(name, value);
438}
439
440status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
441 Mutex::Autolock autoLock(mLock);
442
443 if (mInitCheck != OK) {
444 return mInitCheck;
445 }
446
447 if (mPlugin == NULL) {
448 return -EINVAL;
449 }
450
451 return mPlugin->getPropertyByteArray(name, value);
452}
453
454status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
455 Mutex::Autolock autoLock(mLock);
456
457 if (mInitCheck != OK) {
458 return mInitCheck;
459 }
460
461 if (mPlugin == NULL) {
462 return -EINVAL;
463 }
464
465 return mPlugin->setPropertyString(name, value);
466}
467
468status_t Drm::setPropertyByteArray(String8 const &name,
469 Vector<uint8_t> const &value ) const {
470 Mutex::Autolock autoLock(mLock);
471
472 if (mInitCheck != OK) {
473 return mInitCheck;
474 }
475
476 if (mPlugin == NULL) {
477 return -EINVAL;
478 }
479
480 return mPlugin->setPropertyByteArray(name, value);
481}
482
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700483
484status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
485 String8 const &algorithm) {
486 Mutex::Autolock autoLock(mLock);
487
488 if (mInitCheck != OK) {
489 return mInitCheck;
490 }
491
492 if (mPlugin == NULL) {
493 return -EINVAL;
494 }
495
496 return mPlugin->setCipherAlgorithm(sessionId, algorithm);
497}
498
499status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
500 String8 const &algorithm) {
501 Mutex::Autolock autoLock(mLock);
502
503 if (mInitCheck != OK) {
504 return mInitCheck;
505 }
506
507 if (mPlugin == NULL) {
508 return -EINVAL;
509 }
510
511 return mPlugin->setMacAlgorithm(sessionId, algorithm);
512}
513
514status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
515 Vector<uint8_t> const &keyId,
516 Vector<uint8_t> const &input,
517 Vector<uint8_t> const &iv,
518 Vector<uint8_t> &output) {
519 Mutex::Autolock autoLock(mLock);
520
521 if (mInitCheck != OK) {
522 return mInitCheck;
523 }
524
525 if (mPlugin == NULL) {
526 return -EINVAL;
527 }
528
529 return mPlugin->encrypt(sessionId, keyId, input, iv, output);
530}
531
532status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
533 Vector<uint8_t> const &keyId,
534 Vector<uint8_t> const &input,
535 Vector<uint8_t> const &iv,
536 Vector<uint8_t> &output) {
537 Mutex::Autolock autoLock(mLock);
538
539 if (mInitCheck != OK) {
540 return mInitCheck;
541 }
542
543 if (mPlugin == NULL) {
544 return -EINVAL;
545 }
546
547 return mPlugin->decrypt(sessionId, keyId, input, iv, output);
548}
549
550status_t Drm::sign(Vector<uint8_t> const &sessionId,
551 Vector<uint8_t> const &keyId,
552 Vector<uint8_t> const &message,
553 Vector<uint8_t> &signature) {
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->sign(sessionId, keyId, message, signature);
565}
566
567status_t Drm::verify(Vector<uint8_t> const &sessionId,
568 Vector<uint8_t> const &keyId,
569 Vector<uint8_t> const &message,
570 Vector<uint8_t> const &signature,
571 bool &match) {
572 Mutex::Autolock autoLock(mLock);
573
574 if (mInitCheck != OK) {
575 return mInitCheck;
576 }
577
578 if (mPlugin == NULL) {
579 return -EINVAL;
580 }
581
582 return mPlugin->verify(sessionId, keyId, message, signature, match);
583}
584
Jeff Tinker3d3f67f2013-07-03 15:38:58 -0700585void Drm::binderDied(const wp<IBinder> &the_late_who)
586{
587 delete mPlugin;
588 mPlugin = NULL;
589 closeFactory();
590 mListener.clear();
591}
592
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800593} // namespace android