Drm.cpp revision 68d9d71a792deed75d32fe13febc07c9c12c8449
1/* 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 mListener(NULL), 51 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 71status_t Drm::setListener(const sp<IDrmClient>& listener) 72{ 73 Mutex::Autolock lock(mEventLock); 74 if (mListener != NULL){ 75 mListener->asBinder()->unlinkToDeath(this); 76 } 77 if (listener != NULL) { 78 listener->asBinder()->linkToDeath(this); 79 } 80 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} 112 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], const String8 &mimeType) { 215 216 Mutex::Autolock autoLock(mLock); 217 218 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 219 findFactoryForScheme(uuid); 220 if (mInitCheck != OK) { 221 return false; 222 } 223 } 224 225 if (mimeType != "") { 226 return mFactory->isContentTypeSupported(mimeType); 227 } 228 229 return true; 230} 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 247 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin); 248 mPlugin->setListener(this); 249 return result; 250} 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 297status_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) { 302 Mutex::Autolock autoLock(mLock); 303 304 if (mInitCheck != OK) { 305 return mInitCheck; 306 } 307 308 if (mPlugin == NULL) { 309 return -EINVAL; 310 } 311 312 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, 313 optionalParameters, request, defaultUrl); 314} 315 316status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId, 317 Vector<uint8_t> const &response, 318 Vector<uint8_t> &keySetId) { 319 Mutex::Autolock autoLock(mLock); 320 321 if (mInitCheck != OK) { 322 return mInitCheck; 323 } 324 325 if (mPlugin == NULL) { 326 return -EINVAL; 327 } 328 329 return mPlugin->provideKeyResponse(sessionId, response, keySetId); 330} 331 332status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) { 333 Mutex::Autolock autoLock(mLock); 334 335 if (mInitCheck != OK) { 336 return mInitCheck; 337 } 338 339 if (mPlugin == NULL) { 340 return -EINVAL; 341 } 342 343 return mPlugin->removeKeys(keySetId); 344} 345 346status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId, 347 Vector<uint8_t> const &keySetId) { 348 Mutex::Autolock autoLock(mLock); 349 350 if (mInitCheck != OK) { 351 return mInitCheck; 352 } 353 354 if (mPlugin == NULL) { 355 return -EINVAL; 356 } 357 358 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); 374} 375 376status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority, 377 Vector<uint8_t> &request, String8 &defaultUrl) { 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->getProvisionRequest(certType, certAuthority, 389 request, defaultUrl); 390} 391 392status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response, 393 Vector<uint8_t> &certificate, 394 Vector<uint8_t> &wrappedKey) { 395 Mutex::Autolock autoLock(mLock); 396 397 if (mInitCheck != OK) { 398 return mInitCheck; 399 } 400 401 if (mPlugin == NULL) { 402 return -EINVAL; 403 } 404 405 return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); 406} 407 408 409status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { 410 Mutex::Autolock autoLock(mLock); 411 412 if (mInitCheck != OK) { 413 return mInitCheck; 414 } 415 416 if (mPlugin == NULL) { 417 return -EINVAL; 418 } 419 420 return mPlugin->getSecureStops(secureStops); 421} 422 423status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) { 424 Mutex::Autolock autoLock(mLock); 425 426 if (mInitCheck != OK) { 427 return mInitCheck; 428 } 429 430 if (mPlugin == NULL) { 431 return -EINVAL; 432 } 433 434 return mPlugin->releaseSecureStops(ssRelease); 435} 436 437status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { 438 Mutex::Autolock autoLock(mLock); 439 440 if (mInitCheck != OK) { 441 return mInitCheck; 442 } 443 444 if (mPlugin == NULL) { 445 return -EINVAL; 446 } 447 448 return mPlugin->getPropertyString(name, value); 449} 450 451status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { 452 Mutex::Autolock autoLock(mLock); 453 454 if (mInitCheck != OK) { 455 return mInitCheck; 456 } 457 458 if (mPlugin == NULL) { 459 return -EINVAL; 460 } 461 462 return mPlugin->getPropertyByteArray(name, value); 463} 464 465status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { 466 Mutex::Autolock autoLock(mLock); 467 468 if (mInitCheck != OK) { 469 return mInitCheck; 470 } 471 472 if (mPlugin == NULL) { 473 return -EINVAL; 474 } 475 476 return mPlugin->setPropertyString(name, value); 477} 478 479status_t Drm::setPropertyByteArray(String8 const &name, 480 Vector<uint8_t> const &value ) const { 481 Mutex::Autolock autoLock(mLock); 482 483 if (mInitCheck != OK) { 484 return mInitCheck; 485 } 486 487 if (mPlugin == NULL) { 488 return -EINVAL; 489 } 490 491 return mPlugin->setPropertyByteArray(name, value); 492} 493 494 495status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, 496 String8 const &algorithm) { 497 Mutex::Autolock autoLock(mLock); 498 499 if (mInitCheck != OK) { 500 return mInitCheck; 501 } 502 503 if (mPlugin == NULL) { 504 return -EINVAL; 505 } 506 507 return mPlugin->setCipherAlgorithm(sessionId, algorithm); 508} 509 510status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, 511 String8 const &algorithm) { 512 Mutex::Autolock autoLock(mLock); 513 514 if (mInitCheck != OK) { 515 return mInitCheck; 516 } 517 518 if (mPlugin == NULL) { 519 return -EINVAL; 520 } 521 522 return mPlugin->setMacAlgorithm(sessionId, algorithm); 523} 524 525status_t Drm::encrypt(Vector<uint8_t> const &sessionId, 526 Vector<uint8_t> const &keyId, 527 Vector<uint8_t> const &input, 528 Vector<uint8_t> const &iv, 529 Vector<uint8_t> &output) { 530 Mutex::Autolock autoLock(mLock); 531 532 if (mInitCheck != OK) { 533 return mInitCheck; 534 } 535 536 if (mPlugin == NULL) { 537 return -EINVAL; 538 } 539 540 return mPlugin->encrypt(sessionId, keyId, input, iv, output); 541} 542 543status_t Drm::decrypt(Vector<uint8_t> const &sessionId, 544 Vector<uint8_t> const &keyId, 545 Vector<uint8_t> const &input, 546 Vector<uint8_t> const &iv, 547 Vector<uint8_t> &output) { 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->decrypt(sessionId, keyId, input, iv, output); 559} 560 561status_t Drm::sign(Vector<uint8_t> const &sessionId, 562 Vector<uint8_t> const &keyId, 563 Vector<uint8_t> const &message, 564 Vector<uint8_t> &signature) { 565 Mutex::Autolock autoLock(mLock); 566 567 if (mInitCheck != OK) { 568 return mInitCheck; 569 } 570 571 if (mPlugin == NULL) { 572 return -EINVAL; 573 } 574 575 return mPlugin->sign(sessionId, keyId, message, signature); 576} 577 578status_t Drm::verify(Vector<uint8_t> const &sessionId, 579 Vector<uint8_t> const &keyId, 580 Vector<uint8_t> const &message, 581 Vector<uint8_t> const &signature, 582 bool &match) { 583 Mutex::Autolock autoLock(mLock); 584 585 if (mInitCheck != OK) { 586 return mInitCheck; 587 } 588 589 if (mPlugin == NULL) { 590 return -EINVAL; 591 } 592 593 return mPlugin->verify(sessionId, keyId, message, signature, match); 594} 595 596status_t Drm::signRSA(Vector<uint8_t> const &sessionId, 597 String8 const &algorithm, 598 Vector<uint8_t> const &message, 599 Vector<uint8_t> const &wrappedKey, 600 Vector<uint8_t> &signature) { 601 Mutex::Autolock autoLock(mLock); 602 603 if (mInitCheck != OK) { 604 return mInitCheck; 605 } 606 607 if (mPlugin == NULL) { 608 return -EINVAL; 609 } 610 611 return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); 612} 613 614void Drm::binderDied(const wp<IBinder> &the_late_who) 615{ 616 delete mPlugin; 617 mPlugin = NULL; 618 closeFactory(); 619 mListener.clear(); 620} 621 622} // namespace android 623