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 <media/DrmSessionClientInterface.h> 25 #include <media/DrmSessionManager.h> 26 #include <media/Drm.h> 27 #include <media/drm/DrmAPI.h> 28 #include <media/stagefright/foundation/ADebug.h> 29 #include <media/stagefright/foundation/AString.h> 30 #include <media/stagefright/foundation/hexdump.h> 31 #include <media/stagefright/MediaErrors.h> 32 #include <binder/IServiceManager.h> 33 #include <binder/IPCThreadState.h> 34 35 namespace android { 36 37 static inline int getCallingPid() { 38 return IPCThreadState::self()->getCallingPid(); 39 } 40 41 static bool checkPermission(const char* permissionString) { 42 if (getpid() == IPCThreadState::self()->getCallingPid()) return true; 43 bool ok = checkCallingPermission(String16(permissionString)); 44 if (!ok) ALOGE("Request requires %s", permissionString); 45 return ok; 46 } 47 48 KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap; 49 KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap; 50 Mutex Drm::mMapLock; 51 Mutex Drm::mLock; 52 53 static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) { 54 if (lhs.size() < rhs.size()) { 55 return true; 56 } else if (lhs.size() > rhs.size()) { 57 return false; 58 } 59 60 return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0; 61 } 62 63 struct DrmSessionClient : public DrmSessionClientInterface { 64 DrmSessionClient(Drm* drm) : mDrm(drm) {} 65 66 virtual bool reclaimSession(const Vector<uint8_t>& sessionId) { 67 sp<Drm> drm = mDrm.promote(); 68 if (drm == NULL) { 69 return true; 70 } 71 status_t err = drm->closeSession(sessionId); 72 if (err != OK) { 73 return false; 74 } 75 drm->sendEvent(DrmPlugin::kDrmPluginEventSessionReclaimed, 0, &sessionId, NULL); 76 return true; 77 } 78 79 protected: 80 virtual ~DrmSessionClient() {} 81 82 private: 83 wp<Drm> mDrm; 84 85 DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient); 86 }; 87 88 Drm::Drm() 89 : mInitCheck(NO_INIT), 90 mDrmSessionClient(new DrmSessionClient(this)), 91 mListener(NULL), 92 mFactory(NULL), 93 mPlugin(NULL) { 94 } 95 96 Drm::~Drm() { 97 DrmSessionManager::Instance()->removeDrm(mDrmSessionClient); 98 delete mPlugin; 99 mPlugin = NULL; 100 closeFactory(); 101 } 102 103 void Drm::closeFactory() { 104 delete mFactory; 105 mFactory = NULL; 106 mLibrary.clear(); 107 } 108 109 status_t Drm::initCheck() const { 110 return mInitCheck; 111 } 112 113 status_t Drm::setListener(const sp<IDrmClient>& listener) 114 { 115 Mutex::Autolock lock(mEventLock); 116 if (mListener != NULL){ 117 IInterface::asBinder(mListener)->unlinkToDeath(this); 118 } 119 if (listener != NULL) { 120 IInterface::asBinder(listener)->linkToDeath(this); 121 } 122 mListener = listener; 123 return NO_ERROR; 124 } 125 126 void Drm::sendEvent(DrmPlugin::EventType eventType, int extra, 127 Vector<uint8_t> const *sessionId, 128 Vector<uint8_t> const *data) 129 { 130 mEventLock.lock(); 131 sp<IDrmClient> listener = mListener; 132 mEventLock.unlock(); 133 134 if (listener != NULL) { 135 Parcel obj; 136 writeByteArray(obj, sessionId); 137 writeByteArray(obj, data); 138 139 Mutex::Autolock lock(mNotifyLock); 140 listener->notify(eventType, extra, &obj); 141 } 142 } 143 144 void Drm::sendExpirationUpdate(Vector<uint8_t> const *sessionId, 145 int64_t expiryTimeInMS) 146 { 147 mEventLock.lock(); 148 sp<IDrmClient> listener = mListener; 149 mEventLock.unlock(); 150 151 if (listener != NULL) { 152 Parcel obj; 153 writeByteArray(obj, sessionId); 154 obj.writeInt64(expiryTimeInMS); 155 156 Mutex::Autolock lock(mNotifyLock); 157 listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj); 158 } 159 } 160 161 void Drm::sendKeysChange(Vector<uint8_t> const *sessionId, 162 Vector<DrmPlugin::KeyStatus> const *keyStatusList, 163 bool hasNewUsableKey) 164 { 165 mEventLock.lock(); 166 sp<IDrmClient> listener = mListener; 167 mEventLock.unlock(); 168 169 if (listener != NULL) { 170 Parcel obj; 171 writeByteArray(obj, sessionId); 172 173 size_t nkeys = keyStatusList->size(); 174 obj.writeInt32(keyStatusList->size()); 175 for (size_t i = 0; i < nkeys; ++i) { 176 const DrmPlugin::KeyStatus *keyStatus = &keyStatusList->itemAt(i); 177 writeByteArray(obj, &keyStatus->mKeyId); 178 obj.writeInt32(keyStatus->mType); 179 } 180 obj.writeInt32(hasNewUsableKey); 181 182 Mutex::Autolock lock(mNotifyLock); 183 listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj); 184 } 185 } 186 187 /* 188 * Search the plugins directory for a plugin that supports the scheme 189 * specified by uuid 190 * 191 * If found: 192 * mLibrary holds a strong pointer to the dlopen'd library 193 * mFactory is set to the library's factory method 194 * mInitCheck is set to OK 195 * 196 * If not found: 197 * mLibrary is cleared and mFactory are set to NULL 198 * mInitCheck is set to an error (!OK) 199 */ 200 void Drm::findFactoryForScheme(const uint8_t uuid[16]) { 201 202 closeFactory(); 203 204 // lock static maps 205 Mutex::Autolock autoLock(mMapLock); 206 207 // first check cache 208 Vector<uint8_t> uuidVector; 209 uuidVector.appendArray(uuid, sizeof(uuid[0]) * 16); 210 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector); 211 if (index >= 0) { 212 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) { 213 mInitCheck = OK; 214 return; 215 } else { 216 ALOGE("Failed to load from cached library path!"); 217 mInitCheck = ERROR_UNSUPPORTED; 218 return; 219 } 220 } 221 222 // no luck, have to search 223 String8 dirPath("/vendor/lib/mediadrm"); 224 DIR* pDir = opendir(dirPath.string()); 225 226 if (pDir == NULL) { 227 mInitCheck = ERROR_UNSUPPORTED; 228 ALOGE("Failed to open plugin directory %s", dirPath.string()); 229 return; 230 } 231 232 233 struct dirent* pEntry; 234 while ((pEntry = readdir(pDir))) { 235 236 String8 pluginPath = dirPath + "/" + pEntry->d_name; 237 238 if (pluginPath.getPathExtension() == ".so") { 239 240 if (loadLibraryForScheme(pluginPath, uuid)) { 241 mUUIDToLibraryPathMap.add(uuidVector, pluginPath); 242 mInitCheck = OK; 243 closedir(pDir); 244 return; 245 } 246 } 247 } 248 249 closedir(pDir); 250 251 ALOGE("Failed to find drm plugin"); 252 mInitCheck = ERROR_UNSUPPORTED; 253 } 254 255 bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { 256 257 // get strong pointer to open shared library 258 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); 259 if (index >= 0) { 260 mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); 261 } else { 262 index = mLibraryPathToOpenLibraryMap.add(path, NULL); 263 } 264 265 if (!mLibrary.get()) { 266 mLibrary = new SharedLibrary(path); 267 if (!*mLibrary) { 268 return false; 269 } 270 271 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); 272 } 273 274 typedef DrmFactory *(*CreateDrmFactoryFunc)(); 275 276 CreateDrmFactoryFunc createDrmFactory = 277 (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory"); 278 279 if (createDrmFactory == NULL || 280 (mFactory = createDrmFactory()) == NULL || 281 !mFactory->isCryptoSchemeSupported(uuid)) { 282 closeFactory(); 283 return false; 284 } 285 return true; 286 } 287 288 bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { 289 290 Mutex::Autolock autoLock(mLock); 291 292 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 293 findFactoryForScheme(uuid); 294 if (mInitCheck != OK) { 295 return false; 296 } 297 } 298 299 if (mimeType != "") { 300 return mFactory->isContentTypeSupported(mimeType); 301 } 302 303 return true; 304 } 305 306 status_t Drm::createPlugin(const uint8_t uuid[16]) { 307 Mutex::Autolock autoLock(mLock); 308 309 if (mPlugin != NULL) { 310 return -EINVAL; 311 } 312 313 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 314 findFactoryForScheme(uuid); 315 } 316 317 if (mInitCheck != OK) { 318 return mInitCheck; 319 } 320 321 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin); 322 mPlugin->setListener(this); 323 return result; 324 } 325 326 status_t Drm::destroyPlugin() { 327 Mutex::Autolock autoLock(mLock); 328 329 if (mInitCheck != OK) { 330 return mInitCheck; 331 } 332 333 if (mPlugin == NULL) { 334 return -EINVAL; 335 } 336 337 delete mPlugin; 338 mPlugin = NULL; 339 340 return OK; 341 } 342 343 status_t Drm::openSession(Vector<uint8_t> &sessionId) { 344 Mutex::Autolock autoLock(mLock); 345 346 if (mInitCheck != OK) { 347 return mInitCheck; 348 } 349 350 if (mPlugin == NULL) { 351 return -EINVAL; 352 } 353 354 status_t err = mPlugin->openSession(sessionId); 355 if (err == ERROR_DRM_RESOURCE_BUSY) { 356 bool retry = false; 357 mLock.unlock(); 358 // reclaimSession may call back to closeSession, since mLock is shared between Drm 359 // instances, we should unlock here to avoid deadlock. 360 retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid()); 361 mLock.lock(); 362 if (mInitCheck != OK) { 363 return mInitCheck; 364 } 365 366 if (mPlugin == NULL) { 367 return -EINVAL; 368 } 369 if (retry) { 370 err = mPlugin->openSession(sessionId); 371 } 372 } 373 if (err == OK) { 374 DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId); 375 } 376 return err; 377 } 378 379 status_t Drm::closeSession(Vector<uint8_t> const &sessionId) { 380 Mutex::Autolock autoLock(mLock); 381 382 if (mInitCheck != OK) { 383 return mInitCheck; 384 } 385 386 if (mPlugin == NULL) { 387 return -EINVAL; 388 } 389 390 status_t err = mPlugin->closeSession(sessionId); 391 if (err == OK) { 392 DrmSessionManager::Instance()->removeSession(sessionId); 393 } 394 return err; 395 } 396 397 status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId, 398 Vector<uint8_t> const &initData, 399 String8 const &mimeType, DrmPlugin::KeyType keyType, 400 KeyedVector<String8, String8> const &optionalParameters, 401 Vector<uint8_t> &request, String8 &defaultUrl, 402 DrmPlugin::KeyRequestType *keyRequestType) { 403 Mutex::Autolock autoLock(mLock); 404 405 if (mInitCheck != OK) { 406 return mInitCheck; 407 } 408 409 if (mPlugin == NULL) { 410 return -EINVAL; 411 } 412 413 DrmSessionManager::Instance()->useSession(sessionId); 414 415 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, 416 optionalParameters, request, defaultUrl, 417 keyRequestType); 418 } 419 420 status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId, 421 Vector<uint8_t> const &response, 422 Vector<uint8_t> &keySetId) { 423 Mutex::Autolock autoLock(mLock); 424 425 if (mInitCheck != OK) { 426 return mInitCheck; 427 } 428 429 if (mPlugin == NULL) { 430 return -EINVAL; 431 } 432 433 DrmSessionManager::Instance()->useSession(sessionId); 434 435 return mPlugin->provideKeyResponse(sessionId, response, keySetId); 436 } 437 438 status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) { 439 Mutex::Autolock autoLock(mLock); 440 441 if (mInitCheck != OK) { 442 return mInitCheck; 443 } 444 445 if (mPlugin == NULL) { 446 return -EINVAL; 447 } 448 449 return mPlugin->removeKeys(keySetId); 450 } 451 452 status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId, 453 Vector<uint8_t> const &keySetId) { 454 Mutex::Autolock autoLock(mLock); 455 456 if (mInitCheck != OK) { 457 return mInitCheck; 458 } 459 460 if (mPlugin == NULL) { 461 return -EINVAL; 462 } 463 464 DrmSessionManager::Instance()->useSession(sessionId); 465 466 return mPlugin->restoreKeys(sessionId, keySetId); 467 } 468 469 status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, 470 KeyedVector<String8, String8> &infoMap) const { 471 Mutex::Autolock autoLock(mLock); 472 473 if (mInitCheck != OK) { 474 return mInitCheck; 475 } 476 477 if (mPlugin == NULL) { 478 return -EINVAL; 479 } 480 481 DrmSessionManager::Instance()->useSession(sessionId); 482 483 return mPlugin->queryKeyStatus(sessionId, infoMap); 484 } 485 486 status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority, 487 Vector<uint8_t> &request, String8 &defaultUrl) { 488 Mutex::Autolock autoLock(mLock); 489 490 if (mInitCheck != OK) { 491 return mInitCheck; 492 } 493 494 if (mPlugin == NULL) { 495 return -EINVAL; 496 } 497 498 return mPlugin->getProvisionRequest(certType, certAuthority, 499 request, defaultUrl); 500 } 501 502 status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response, 503 Vector<uint8_t> &certificate, 504 Vector<uint8_t> &wrappedKey) { 505 Mutex::Autolock autoLock(mLock); 506 507 if (mInitCheck != OK) { 508 return mInitCheck; 509 } 510 511 if (mPlugin == NULL) { 512 return -EINVAL; 513 } 514 515 return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); 516 } 517 518 status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { 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->getSecureStops(secureStops); 530 } 531 532 status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) { 533 Mutex::Autolock autoLock(mLock); 534 535 if (mInitCheck != OK) { 536 return mInitCheck; 537 } 538 539 if (mPlugin == NULL) { 540 return -EINVAL; 541 } 542 543 return mPlugin->getSecureStop(ssid, secureStop); 544 } 545 546 status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) { 547 Mutex::Autolock autoLock(mLock); 548 549 if (mInitCheck != OK) { 550 return mInitCheck; 551 } 552 553 if (mPlugin == NULL) { 554 return -EINVAL; 555 } 556 557 return mPlugin->releaseSecureStops(ssRelease); 558 } 559 560 status_t Drm::releaseAllSecureStops() { 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->releaseAllSecureStops(); 572 } 573 574 status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { 575 Mutex::Autolock autoLock(mLock); 576 577 if (mInitCheck != OK) { 578 return mInitCheck; 579 } 580 581 if (mPlugin == NULL) { 582 return -EINVAL; 583 } 584 585 return mPlugin->getPropertyString(name, value); 586 } 587 588 status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { 589 Mutex::Autolock autoLock(mLock); 590 591 if (mInitCheck != OK) { 592 return mInitCheck; 593 } 594 595 if (mPlugin == NULL) { 596 return -EINVAL; 597 } 598 599 return mPlugin->getPropertyByteArray(name, value); 600 } 601 602 status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { 603 Mutex::Autolock autoLock(mLock); 604 605 if (mInitCheck != OK) { 606 return mInitCheck; 607 } 608 609 if (mPlugin == NULL) { 610 return -EINVAL; 611 } 612 613 return mPlugin->setPropertyString(name, value); 614 } 615 616 status_t Drm::setPropertyByteArray(String8 const &name, 617 Vector<uint8_t> const &value ) const { 618 Mutex::Autolock autoLock(mLock); 619 620 if (mInitCheck != OK) { 621 return mInitCheck; 622 } 623 624 if (mPlugin == NULL) { 625 return -EINVAL; 626 } 627 628 return mPlugin->setPropertyByteArray(name, value); 629 } 630 631 632 status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, 633 String8 const &algorithm) { 634 Mutex::Autolock autoLock(mLock); 635 636 if (mInitCheck != OK) { 637 return mInitCheck; 638 } 639 640 if (mPlugin == NULL) { 641 return -EINVAL; 642 } 643 644 DrmSessionManager::Instance()->useSession(sessionId); 645 646 return mPlugin->setCipherAlgorithm(sessionId, algorithm); 647 } 648 649 status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, 650 String8 const &algorithm) { 651 Mutex::Autolock autoLock(mLock); 652 653 if (mInitCheck != OK) { 654 return mInitCheck; 655 } 656 657 if (mPlugin == NULL) { 658 return -EINVAL; 659 } 660 661 DrmSessionManager::Instance()->useSession(sessionId); 662 663 return mPlugin->setMacAlgorithm(sessionId, algorithm); 664 } 665 666 status_t Drm::encrypt(Vector<uint8_t> const &sessionId, 667 Vector<uint8_t> const &keyId, 668 Vector<uint8_t> const &input, 669 Vector<uint8_t> const &iv, 670 Vector<uint8_t> &output) { 671 Mutex::Autolock autoLock(mLock); 672 673 if (mInitCheck != OK) { 674 return mInitCheck; 675 } 676 677 if (mPlugin == NULL) { 678 return -EINVAL; 679 } 680 681 DrmSessionManager::Instance()->useSession(sessionId); 682 683 return mPlugin->encrypt(sessionId, keyId, input, iv, output); 684 } 685 686 status_t Drm::decrypt(Vector<uint8_t> const &sessionId, 687 Vector<uint8_t> const &keyId, 688 Vector<uint8_t> const &input, 689 Vector<uint8_t> const &iv, 690 Vector<uint8_t> &output) { 691 Mutex::Autolock autoLock(mLock); 692 693 if (mInitCheck != OK) { 694 return mInitCheck; 695 } 696 697 if (mPlugin == NULL) { 698 return -EINVAL; 699 } 700 701 DrmSessionManager::Instance()->useSession(sessionId); 702 703 return mPlugin->decrypt(sessionId, keyId, input, iv, output); 704 } 705 706 status_t Drm::sign(Vector<uint8_t> const &sessionId, 707 Vector<uint8_t> const &keyId, 708 Vector<uint8_t> const &message, 709 Vector<uint8_t> &signature) { 710 Mutex::Autolock autoLock(mLock); 711 712 if (mInitCheck != OK) { 713 return mInitCheck; 714 } 715 716 if (mPlugin == NULL) { 717 return -EINVAL; 718 } 719 720 DrmSessionManager::Instance()->useSession(sessionId); 721 722 return mPlugin->sign(sessionId, keyId, message, signature); 723 } 724 725 status_t Drm::verify(Vector<uint8_t> const &sessionId, 726 Vector<uint8_t> const &keyId, 727 Vector<uint8_t> const &message, 728 Vector<uint8_t> const &signature, 729 bool &match) { 730 Mutex::Autolock autoLock(mLock); 731 732 if (mInitCheck != OK) { 733 return mInitCheck; 734 } 735 736 if (mPlugin == NULL) { 737 return -EINVAL; 738 } 739 740 DrmSessionManager::Instance()->useSession(sessionId); 741 742 return mPlugin->verify(sessionId, keyId, message, signature, match); 743 } 744 745 status_t Drm::signRSA(Vector<uint8_t> const &sessionId, 746 String8 const &algorithm, 747 Vector<uint8_t> const &message, 748 Vector<uint8_t> const &wrappedKey, 749 Vector<uint8_t> &signature) { 750 Mutex::Autolock autoLock(mLock); 751 752 if (mInitCheck != OK) { 753 return mInitCheck; 754 } 755 756 if (mPlugin == NULL) { 757 return -EINVAL; 758 } 759 760 if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) { 761 return -EPERM; 762 } 763 764 DrmSessionManager::Instance()->useSession(sessionId); 765 766 return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); 767 } 768 769 void Drm::binderDied(const wp<IBinder> &the_late_who __unused) 770 { 771 mEventLock.lock(); 772 mListener.clear(); 773 mEventLock.unlock(); 774 775 Mutex::Autolock autoLock(mLock); 776 delete mPlugin; 777 mPlugin = NULL; 778 closeFactory(); 779 } 780 781 void Drm::writeByteArray(Parcel &obj, Vector<uint8_t> const *array) 782 { 783 if (array && array->size()) { 784 obj.writeInt32(array->size()); 785 obj.write(array->array(), array->size()); 786 } else { 787 obj.writeInt32(0); 788 } 789 } 790 791 } // namespace android 792