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 32 namespace android { 33 34 KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap; 35 KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap; 36 Mutex Drm::mMapLock; 37 38 static 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 48 Drm::Drm() 49 : mInitCheck(NO_INIT), 50 mListener(NULL), 51 mFactory(NULL), 52 mPlugin(NULL) { 53 } 54 55 Drm::~Drm() { 56 delete mPlugin; 57 mPlugin = NULL; 58 closeFactory(); 59 } 60 61 void Drm::closeFactory() { 62 delete mFactory; 63 mFactory = NULL; 64 mLibrary.clear(); 65 } 66 67 status_t Drm::initCheck() const { 68 return mInitCheck; 69 } 70 71 status_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 84 void 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 */ 126 void 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 181 bool 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 214 bool 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 232 status_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 252 status_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 269 status_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 283 status_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 297 status_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 316 status_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 332 status_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 346 status_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 361 status_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 376 status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) { 377 Mutex::Autolock autoLock(mLock); 378 379 if (mInitCheck != OK) { 380 return mInitCheck; 381 } 382 383 if (mPlugin == NULL) { 384 return -EINVAL; 385 } 386 387 return mPlugin->getProvisionRequest(request, defaultUrl); 388 } 389 390 status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) { 391 Mutex::Autolock autoLock(mLock); 392 393 if (mInitCheck != OK) { 394 return mInitCheck; 395 } 396 397 if (mPlugin == NULL) { 398 return -EINVAL; 399 } 400 401 return mPlugin->provideProvisionResponse(response); 402 } 403 404 405 status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { 406 Mutex::Autolock autoLock(mLock); 407 408 if (mInitCheck != OK) { 409 return mInitCheck; 410 } 411 412 if (mPlugin == NULL) { 413 return -EINVAL; 414 } 415 416 return mPlugin->getSecureStops(secureStops); 417 } 418 419 status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) { 420 Mutex::Autolock autoLock(mLock); 421 422 if (mInitCheck != OK) { 423 return mInitCheck; 424 } 425 426 if (mPlugin == NULL) { 427 return -EINVAL; 428 } 429 430 return mPlugin->releaseSecureStops(ssRelease); 431 } 432 433 status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { 434 Mutex::Autolock autoLock(mLock); 435 436 if (mInitCheck != OK) { 437 return mInitCheck; 438 } 439 440 if (mPlugin == NULL) { 441 return -EINVAL; 442 } 443 444 return mPlugin->getPropertyString(name, value); 445 } 446 447 status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { 448 Mutex::Autolock autoLock(mLock); 449 450 if (mInitCheck != OK) { 451 return mInitCheck; 452 } 453 454 if (mPlugin == NULL) { 455 return -EINVAL; 456 } 457 458 return mPlugin->getPropertyByteArray(name, value); 459 } 460 461 status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { 462 Mutex::Autolock autoLock(mLock); 463 464 if (mInitCheck != OK) { 465 return mInitCheck; 466 } 467 468 if (mPlugin == NULL) { 469 return -EINVAL; 470 } 471 472 return mPlugin->setPropertyString(name, value); 473 } 474 475 status_t Drm::setPropertyByteArray(String8 const &name, 476 Vector<uint8_t> const &value ) const { 477 Mutex::Autolock autoLock(mLock); 478 479 if (mInitCheck != OK) { 480 return mInitCheck; 481 } 482 483 if (mPlugin == NULL) { 484 return -EINVAL; 485 } 486 487 return mPlugin->setPropertyByteArray(name, value); 488 } 489 490 491 status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, 492 String8 const &algorithm) { 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->setCipherAlgorithm(sessionId, algorithm); 504 } 505 506 status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, 507 String8 const &algorithm) { 508 Mutex::Autolock autoLock(mLock); 509 510 if (mInitCheck != OK) { 511 return mInitCheck; 512 } 513 514 if (mPlugin == NULL) { 515 return -EINVAL; 516 } 517 518 return mPlugin->setMacAlgorithm(sessionId, algorithm); 519 } 520 521 status_t Drm::encrypt(Vector<uint8_t> const &sessionId, 522 Vector<uint8_t> const &keyId, 523 Vector<uint8_t> const &input, 524 Vector<uint8_t> const &iv, 525 Vector<uint8_t> &output) { 526 Mutex::Autolock autoLock(mLock); 527 528 if (mInitCheck != OK) { 529 return mInitCheck; 530 } 531 532 if (mPlugin == NULL) { 533 return -EINVAL; 534 } 535 536 return mPlugin->encrypt(sessionId, keyId, input, iv, output); 537 } 538 539 status_t Drm::decrypt(Vector<uint8_t> const &sessionId, 540 Vector<uint8_t> const &keyId, 541 Vector<uint8_t> const &input, 542 Vector<uint8_t> const &iv, 543 Vector<uint8_t> &output) { 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->decrypt(sessionId, keyId, input, iv, output); 555 } 556 557 status_t Drm::sign(Vector<uint8_t> const &sessionId, 558 Vector<uint8_t> const &keyId, 559 Vector<uint8_t> const &message, 560 Vector<uint8_t> &signature) { 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->sign(sessionId, keyId, message, signature); 572 } 573 574 status_t Drm::verify(Vector<uint8_t> const &sessionId, 575 Vector<uint8_t> const &keyId, 576 Vector<uint8_t> const &message, 577 Vector<uint8_t> const &signature, 578 bool &match) { 579 Mutex::Autolock autoLock(mLock); 580 581 if (mInitCheck != OK) { 582 return mInitCheck; 583 } 584 585 if (mPlugin == NULL) { 586 return -EINVAL; 587 } 588 589 return mPlugin->verify(sessionId, keyId, message, signature, match); 590 } 591 592 void Drm::binderDied(const wp<IBinder> &the_late_who) 593 { 594 delete mPlugin; 595 mPlugin = NULL; 596 closeFactory(); 597 mListener.clear(); 598 } 599 600 } // namespace android 601