blob: 5fdb9f42bdafb1eb214849379427f62f16965d23 [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),
50 mFactory(NULL),
51 mPlugin(NULL) {
52}
53
54Drm::~Drm() {
55 delete mPlugin;
56 mPlugin = NULL;
57 closeFactory();
58}
59
60void Drm::closeFactory() {
61 delete mFactory;
62 mFactory = NULL;
63 mLibrary.clear();
64}
65
66status_t Drm::initCheck() const {
67 return mInitCheck;
68}
69
70
71/*
72 * Search the plugins directory for a plugin that supports the scheme
73 * specified by uuid
74 *
75 * If found:
76 * mLibrary holds a strong pointer to the dlopen'd library
77 * mFactory is set to the library's factory method
78 * mInitCheck is set to OK
79 *
80 * If not found:
81 * mLibrary is cleared and mFactory are set to NULL
82 * mInitCheck is set to an error (!OK)
83 */
84void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
85
86 closeFactory();
87
88 // lock static maps
89 Mutex::Autolock autoLock(mMapLock);
90
91 // first check cache
92 Vector<uint8_t> uuidVector;
93 uuidVector.appendArray(uuid, sizeof(uuid));
94 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
95 if (index >= 0) {
96 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
97 mInitCheck = OK;
98 return;
99 } else {
100 ALOGE("Failed to load from cached library path!");
101 mInitCheck = ERROR_UNSUPPORTED;
102 return;
103 }
104 }
105
106 // no luck, have to search
107 String8 dirPath("/vendor/lib/mediadrm");
108 DIR* pDir = opendir(dirPath.string());
109
110 if (pDir == NULL) {
111 mInitCheck = ERROR_UNSUPPORTED;
112 ALOGE("Failed to open plugin directory %s", dirPath.string());
113 return;
114 }
115
116
117 struct dirent* pEntry;
118 while ((pEntry = readdir(pDir))) {
119
120 String8 pluginPath = dirPath + "/" + pEntry->d_name;
121
122 if (pluginPath.getPathExtension() == ".so") {
123
124 if (loadLibraryForScheme(pluginPath, uuid)) {
125 mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
126 mInitCheck = OK;
127 closedir(pDir);
128 return;
129 }
130 }
131 }
132
133 closedir(pDir);
134
135 ALOGE("Failed to find drm plugin");
136 mInitCheck = ERROR_UNSUPPORTED;
137}
138
139bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
140
141 // get strong pointer to open shared library
142 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
143 if (index >= 0) {
144 mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
145 } else {
146 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
147 }
148
149 if (!mLibrary.get()) {
150 mLibrary = new SharedLibrary(path);
151 if (!*mLibrary) {
152 return false;
153 }
154
155 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
156 }
157
158 typedef DrmFactory *(*CreateDrmFactoryFunc)();
159
160 CreateDrmFactoryFunc createDrmFactory =
161 (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
162
163 if (createDrmFactory == NULL ||
164 (mFactory = createDrmFactory()) == NULL ||
165 !mFactory->isCryptoSchemeSupported(uuid)) {
166 closeFactory();
167 return false;
168 }
169 return true;
170}
171
172bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) {
173 Mutex::Autolock autoLock(mLock);
174
175 if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
176 return true;
177 }
178
179 findFactoryForScheme(uuid);
180 return (mInitCheck == OK);
181}
182
183status_t Drm::createPlugin(const uint8_t uuid[16]) {
184 Mutex::Autolock autoLock(mLock);
185
186 if (mPlugin != NULL) {
187 return -EINVAL;
188 }
189
190 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
191 findFactoryForScheme(uuid);
192 }
193
194 if (mInitCheck != OK) {
195 return mInitCheck;
196 }
197
198 return mFactory->createDrmPlugin(uuid, &mPlugin);
199}
200
201status_t Drm::destroyPlugin() {
202 Mutex::Autolock autoLock(mLock);
203
204 if (mInitCheck != OK) {
205 return mInitCheck;
206 }
207
208 if (mPlugin == NULL) {
209 return -EINVAL;
210 }
211
212 delete mPlugin;
213 mPlugin = NULL;
214
215 return OK;
216}
217
218status_t Drm::openSession(Vector<uint8_t> &sessionId) {
219 Mutex::Autolock autoLock(mLock);
220
221 if (mInitCheck != OK) {
222 return mInitCheck;
223 }
224
225 if (mPlugin == NULL) {
226 return -EINVAL;
227 }
228
229 return mPlugin->openSession(sessionId);
230}
231
232status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
233 Mutex::Autolock autoLock(mLock);
234
235 if (mInitCheck != OK) {
236 return mInitCheck;
237 }
238
239 if (mPlugin == NULL) {
240 return -EINVAL;
241 }
242
243 return mPlugin->closeSession(sessionId);
244}
245
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700246status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
247 Vector<uint8_t> const &initData,
248 String8 const &mimeType, DrmPlugin::KeyType keyType,
249 KeyedVector<String8, String8> const &optionalParameters,
250 Vector<uint8_t> &request, String8 &defaultUrl) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800251 Mutex::Autolock autoLock(mLock);
252
253 if (mInitCheck != OK) {
254 return mInitCheck;
255 }
256
257 if (mPlugin == NULL) {
258 return -EINVAL;
259 }
260
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700261 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
262 optionalParameters, request, defaultUrl);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800263}
264
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700265status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
266 Vector<uint8_t> const &response,
267 Vector<uint8_t> &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800268 Mutex::Autolock autoLock(mLock);
269
270 if (mInitCheck != OK) {
271 return mInitCheck;
272 }
273
274 if (mPlugin == NULL) {
275 return -EINVAL;
276 }
277
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700278 return mPlugin->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800279}
280
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700281status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800282 Mutex::Autolock autoLock(mLock);
283
284 if (mInitCheck != OK) {
285 return mInitCheck;
286 }
287
288 if (mPlugin == NULL) {
289 return -EINVAL;
290 }
291
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700292 return mPlugin->removeKeys(keySetId);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800293}
294
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700295status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
296 Vector<uint8_t> const &keySetId) {
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800297 Mutex::Autolock autoLock(mLock);
298
299 if (mInitCheck != OK) {
300 return mInitCheck;
301 }
302
303 if (mPlugin == NULL) {
304 return -EINVAL;
305 }
306
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700307 return mPlugin->restoreKeys(sessionId, keySetId);
308}
309
310status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
311 KeyedVector<String8, String8> &infoMap) const {
312 Mutex::Autolock autoLock(mLock);
313
314 if (mInitCheck != OK) {
315 return mInitCheck;
316 }
317
318 if (mPlugin == NULL) {
319 return -EINVAL;
320 }
321
322 return mPlugin->queryKeyStatus(sessionId, infoMap);
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800323}
324
325status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
326 Mutex::Autolock autoLock(mLock);
327
328 if (mInitCheck != OK) {
329 return mInitCheck;
330 }
331
332 if (mPlugin == NULL) {
333 return -EINVAL;
334 }
335
336 return mPlugin->getProvisionRequest(request, defaultUrl);
337}
338
339status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
340 Mutex::Autolock autoLock(mLock);
341
342 if (mInitCheck != OK) {
343 return mInitCheck;
344 }
345
346 if (mPlugin == NULL) {
347 return -EINVAL;
348 }
349
350 return mPlugin->provideProvisionResponse(response);
351}
352
353
354status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
355 Mutex::Autolock autoLock(mLock);
356
357 if (mInitCheck != OK) {
358 return mInitCheck;
359 }
360
361 if (mPlugin == NULL) {
362 return -EINVAL;
363 }
364
365 return mPlugin->getSecureStops(secureStops);
366}
367
368status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
369 Mutex::Autolock autoLock(mLock);
370
371 if (mInitCheck != OK) {
372 return mInitCheck;
373 }
374
375 if (mPlugin == NULL) {
376 return -EINVAL;
377 }
378
379 return mPlugin->releaseSecureStops(ssRelease);
380}
381
382status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
383 Mutex::Autolock autoLock(mLock);
384
385 if (mInitCheck != OK) {
386 return mInitCheck;
387 }
388
389 if (mPlugin == NULL) {
390 return -EINVAL;
391 }
392
393 return mPlugin->getPropertyString(name, value);
394}
395
396status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
397 Mutex::Autolock autoLock(mLock);
398
399 if (mInitCheck != OK) {
400 return mInitCheck;
401 }
402
403 if (mPlugin == NULL) {
404 return -EINVAL;
405 }
406
407 return mPlugin->getPropertyByteArray(name, value);
408}
409
410status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
411 Mutex::Autolock autoLock(mLock);
412
413 if (mInitCheck != OK) {
414 return mInitCheck;
415 }
416
417 if (mPlugin == NULL) {
418 return -EINVAL;
419 }
420
421 return mPlugin->setPropertyString(name, value);
422}
423
424status_t Drm::setPropertyByteArray(String8 const &name,
425 Vector<uint8_t> const &value ) const {
426 Mutex::Autolock autoLock(mLock);
427
428 if (mInitCheck != OK) {
429 return mInitCheck;
430 }
431
432 if (mPlugin == NULL) {
433 return -EINVAL;
434 }
435
436 return mPlugin->setPropertyByteArray(name, value);
437}
438
Jeff Tinker8856c8b2013-03-30 16:19:44 -0700439
440status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
441 String8 const &algorithm) {
442 Mutex::Autolock autoLock(mLock);
443
444 if (mInitCheck != OK) {
445 return mInitCheck;
446 }
447
448 if (mPlugin == NULL) {
449 return -EINVAL;
450 }
451
452 return mPlugin->setCipherAlgorithm(sessionId, algorithm);
453}
454
455status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
456 String8 const &algorithm) {
457 Mutex::Autolock autoLock(mLock);
458
459 if (mInitCheck != OK) {
460 return mInitCheck;
461 }
462
463 if (mPlugin == NULL) {
464 return -EINVAL;
465 }
466
467 return mPlugin->setMacAlgorithm(sessionId, algorithm);
468}
469
470status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
471 Vector<uint8_t> const &keyId,
472 Vector<uint8_t> const &input,
473 Vector<uint8_t> const &iv,
474 Vector<uint8_t> &output) {
475 Mutex::Autolock autoLock(mLock);
476
477 if (mInitCheck != OK) {
478 return mInitCheck;
479 }
480
481 if (mPlugin == NULL) {
482 return -EINVAL;
483 }
484
485 return mPlugin->encrypt(sessionId, keyId, input, iv, output);
486}
487
488status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
489 Vector<uint8_t> const &keyId,
490 Vector<uint8_t> const &input,
491 Vector<uint8_t> const &iv,
492 Vector<uint8_t> &output) {
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->decrypt(sessionId, keyId, input, iv, output);
504}
505
506status_t Drm::sign(Vector<uint8_t> const &sessionId,
507 Vector<uint8_t> const &keyId,
508 Vector<uint8_t> const &message,
509 Vector<uint8_t> &signature) {
510 Mutex::Autolock autoLock(mLock);
511
512 if (mInitCheck != OK) {
513 return mInitCheck;
514 }
515
516 if (mPlugin == NULL) {
517 return -EINVAL;
518 }
519
520 return mPlugin->sign(sessionId, keyId, message, signature);
521}
522
523status_t Drm::verify(Vector<uint8_t> const &sessionId,
524 Vector<uint8_t> const &keyId,
525 Vector<uint8_t> const &message,
526 Vector<uint8_t> const &signature,
527 bool &match) {
528 Mutex::Autolock autoLock(mLock);
529
530 if (mInitCheck != OK) {
531 return mInitCheck;
532 }
533
534 if (mPlugin == NULL) {
535 return -EINVAL;
536 }
537
538 return mPlugin->verify(sessionId, keyId, message, signature, match);
539}
540
Jeff Tinkercc82dc62013-02-08 10:18:35 -0800541} // namespace android