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