blob: 1e6cd94c5d0f78edb221d247aa679bb3accea99e [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);
74 mListener = listener;
75 return NO_ERROR;
76}
77
78void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
79 Vector<uint8_t> const *sessionId,
80 Vector<uint8_t> const *data)
81{
82 mEventLock.lock();
83 sp<IDrmClient> listener = mListener;
84 mEventLock.unlock();
85
86 if (listener != NULL) {
87 Parcel obj;
88 if (sessionId && sessionId->size()) {
89 obj.writeInt32(sessionId->size());
90 obj.write(sessionId->array(), sessionId->size());
91 } else {
92 obj.writeInt32(0);
93 }
94
95 if (data && data->size()) {
96 obj.writeInt32(data->size());
97 obj.write(data->array(), data->size());
98 } else {
99 obj.writeInt32(0);
100 }
101
102 Mutex::Autolock lock(mNotifyLock);
103 listener->notify(eventType, extra, &obj);
104 }
105}
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800106
107/*
108 * Search the plugins directory for a plugin that supports the scheme
109 * specified by uuid
110 *
111 * If found:
112 * mLibrary holds a strong pointer to the dlopen'd library
113 * mFactory is set to the library's factory method
114 * mInitCheck is set to OK
115 *
116 * If not found:
117 * mLibrary is cleared and mFactory are set to NULL
118 * mInitCheck is set to an error (!OK)
119 */
120void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
121
122 closeFactory();
123
124 // lock static maps
125 Mutex::Autolock autoLock(mMapLock);
126
127 // first check cache
128 Vector<uint8_t> uuidVector;
129 uuidVector.appendArray(uuid, sizeof(uuid));
130 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
131 if (index >= 0) {
132 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
133 mInitCheck = OK;
134 return;
135 } else {
136 ALOGE("Failed to load from cached library path!");
137 mInitCheck = ERROR_UNSUPPORTED;
138 return;
139 }
140 }
141
142 // no luck, have to search
143 String8 dirPath("/vendor/lib/mediadrm");
144 DIR* pDir = opendir(dirPath.string());
145
146 if (pDir == NULL) {
147 mInitCheck = ERROR_UNSUPPORTED;
148 ALOGE("Failed to open plugin directory %s", dirPath.string());
149 return;
150 }
151
152
153 struct dirent* pEntry;
154 while ((pEntry = readdir(pDir))) {
155
156 String8 pluginPath = dirPath + "/" + pEntry->d_name;
157
158 if (pluginPath.getPathExtension() == ".so") {
159
160 if (loadLibraryForScheme(pluginPath, uuid)) {
161 mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
162 mInitCheck = OK;
163 closedir(pDir);
164 return;
165 }
166 }
167 }
168
169 closedir(pDir);
170
171 ALOGE("Failed to find drm plugin");
172 mInitCheck = ERROR_UNSUPPORTED;
173}
174
175bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
176
177 // get strong pointer to open shared library
178 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
179 if (index >= 0) {
180 mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
181 } else {
182 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
183 }
184
185 if (!mLibrary.get()) {
186 mLibrary = new SharedLibrary(path);
187 if (!*mLibrary) {
188 return false;
189 }
190
191 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
192 }
193
194 typedef DrmFactory *(*CreateDrmFactoryFunc)();
195
196 CreateDrmFactoryFunc createDrmFactory =
197 (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
198
199 if (createDrmFactory == NULL ||
200 (mFactory = createDrmFactory()) == NULL ||
201 !mFactory->isCryptoSchemeSupported(uuid)) {
202 closeFactory();
203 return false;
204 }
205 return true;
206}
207
208bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) {
209 Mutex::Autolock autoLock(mLock);
210
211 if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
212 return true;
213 }
214
215 findFactoryForScheme(uuid);
216 return (mInitCheck == OK);
217}
218
219status_t Drm::createPlugin(const uint8_t uuid[16]) {
220 Mutex::Autolock autoLock(mLock);
221
222 if (mPlugin != NULL) {
223 return -EINVAL;
224 }
225
226 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
227 findFactoryForScheme(uuid);
228 }
229
230 if (mInitCheck != OK) {
231 return mInitCheck;
232 }
233
Jeff Tinker0cb126a2013-04-02 13:08:05 -0700234 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
235 mPlugin->setListener(this);
236 return result;
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800237}
238
239status_t Drm::destroyPlugin() {
240 Mutex::Autolock autoLock(mLock);
241
242 if (mInitCheck != OK) {
243 return mInitCheck;
244 }
245
246 if (mPlugin == NULL) {
247 return -EINVAL;
248 }
249
250 delete mPlugin;
251 mPlugin = NULL;
252
253 return OK;
254}
255
256status_t Drm::openSession(Vector<uint8_t> &sessionId) {
257 Mutex::Autolock autoLock(mLock);
258
259 if (mInitCheck != OK) {
260 return mInitCheck;
261 }
262
263 if (mPlugin == NULL) {
264 return -EINVAL;
265 }
266
267 return mPlugin->openSession(sessionId);
268}
269
270status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
271 Mutex::Autolock autoLock(mLock);
272
273 if (mInitCheck != OK) {
274 return mInitCheck;
275 }
276
277 if (mPlugin == NULL) {
278 return -EINVAL;
279 }
280
281 return mPlugin->closeSession(sessionId);
282}
283
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700284status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
285 Vector<uint8_t> const &initData,
286 String8 const &mimeType, DrmPlugin::KeyType keyType,
287 KeyedVector<String8, String8> const &optionalParameters,
288 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800289 Mutex::Autolock autoLock(mLock);
290
291 if (mInitCheck != OK) {
292 return mInitCheck;
293 }
294
295 if (mPlugin == NULL) {
296 return -EINVAL;
297 }
298
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700299 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
300 optionalParameters, request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800301}
302
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700303status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
304 Vector<uint8_t> const &response,
305 Vector<uint8_t> &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800306 Mutex::Autolock autoLock(mLock);
307
308 if (mInitCheck != OK) {
309 return mInitCheck;
310 }
311
312 if (mPlugin == NULL) {
313 return -EINVAL;
314 }
315
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700316 return mPlugin->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800317}
318
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700319status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800320 Mutex::Autolock autoLock(mLock);
321
322 if (mInitCheck != OK) {
323 return mInitCheck;
324 }
325
326 if (mPlugin == NULL) {
327 return -EINVAL;
328 }
329
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700330 return mPlugin->removeKeys(keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800331}
332
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700333status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
334 Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800335 Mutex::Autolock autoLock(mLock);
336
337 if (mInitCheck != OK) {
338 return mInitCheck;
339 }
340
341 if (mPlugin == NULL) {
342 return -EINVAL;
343 }
344
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700345 return mPlugin->restoreKeys(sessionId, keySetId);
346}
347
348status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
349 KeyedVector<String8, String8> &infoMap) const {
350 Mutex::Autolock autoLock(mLock);
351
352 if (mInitCheck != OK) {
353 return mInitCheck;
354 }
355
356 if (mPlugin == NULL) {
357 return -EINVAL;
358 }
359
360 return mPlugin->queryKeyStatus(sessionId, infoMap);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800361}
362
363status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
364 Mutex::Autolock autoLock(mLock);
365
366 if (mInitCheck != OK) {
367 return mInitCheck;
368 }
369
370 if (mPlugin == NULL) {
371 return -EINVAL;
372 }
373
374 return mPlugin->getProvisionRequest(request, defaultUrl);
375}
376
377status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
378 Mutex::Autolock autoLock(mLock);
379
380 if (mInitCheck != OK) {
381 return mInitCheck;
382 }
383
384 if (mPlugin == NULL) {
385 return -EINVAL;
386 }
387
388 return mPlugin->provideProvisionResponse(response);
389}
390
391
392status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
393 Mutex::Autolock autoLock(mLock);
394
395 if (mInitCheck != OK) {
396 return mInitCheck;
397 }
398
399 if (mPlugin == NULL) {
400 return -EINVAL;
401 }
402
403 return mPlugin->getSecureStops(secureStops);
404}
405
406status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
407 Mutex::Autolock autoLock(mLock);
408
409 if (mInitCheck != OK) {
410 return mInitCheck;
411 }
412
413 if (mPlugin == NULL) {
414 return -EINVAL;
415 }
416
417 return mPlugin->releaseSecureStops(ssRelease);
418}
419
420status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
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 return mPlugin->getPropertyString(name, value);
432}
433
434status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
435 Mutex::Autolock autoLock(mLock);
436
437 if (mInitCheck != OK) {
438 return mInitCheck;
439 }
440
441 if (mPlugin == NULL) {
442 return -EINVAL;
443 }
444
445 return mPlugin->getPropertyByteArray(name, value);
446}
447
448status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
449 Mutex::Autolock autoLock(mLock);
450
451 if (mInitCheck != OK) {
452 return mInitCheck;
453 }
454
455 if (mPlugin == NULL) {
456 return -EINVAL;
457 }
458
459 return mPlugin->setPropertyString(name, value);
460}
461
462status_t Drm::setPropertyByteArray(String8 const &name,
463 Vector<uint8_t> const &value ) const {
464 Mutex::Autolock autoLock(mLock);
465
466 if (mInitCheck != OK) {
467 return mInitCheck;
468 }
469
470 if (mPlugin == NULL) {
471 return -EINVAL;
472 }
473
474 return mPlugin->setPropertyByteArray(name, value);
475}
476
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700477
478status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
479 String8 const &algorithm) {
480 Mutex::Autolock autoLock(mLock);
481
482 if (mInitCheck != OK) {
483 return mInitCheck;
484 }
485
486 if (mPlugin == NULL) {
487 return -EINVAL;
488 }
489
490 return mPlugin->setCipherAlgorithm(sessionId, algorithm);
491}
492
493status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
494 String8 const &algorithm) {
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->setMacAlgorithm(sessionId, algorithm);
506}
507
508status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
509 Vector<uint8_t> const &keyId,
510 Vector<uint8_t> const &input,
511 Vector<uint8_t> const &iv,
512 Vector<uint8_t> &output) {
513 Mutex::Autolock autoLock(mLock);
514
515 if (mInitCheck != OK) {
516 return mInitCheck;
517 }
518
519 if (mPlugin == NULL) {
520 return -EINVAL;
521 }
522
523 return mPlugin->encrypt(sessionId, keyId, input, iv, output);
524}
525
526status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
527 Vector<uint8_t> const &keyId,
528 Vector<uint8_t> const &input,
529 Vector<uint8_t> const &iv,
530 Vector<uint8_t> &output) {
531 Mutex::Autolock autoLock(mLock);
532
533 if (mInitCheck != OK) {
534 return mInitCheck;
535 }
536
537 if (mPlugin == NULL) {
538 return -EINVAL;
539 }
540
541 return mPlugin->decrypt(sessionId, keyId, input, iv, output);
542}
543
544status_t Drm::sign(Vector<uint8_t> const &sessionId,
545 Vector<uint8_t> const &keyId,
546 Vector<uint8_t> const &message,
547 Vector<uint8_t> &signature) {
548 Mutex::Autolock autoLock(mLock);
549
550 if (mInitCheck != OK) {
551 return mInitCheck;
552 }
553
554 if (mPlugin == NULL) {
555 return -EINVAL;
556 }
557
558 return mPlugin->sign(sessionId, keyId, message, signature);
559}
560
561status_t Drm::verify(Vector<uint8_t> const &sessionId,
562 Vector<uint8_t> const &keyId,
563 Vector<uint8_t> const &message,
564 Vector<uint8_t> const &signature,
565 bool &match) {
566 Mutex::Autolock autoLock(mLock);
567
568 if (mInitCheck != OK) {
569 return mInitCheck;
570 }
571
572 if (mPlugin == NULL) {
573 return -EINVAL;
574 }
575
576 return mPlugin->verify(sessionId, keyId, message, signature, match);
577}
578
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800579} // namespace android