Drm.cpp revision 9cf69e0fc110f17c28e988ed0f9bf91abfaf710d
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 return mFactory->isContentTypeSupported(mimeType); 226} 227 228status_t Drm::createPlugin(const uint8_t uuid[16]) { 229 Mutex::Autolock autoLock(mLock); 230 231 if (mPlugin != NULL) { 232 return -EINVAL; 233 } 234 235 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 236 findFactoryForScheme(uuid); 237 } 238 239 if (mInitCheck != OK) { 240 return mInitCheck; 241 } 242 243 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin); 244 mPlugin->setListener(this); 245 return result; 246} 247 248status_t Drm::destroyPlugin() { 249 Mutex::Autolock autoLock(mLock); 250 251 if (mInitCheck != OK) { 252 return mInitCheck; 253 } 254 255 if (mPlugin == NULL) { 256 return -EINVAL; 257 } 258 259 delete mPlugin; 260 mPlugin = NULL; 261 262 return OK; 263} 264 265status_t Drm::openSession(Vector<uint8_t> &sessionId) { 266 Mutex::Autolock autoLock(mLock); 267 268 if (mInitCheck != OK) { 269 return mInitCheck; 270 } 271 272 if (mPlugin == NULL) { 273 return -EINVAL; 274 } 275 276 return mPlugin->openSession(sessionId); 277} 278 279status_t Drm::closeSession(Vector<uint8_t> const &sessionId) { 280 Mutex::Autolock autoLock(mLock); 281 282 if (mInitCheck != OK) { 283 return mInitCheck; 284 } 285 286 if (mPlugin == NULL) { 287 return -EINVAL; 288 } 289 290 return mPlugin->closeSession(sessionId); 291} 292 293status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId, 294 Vector<uint8_t> const &initData, 295 String8 const &mimeType, DrmPlugin::KeyType keyType, 296 KeyedVector<String8, String8> const &optionalParameters, 297 Vector<uint8_t> &request, String8 &defaultUrl) { 298 Mutex::Autolock autoLock(mLock); 299 300 if (mInitCheck != OK) { 301 return mInitCheck; 302 } 303 304 if (mPlugin == NULL) { 305 return -EINVAL; 306 } 307 308 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, 309 optionalParameters, request, defaultUrl); 310} 311 312status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId, 313 Vector<uint8_t> const &response, 314 Vector<uint8_t> &keySetId) { 315 Mutex::Autolock autoLock(mLock); 316 317 if (mInitCheck != OK) { 318 return mInitCheck; 319 } 320 321 if (mPlugin == NULL) { 322 return -EINVAL; 323 } 324 325 return mPlugin->provideKeyResponse(sessionId, response, keySetId); 326} 327 328status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) { 329 Mutex::Autolock autoLock(mLock); 330 331 if (mInitCheck != OK) { 332 return mInitCheck; 333 } 334 335 if (mPlugin == NULL) { 336 return -EINVAL; 337 } 338 339 return mPlugin->removeKeys(keySetId); 340} 341 342status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId, 343 Vector<uint8_t> const &keySetId) { 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 return mPlugin->restoreKeys(sessionId, keySetId); 355} 356 357status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, 358 KeyedVector<String8, String8> &infoMap) const { 359 Mutex::Autolock autoLock(mLock); 360 361 if (mInitCheck != OK) { 362 return mInitCheck; 363 } 364 365 if (mPlugin == NULL) { 366 return -EINVAL; 367 } 368 369 return mPlugin->queryKeyStatus(sessionId, infoMap); 370} 371 372status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) { 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 return mPlugin->getProvisionRequest(request, defaultUrl); 384} 385 386status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) { 387 Mutex::Autolock autoLock(mLock); 388 389 if (mInitCheck != OK) { 390 return mInitCheck; 391 } 392 393 if (mPlugin == NULL) { 394 return -EINVAL; 395 } 396 397 return mPlugin->provideProvisionResponse(response); 398} 399 400 401status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { 402 Mutex::Autolock autoLock(mLock); 403 404 if (mInitCheck != OK) { 405 return mInitCheck; 406 } 407 408 if (mPlugin == NULL) { 409 return -EINVAL; 410 } 411 412 return mPlugin->getSecureStops(secureStops); 413} 414 415status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) { 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 return mPlugin->releaseSecureStops(ssRelease); 427} 428 429status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { 430 Mutex::Autolock autoLock(mLock); 431 432 if (mInitCheck != OK) { 433 return mInitCheck; 434 } 435 436 if (mPlugin == NULL) { 437 return -EINVAL; 438 } 439 440 return mPlugin->getPropertyString(name, value); 441} 442 443status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { 444 Mutex::Autolock autoLock(mLock); 445 446 if (mInitCheck != OK) { 447 return mInitCheck; 448 } 449 450 if (mPlugin == NULL) { 451 return -EINVAL; 452 } 453 454 return mPlugin->getPropertyByteArray(name, value); 455} 456 457status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { 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 return mPlugin->setPropertyString(name, value); 469} 470 471status_t Drm::setPropertyByteArray(String8 const &name, 472 Vector<uint8_t> const &value ) const { 473 Mutex::Autolock autoLock(mLock); 474 475 if (mInitCheck != OK) { 476 return mInitCheck; 477 } 478 479 if (mPlugin == NULL) { 480 return -EINVAL; 481 } 482 483 return mPlugin->setPropertyByteArray(name, value); 484} 485 486 487status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, 488 String8 const &algorithm) { 489 Mutex::Autolock autoLock(mLock); 490 491 if (mInitCheck != OK) { 492 return mInitCheck; 493 } 494 495 if (mPlugin == NULL) { 496 return -EINVAL; 497 } 498 499 return mPlugin->setCipherAlgorithm(sessionId, algorithm); 500} 501 502status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, 503 String8 const &algorithm) { 504 Mutex::Autolock autoLock(mLock); 505 506 if (mInitCheck != OK) { 507 return mInitCheck; 508 } 509 510 if (mPlugin == NULL) { 511 return -EINVAL; 512 } 513 514 return mPlugin->setMacAlgorithm(sessionId, algorithm); 515} 516 517status_t Drm::encrypt(Vector<uint8_t> const &sessionId, 518 Vector<uint8_t> const &keyId, 519 Vector<uint8_t> const &input, 520 Vector<uint8_t> const &iv, 521 Vector<uint8_t> &output) { 522 Mutex::Autolock autoLock(mLock); 523 524 if (mInitCheck != OK) { 525 return mInitCheck; 526 } 527 528 if (mPlugin == NULL) { 529 return -EINVAL; 530 } 531 532 return mPlugin->encrypt(sessionId, keyId, input, iv, output); 533} 534 535status_t Drm::decrypt(Vector<uint8_t> const &sessionId, 536 Vector<uint8_t> const &keyId, 537 Vector<uint8_t> const &input, 538 Vector<uint8_t> const &iv, 539 Vector<uint8_t> &output) { 540 Mutex::Autolock autoLock(mLock); 541 542 if (mInitCheck != OK) { 543 return mInitCheck; 544 } 545 546 if (mPlugin == NULL) { 547 return -EINVAL; 548 } 549 550 return mPlugin->decrypt(sessionId, keyId, input, iv, output); 551} 552 553status_t Drm::sign(Vector<uint8_t> const &sessionId, 554 Vector<uint8_t> const &keyId, 555 Vector<uint8_t> const &message, 556 Vector<uint8_t> &signature) { 557 Mutex::Autolock autoLock(mLock); 558 559 if (mInitCheck != OK) { 560 return mInitCheck; 561 } 562 563 if (mPlugin == NULL) { 564 return -EINVAL; 565 } 566 567 return mPlugin->sign(sessionId, keyId, message, signature); 568} 569 570status_t Drm::verify(Vector<uint8_t> const &sessionId, 571 Vector<uint8_t> const &keyId, 572 Vector<uint8_t> const &message, 573 Vector<uint8_t> const &signature, 574 bool &match) { 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->verify(sessionId, keyId, message, signature, match); 586} 587 588void Drm::binderDied(const wp<IBinder> &the_late_who) 589{ 590 delete mPlugin; 591 mPlugin = NULL; 592 closeFactory(); 593 mListener.clear(); 594} 595 596} // namespace android 597