Drm.cpp revision 2fb561a6fe9bca79c50a81e90fc4bb4eb18af0be
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 retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid()); 362 if (retry) { 363 err = mPlugin->openSession(sessionId); 364 } 365 } 366 if (err == OK) { 367 DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId); 368 } 369 return err; 370} 371 372status_t Drm::closeSession(Vector<uint8_t> const &sessionId) { 373 Mutex::Autolock autoLock(mLock); 374 375 if (mInitCheck != OK) { 376 return mInitCheck; 377 } 378 379 if (mPlugin == NULL) { 380 return -EINVAL; 381 } 382 383 status_t err = mPlugin->closeSession(sessionId); 384 if (err == OK) { 385 DrmSessionManager::Instance()->removeSession(sessionId); 386 } 387 return err; 388} 389 390status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId, 391 Vector<uint8_t> const &initData, 392 String8 const &mimeType, DrmPlugin::KeyType keyType, 393 KeyedVector<String8, String8> const &optionalParameters, 394 Vector<uint8_t> &request, String8 &defaultUrl, 395 DrmPlugin::KeyRequestType *keyRequestType) { 396 Mutex::Autolock autoLock(mLock); 397 398 if (mInitCheck != OK) { 399 return mInitCheck; 400 } 401 402 if (mPlugin == NULL) { 403 return -EINVAL; 404 } 405 406 DrmSessionManager::Instance()->useSession(sessionId); 407 408 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, 409 optionalParameters, request, defaultUrl, 410 keyRequestType); 411} 412 413status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId, 414 Vector<uint8_t> const &response, 415 Vector<uint8_t> &keySetId) { 416 Mutex::Autolock autoLock(mLock); 417 418 if (mInitCheck != OK) { 419 return mInitCheck; 420 } 421 422 if (mPlugin == NULL) { 423 return -EINVAL; 424 } 425 426 DrmSessionManager::Instance()->useSession(sessionId); 427 428 return mPlugin->provideKeyResponse(sessionId, response, keySetId); 429} 430 431status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) { 432 Mutex::Autolock autoLock(mLock); 433 434 if (mInitCheck != OK) { 435 return mInitCheck; 436 } 437 438 if (mPlugin == NULL) { 439 return -EINVAL; 440 } 441 442 return mPlugin->removeKeys(keySetId); 443} 444 445status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId, 446 Vector<uint8_t> const &keySetId) { 447 Mutex::Autolock autoLock(mLock); 448 449 if (mInitCheck != OK) { 450 return mInitCheck; 451 } 452 453 if (mPlugin == NULL) { 454 return -EINVAL; 455 } 456 457 DrmSessionManager::Instance()->useSession(sessionId); 458 459 return mPlugin->restoreKeys(sessionId, keySetId); 460} 461 462status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, 463 KeyedVector<String8, String8> &infoMap) 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 DrmSessionManager::Instance()->useSession(sessionId); 475 476 return mPlugin->queryKeyStatus(sessionId, infoMap); 477} 478 479status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority, 480 Vector<uint8_t> &request, String8 &defaultUrl) { 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->getProvisionRequest(certType, certAuthority, 492 request, defaultUrl); 493} 494 495status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response, 496 Vector<uint8_t> &certificate, 497 Vector<uint8_t> &wrappedKey) { 498 Mutex::Autolock autoLock(mLock); 499 500 if (mInitCheck != OK) { 501 return mInitCheck; 502 } 503 504 if (mPlugin == NULL) { 505 return -EINVAL; 506 } 507 508 return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); 509} 510 511status_t Drm::unprovisionDevice() { 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 if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) { 523 return -EPERM; 524 } 525 526 return mPlugin->unprovisionDevice(); 527} 528 529status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { 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->getSecureStops(secureStops); 541} 542 543status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) { 544 Mutex::Autolock autoLock(mLock); 545 546 if (mInitCheck != OK) { 547 return mInitCheck; 548 } 549 550 if (mPlugin == NULL) { 551 return -EINVAL; 552 } 553 554 return mPlugin->getSecureStop(ssid, secureStop); 555} 556 557status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) { 558 Mutex::Autolock autoLock(mLock); 559 560 if (mInitCheck != OK) { 561 return mInitCheck; 562 } 563 564 if (mPlugin == NULL) { 565 return -EINVAL; 566 } 567 568 return mPlugin->releaseSecureStops(ssRelease); 569} 570 571status_t Drm::releaseAllSecureStops() { 572 Mutex::Autolock autoLock(mLock); 573 574 if (mInitCheck != OK) { 575 return mInitCheck; 576 } 577 578 if (mPlugin == NULL) { 579 return -EINVAL; 580 } 581 582 return mPlugin->releaseAllSecureStops(); 583} 584 585status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { 586 Mutex::Autolock autoLock(mLock); 587 588 if (mInitCheck != OK) { 589 return mInitCheck; 590 } 591 592 if (mPlugin == NULL) { 593 return -EINVAL; 594 } 595 596 return mPlugin->getPropertyString(name, value); 597} 598 599status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { 600 Mutex::Autolock autoLock(mLock); 601 602 if (mInitCheck != OK) { 603 return mInitCheck; 604 } 605 606 if (mPlugin == NULL) { 607 return -EINVAL; 608 } 609 610 return mPlugin->getPropertyByteArray(name, value); 611} 612 613status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { 614 Mutex::Autolock autoLock(mLock); 615 616 if (mInitCheck != OK) { 617 return mInitCheck; 618 } 619 620 if (mPlugin == NULL) { 621 return -EINVAL; 622 } 623 624 return mPlugin->setPropertyString(name, value); 625} 626 627status_t Drm::setPropertyByteArray(String8 const &name, 628 Vector<uint8_t> const &value ) const { 629 Mutex::Autolock autoLock(mLock); 630 631 if (mInitCheck != OK) { 632 return mInitCheck; 633 } 634 635 if (mPlugin == NULL) { 636 return -EINVAL; 637 } 638 639 return mPlugin->setPropertyByteArray(name, value); 640} 641 642 643status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, 644 String8 const &algorithm) { 645 Mutex::Autolock autoLock(mLock); 646 647 if (mInitCheck != OK) { 648 return mInitCheck; 649 } 650 651 if (mPlugin == NULL) { 652 return -EINVAL; 653 } 654 655 DrmSessionManager::Instance()->useSession(sessionId); 656 657 return mPlugin->setCipherAlgorithm(sessionId, algorithm); 658} 659 660status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, 661 String8 const &algorithm) { 662 Mutex::Autolock autoLock(mLock); 663 664 if (mInitCheck != OK) { 665 return mInitCheck; 666 } 667 668 if (mPlugin == NULL) { 669 return -EINVAL; 670 } 671 672 DrmSessionManager::Instance()->useSession(sessionId); 673 674 return mPlugin->setMacAlgorithm(sessionId, algorithm); 675} 676 677status_t Drm::encrypt(Vector<uint8_t> const &sessionId, 678 Vector<uint8_t> const &keyId, 679 Vector<uint8_t> const &input, 680 Vector<uint8_t> const &iv, 681 Vector<uint8_t> &output) { 682 Mutex::Autolock autoLock(mLock); 683 684 if (mInitCheck != OK) { 685 return mInitCheck; 686 } 687 688 if (mPlugin == NULL) { 689 return -EINVAL; 690 } 691 692 DrmSessionManager::Instance()->useSession(sessionId); 693 694 return mPlugin->encrypt(sessionId, keyId, input, iv, output); 695} 696 697status_t Drm::decrypt(Vector<uint8_t> const &sessionId, 698 Vector<uint8_t> const &keyId, 699 Vector<uint8_t> const &input, 700 Vector<uint8_t> const &iv, 701 Vector<uint8_t> &output) { 702 Mutex::Autolock autoLock(mLock); 703 704 if (mInitCheck != OK) { 705 return mInitCheck; 706 } 707 708 if (mPlugin == NULL) { 709 return -EINVAL; 710 } 711 712 DrmSessionManager::Instance()->useSession(sessionId); 713 714 return mPlugin->decrypt(sessionId, keyId, input, iv, output); 715} 716 717status_t Drm::sign(Vector<uint8_t> const &sessionId, 718 Vector<uint8_t> const &keyId, 719 Vector<uint8_t> const &message, 720 Vector<uint8_t> &signature) { 721 Mutex::Autolock autoLock(mLock); 722 723 if (mInitCheck != OK) { 724 return mInitCheck; 725 } 726 727 if (mPlugin == NULL) { 728 return -EINVAL; 729 } 730 731 DrmSessionManager::Instance()->useSession(sessionId); 732 733 return mPlugin->sign(sessionId, keyId, message, signature); 734} 735 736status_t Drm::verify(Vector<uint8_t> const &sessionId, 737 Vector<uint8_t> const &keyId, 738 Vector<uint8_t> const &message, 739 Vector<uint8_t> const &signature, 740 bool &match) { 741 Mutex::Autolock autoLock(mLock); 742 743 if (mInitCheck != OK) { 744 return mInitCheck; 745 } 746 747 if (mPlugin == NULL) { 748 return -EINVAL; 749 } 750 751 DrmSessionManager::Instance()->useSession(sessionId); 752 753 return mPlugin->verify(sessionId, keyId, message, signature, match); 754} 755 756status_t Drm::signRSA(Vector<uint8_t> const &sessionId, 757 String8 const &algorithm, 758 Vector<uint8_t> const &message, 759 Vector<uint8_t> const &wrappedKey, 760 Vector<uint8_t> &signature) { 761 Mutex::Autolock autoLock(mLock); 762 763 if (mInitCheck != OK) { 764 return mInitCheck; 765 } 766 767 if (mPlugin == NULL) { 768 return -EINVAL; 769 } 770 771 if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) { 772 return -EPERM; 773 } 774 775 DrmSessionManager::Instance()->useSession(sessionId); 776 777 return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); 778} 779 780void Drm::binderDied(const wp<IBinder> &the_late_who __unused) 781{ 782 mEventLock.lock(); 783 mListener.clear(); 784 mEventLock.unlock(); 785 786 Mutex::Autolock autoLock(mLock); 787 delete mPlugin; 788 mPlugin = NULL; 789 closeFactory(); 790} 791 792void Drm::writeByteArray(Parcel &obj, Vector<uint8_t> const *array) 793{ 794 if (array && array->size()) { 795 obj.writeInt32(array->size()); 796 obj.write(array->array(), array->size()); 797 } else { 798 obj.writeInt32(0); 799 } 800} 801 802} // namespace android 803