Drm.cpp revision 0cb126a34fe32f81c830858102471e7be2ce85b1
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 mListener = listener; 75 return NO_ERROR; 76} 77 78void Drm::sendEvent(DrmPlugin::EventType eventType, int extra, 79 Vector<uint8_t> const *sessionId, 80 Vector<uint8_t> const *data) 81{ 82 mEventLock.lock(); 83 sp<IDrmClient> listener = mListener; 84 mEventLock.unlock(); 85 86 if (listener != NULL) { 87 Parcel obj; 88 if (sessionId && sessionId->size()) { 89 obj.writeInt32(sessionId->size()); 90 obj.write(sessionId->array(), sessionId->size()); 91 } else { 92 obj.writeInt32(0); 93 } 94 95 if (data && data->size()) { 96 obj.writeInt32(data->size()); 97 obj.write(data->array(), data->size()); 98 } else { 99 obj.writeInt32(0); 100 } 101 102 Mutex::Autolock lock(mNotifyLock); 103 listener->notify(eventType, extra, &obj); 104 } 105} 106 107/* 108 * Search the plugins directory for a plugin that supports the scheme 109 * specified by uuid 110 * 111 * If found: 112 * mLibrary holds a strong pointer to the dlopen'd library 113 * mFactory is set to the library's factory method 114 * mInitCheck is set to OK 115 * 116 * If not found: 117 * mLibrary is cleared and mFactory are set to NULL 118 * mInitCheck is set to an error (!OK) 119 */ 120void Drm::findFactoryForScheme(const uint8_t uuid[16]) { 121 122 closeFactory(); 123 124 // lock static maps 125 Mutex::Autolock autoLock(mMapLock); 126 127 // first check cache 128 Vector<uint8_t> uuidVector; 129 uuidVector.appendArray(uuid, sizeof(uuid)); 130 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector); 131 if (index >= 0) { 132 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) { 133 mInitCheck = OK; 134 return; 135 } else { 136 ALOGE("Failed to load from cached library path!"); 137 mInitCheck = ERROR_UNSUPPORTED; 138 return; 139 } 140 } 141 142 // no luck, have to search 143 String8 dirPath("/vendor/lib/mediadrm"); 144 DIR* pDir = opendir(dirPath.string()); 145 146 if (pDir == NULL) { 147 mInitCheck = ERROR_UNSUPPORTED; 148 ALOGE("Failed to open plugin directory %s", dirPath.string()); 149 return; 150 } 151 152 153 struct dirent* pEntry; 154 while ((pEntry = readdir(pDir))) { 155 156 String8 pluginPath = dirPath + "/" + pEntry->d_name; 157 158 if (pluginPath.getPathExtension() == ".so") { 159 160 if (loadLibraryForScheme(pluginPath, uuid)) { 161 mUUIDToLibraryPathMap.add(uuidVector, pluginPath); 162 mInitCheck = OK; 163 closedir(pDir); 164 return; 165 } 166 } 167 } 168 169 closedir(pDir); 170 171 ALOGE("Failed to find drm plugin"); 172 mInitCheck = ERROR_UNSUPPORTED; 173} 174 175bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { 176 177 // get strong pointer to open shared library 178 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); 179 if (index >= 0) { 180 mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); 181 } else { 182 index = mLibraryPathToOpenLibraryMap.add(path, NULL); 183 } 184 185 if (!mLibrary.get()) { 186 mLibrary = new SharedLibrary(path); 187 if (!*mLibrary) { 188 return false; 189 } 190 191 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); 192 } 193 194 typedef DrmFactory *(*CreateDrmFactoryFunc)(); 195 196 CreateDrmFactoryFunc createDrmFactory = 197 (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory"); 198 199 if (createDrmFactory == NULL || 200 (mFactory = createDrmFactory()) == NULL || 201 !mFactory->isCryptoSchemeSupported(uuid)) { 202 closeFactory(); 203 return false; 204 } 205 return true; 206} 207 208bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) { 209 Mutex::Autolock autoLock(mLock); 210 211 if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) { 212 return true; 213 } 214 215 findFactoryForScheme(uuid); 216 return (mInitCheck == OK); 217} 218 219status_t Drm::createPlugin(const uint8_t uuid[16]) { 220 Mutex::Autolock autoLock(mLock); 221 222 if (mPlugin != NULL) { 223 return -EINVAL; 224 } 225 226 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 227 findFactoryForScheme(uuid); 228 } 229 230 if (mInitCheck != OK) { 231 return mInitCheck; 232 } 233 234 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin); 235 mPlugin->setListener(this); 236 return result; 237} 238 239status_t Drm::destroyPlugin() { 240 Mutex::Autolock autoLock(mLock); 241 242 if (mInitCheck != OK) { 243 return mInitCheck; 244 } 245 246 if (mPlugin == NULL) { 247 return -EINVAL; 248 } 249 250 delete mPlugin; 251 mPlugin = NULL; 252 253 return OK; 254} 255 256status_t Drm::openSession(Vector<uint8_t> &sessionId) { 257 Mutex::Autolock autoLock(mLock); 258 259 if (mInitCheck != OK) { 260 return mInitCheck; 261 } 262 263 if (mPlugin == NULL) { 264 return -EINVAL; 265 } 266 267 return mPlugin->openSession(sessionId); 268} 269 270status_t Drm::closeSession(Vector<uint8_t> const &sessionId) { 271 Mutex::Autolock autoLock(mLock); 272 273 if (mInitCheck != OK) { 274 return mInitCheck; 275 } 276 277 if (mPlugin == NULL) { 278 return -EINVAL; 279 } 280 281 return mPlugin->closeSession(sessionId); 282} 283 284status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId, 285 Vector<uint8_t> const &initData, 286 String8 const &mimeType, DrmPlugin::KeyType keyType, 287 KeyedVector<String8, String8> const &optionalParameters, 288 Vector<uint8_t> &request, String8 &defaultUrl) { 289 Mutex::Autolock autoLock(mLock); 290 291 if (mInitCheck != OK) { 292 return mInitCheck; 293 } 294 295 if (mPlugin == NULL) { 296 return -EINVAL; 297 } 298 299 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, 300 optionalParameters, request, defaultUrl); 301} 302 303status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId, 304 Vector<uint8_t> const &response, 305 Vector<uint8_t> &keySetId) { 306 Mutex::Autolock autoLock(mLock); 307 308 if (mInitCheck != OK) { 309 return mInitCheck; 310 } 311 312 if (mPlugin == NULL) { 313 return -EINVAL; 314 } 315 316 return mPlugin->provideKeyResponse(sessionId, response, keySetId); 317} 318 319status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) { 320 Mutex::Autolock autoLock(mLock); 321 322 if (mInitCheck != OK) { 323 return mInitCheck; 324 } 325 326 if (mPlugin == NULL) { 327 return -EINVAL; 328 } 329 330 return mPlugin->removeKeys(keySetId); 331} 332 333status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId, 334 Vector<uint8_t> const &keySetId) { 335 Mutex::Autolock autoLock(mLock); 336 337 if (mInitCheck != OK) { 338 return mInitCheck; 339 } 340 341 if (mPlugin == NULL) { 342 return -EINVAL; 343 } 344 345 return mPlugin->restoreKeys(sessionId, keySetId); 346} 347 348status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, 349 KeyedVector<String8, String8> &infoMap) const { 350 Mutex::Autolock autoLock(mLock); 351 352 if (mInitCheck != OK) { 353 return mInitCheck; 354 } 355 356 if (mPlugin == NULL) { 357 return -EINVAL; 358 } 359 360 return mPlugin->queryKeyStatus(sessionId, infoMap); 361} 362 363status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) { 364 Mutex::Autolock autoLock(mLock); 365 366 if (mInitCheck != OK) { 367 return mInitCheck; 368 } 369 370 if (mPlugin == NULL) { 371 return -EINVAL; 372 } 373 374 return mPlugin->getProvisionRequest(request, defaultUrl); 375} 376 377status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) { 378 Mutex::Autolock autoLock(mLock); 379 380 if (mInitCheck != OK) { 381 return mInitCheck; 382 } 383 384 if (mPlugin == NULL) { 385 return -EINVAL; 386 } 387 388 return mPlugin->provideProvisionResponse(response); 389} 390 391 392status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { 393 Mutex::Autolock autoLock(mLock); 394 395 if (mInitCheck != OK) { 396 return mInitCheck; 397 } 398 399 if (mPlugin == NULL) { 400 return -EINVAL; 401 } 402 403 return mPlugin->getSecureStops(secureStops); 404} 405 406status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) { 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 return mPlugin->releaseSecureStops(ssRelease); 418} 419 420status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { 421 Mutex::Autolock autoLock(mLock); 422 423 if (mInitCheck != OK) { 424 return mInitCheck; 425 } 426 427 if (mPlugin == NULL) { 428 return -EINVAL; 429 } 430 431 return mPlugin->getPropertyString(name, value); 432} 433 434status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { 435 Mutex::Autolock autoLock(mLock); 436 437 if (mInitCheck != OK) { 438 return mInitCheck; 439 } 440 441 if (mPlugin == NULL) { 442 return -EINVAL; 443 } 444 445 return mPlugin->getPropertyByteArray(name, value); 446} 447 448status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { 449 Mutex::Autolock autoLock(mLock); 450 451 if (mInitCheck != OK) { 452 return mInitCheck; 453 } 454 455 if (mPlugin == NULL) { 456 return -EINVAL; 457 } 458 459 return mPlugin->setPropertyString(name, value); 460} 461 462status_t Drm::setPropertyByteArray(String8 const &name, 463 Vector<uint8_t> const &value ) 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 return mPlugin->setPropertyByteArray(name, value); 475} 476 477 478status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, 479 String8 const &algorithm) { 480 Mutex::Autolock autoLock(mLock); 481 482 if (mInitCheck != OK) { 483 return mInitCheck; 484 } 485 486 if (mPlugin == NULL) { 487 return -EINVAL; 488 } 489 490 return mPlugin->setCipherAlgorithm(sessionId, algorithm); 491} 492 493status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, 494 String8 const &algorithm) { 495 Mutex::Autolock autoLock(mLock); 496 497 if (mInitCheck != OK) { 498 return mInitCheck; 499 } 500 501 if (mPlugin == NULL) { 502 return -EINVAL; 503 } 504 505 return mPlugin->setMacAlgorithm(sessionId, algorithm); 506} 507 508status_t Drm::encrypt(Vector<uint8_t> const &sessionId, 509 Vector<uint8_t> const &keyId, 510 Vector<uint8_t> const &input, 511 Vector<uint8_t> const &iv, 512 Vector<uint8_t> &output) { 513 Mutex::Autolock autoLock(mLock); 514 515 if (mInitCheck != OK) { 516 return mInitCheck; 517 } 518 519 if (mPlugin == NULL) { 520 return -EINVAL; 521 } 522 523 return mPlugin->encrypt(sessionId, keyId, input, iv, output); 524} 525 526status_t Drm::decrypt(Vector<uint8_t> const &sessionId, 527 Vector<uint8_t> const &keyId, 528 Vector<uint8_t> const &input, 529 Vector<uint8_t> const &iv, 530 Vector<uint8_t> &output) { 531 Mutex::Autolock autoLock(mLock); 532 533 if (mInitCheck != OK) { 534 return mInitCheck; 535 } 536 537 if (mPlugin == NULL) { 538 return -EINVAL; 539 } 540 541 return mPlugin->decrypt(sessionId, keyId, input, iv, output); 542} 543 544status_t Drm::sign(Vector<uint8_t> const &sessionId, 545 Vector<uint8_t> const &keyId, 546 Vector<uint8_t> const &message, 547 Vector<uint8_t> &signature) { 548 Mutex::Autolock autoLock(mLock); 549 550 if (mInitCheck != OK) { 551 return mInitCheck; 552 } 553 554 if (mPlugin == NULL) { 555 return -EINVAL; 556 } 557 558 return mPlugin->sign(sessionId, keyId, message, signature); 559} 560 561status_t Drm::verify(Vector<uint8_t> const &sessionId, 562 Vector<uint8_t> const &keyId, 563 Vector<uint8_t> const &message, 564 Vector<uint8_t> const &signature, 565 bool &match) { 566 Mutex::Autolock autoLock(mLock); 567 568 if (mInitCheck != OK) { 569 return mInitCheck; 570 } 571 572 if (mPlugin == NULL) { 573 return -EINVAL; 574 } 575 576 return mPlugin->verify(sessionId, keyId, message, signature, match); 577} 578 579} // namespace android 580