NdkMediaDrm.cpp revision 3425fd5a55dd31e261d2f2a9590c762d6d0a6b79
1/* 2 * Copyright (C) 2014 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 "NdkMediaDrm" 19 20#include "NdkMediaDrm.h" 21 22#include <utils/Log.h> 23#include <utils/StrongPointer.h> 24#include <gui/Surface.h> 25 26#include <media/IDrm.h> 27#include <media/IDrmClient.h> 28#include <media/stagefright/MediaErrors.h> 29#include <binder/IServiceManager.h> 30#include <media/IMediaPlayerService.h> 31#include <ndk/NdkMediaCrypto.h> 32 33 34using namespace android; 35 36typedef Vector<uint8_t> idvec_t; 37 38struct AMediaDrm { 39 sp<IDrm> mDrm; 40 sp<IDrmClient> mDrmClient; 41 AMediaDrmEventListener mListener; 42 List<idvec_t> mIds; 43 KeyedVector<String8, String8> mQueryResults; 44 Vector<uint8_t> mKeyRequest; 45 Vector<uint8_t> mProvisionRequest; 46 String8 mProvisionUrl; 47 String8 mPropertyString; 48 Vector<uint8_t> mPropertyByteArray; 49 List<Vector<uint8_t> > mSecureStops; 50}; 51 52extern "C" { 53 54static mediadrm_status_t translateStatus(status_t status) { 55 mediadrm_status_t result = MEDIADRM_UNKNOWN_ERROR; 56 switch (status) { 57 case OK: 58 result = MEDIADRM_OK; 59 break; 60 case android::ERROR_DRM_NOT_PROVISIONED: 61 result = MEDIADRM_NOT_PROVISIONED_ERROR; 62 break; 63 case android::ERROR_DRM_RESOURCE_BUSY: 64 result = MEDIADRM_RESOURCE_BUSY_ERROR; 65 break; 66 case android::ERROR_DRM_DEVICE_REVOKED: 67 result = MEDIADRM_DEVICE_REVOKED_ERROR; 68 break; 69 case android::ERROR_DRM_CANNOT_HANDLE: 70 result = MEDIADRM_INVALID_PARAMETER_ERROR; 71 break; 72 case android::ERROR_DRM_TAMPER_DETECTED: 73 result = MEDIADRM_TAMPER_DETECTED_ERROR; 74 break; 75 case android::ERROR_DRM_SESSION_NOT_OPENED: 76 result = MEDIADRM_SESSION_NOT_OPENED_ERROR; 77 break; 78 case android::ERROR_DRM_NO_LICENSE: 79 result = MEDIADRM_NEED_KEY_ERROR; 80 break; 81 case android::ERROR_DRM_LICENSE_EXPIRED: 82 result = MEDIADRM_LICENSE_EXPIRED_ERROR; 83 break; 84 default: 85 result = MEDIADRM_UNKNOWN_ERROR; 86 break; 87 } 88 return result; 89} 90 91static sp<IDrm> CreateDrm() { 92 sp<IServiceManager> sm = defaultServiceManager(); 93 94 sp<IBinder> binder = 95 sm->getService(String16("media.player")); 96 97 sp<IMediaPlayerService> service = 98 interface_cast<IMediaPlayerService>(binder); 99 100 if (service == NULL) { 101 return NULL; 102 } 103 104 sp<IDrm> drm = service->makeDrm(); 105 106 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) { 107 return NULL; 108 } 109 110 return drm; 111} 112 113 114static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) { 115 sp<IDrm> drm = CreateDrm(); 116 117 if (drm == NULL) { 118 return NULL; 119 } 120 121 status_t err = drm->createPlugin(uuid); 122 123 if (err != OK) { 124 return NULL; 125 } 126 127 return drm; 128} 129 130EXPORT 131bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) { 132 sp<IDrm> drm = CreateDrm(); 133 134 if (drm == NULL) { 135 return false; 136 } 137 138 String8 mimeStr = mimeType ? String8(mimeType) : String8(""); 139 return drm->isCryptoSchemeSupported(uuid, mimeStr); 140} 141 142EXPORT 143AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { 144 AMediaDrm *mObj = new AMediaDrm(); 145 mObj->mDrm = CreateDrmFromUUID(uuid); 146 return mObj; 147} 148 149EXPORT 150void AMediaDrm_release(AMediaDrm *mObj) { 151 if (mObj->mDrm != NULL) { 152 mObj->mDrm->setListener(NULL); 153 mObj->mDrm->destroyPlugin(); 154 mObj->mDrm.clear(); 155 } 156 delete mObj; 157} 158 159#if 0 160void AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) { 161 mObj->mListener = listener; 162} 163#endif 164 165 166static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) { 167 iter = mObj->mIds.begin(); 168 while (iter != mObj->mIds.end()) { 169 if (iter->array() == id.ptr && iter->size() == id.length) { 170 return true; 171 } 172 } 173 return false; 174} 175 176EXPORT 177mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) { 178 if (!mObj || mObj->mDrm == NULL) { 179 return MEDIADRM_INVALID_OBJECT_ERROR; 180 } 181 Vector<uint8_t> session; 182 status_t status = mObj->mDrm->openSession(session); 183 if (status == OK) { 184 mObj->mIds.push_front(session); 185 List<idvec_t>::iterator iter = mObj->mIds.begin(); 186 sessionId.ptr = iter->array(); 187 sessionId.length = iter->size(); 188 } 189 return MEDIADRM_OK; 190} 191 192EXPORT 193mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) { 194 if (!mObj || mObj->mDrm == NULL) { 195 return MEDIADRM_INVALID_OBJECT_ERROR; 196 } 197 198 List<idvec_t>::iterator iter; 199 if (!findId(mObj, sessionId, iter)) { 200 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 201 } 202 mObj->mDrm->closeSession(*iter); 203 mObj->mIds.erase(iter); 204 return MEDIADRM_OK; 205} 206 207EXPORT 208mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope, 209 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, 210 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, 211 const uint8_t *&keyRequest, size_t &keyRequestSize) { 212 213 if (!mObj || mObj->mDrm == NULL) { 214 return MEDIADRM_INVALID_OBJECT_ERROR; 215 } 216 if (!mimeType) { 217 return MEDIADRM_INVALID_PARAMETER_ERROR; 218 } 219 220 List<idvec_t>::iterator iter; 221 if (!findId(mObj, scope, iter)) { 222 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 223 } 224 225 Vector<uint8_t> mdInit; 226 mdInit.appendArray(init, initSize); 227 DrmPlugin::KeyType mdKeyType; 228 switch (keyType) { 229 case KEY_TYPE_STREAMING: 230 mdKeyType = DrmPlugin::kKeyType_Streaming; 231 break; 232 case KEY_TYPE_OFFLINE: 233 mdKeyType = DrmPlugin::kKeyType_Offline; 234 break; 235 case KEY_TYPE_RELEASE: 236 mdKeyType = DrmPlugin::kKeyType_Release; 237 break; 238 default: 239 return MEDIADRM_INVALID_PARAMETER_ERROR; 240 } 241 KeyedVector<String8, String8> mdOptionalParameters; 242 for (size_t i = 0; i < numOptionalParameters; i++) { 243 mdOptionalParameters.add(String8(optionalParameters[i].mKey), 244 String8(optionalParameters[i].mValue)); 245 } 246 String8 defaultUrl; 247 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType), 248 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl); 249 if (status != OK) { 250 return translateStatus(status); 251 } else { 252 keyRequest = mObj->mKeyRequest.array(); 253 keyRequestSize = mObj->mKeyRequest.size(); 254 } 255 return MEDIADRM_OK; 256} 257 258EXPORT 259mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope, 260 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) { 261 262 if (!mObj || mObj->mDrm == NULL) { 263 return MEDIADRM_INVALID_OBJECT_ERROR; 264 } 265 if (!response || !responseSize) { 266 return MEDIADRM_INVALID_PARAMETER_ERROR; 267 } 268 269 List<idvec_t>::iterator iter; 270 if (!findId(mObj, scope, iter)) { 271 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 272 } 273 Vector<uint8_t> mdResponse; 274 mdResponse.appendArray(response, responseSize); 275 276 Vector<uint8_t> mdKeySetId; 277 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId); 278 if (status == OK) { 279 mObj->mIds.push_front(mdKeySetId); 280 List<idvec_t>::iterator iter = mObj->mIds.begin(); 281 keySetId.ptr = iter->array(); 282 keySetId.length = iter->size(); 283 } else { 284 keySetId.ptr = NULL; 285 keySetId.length = 0; 286 } 287 return MEDIADRM_OK; 288} 289 290EXPORT 291mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 292 const AMediaDrmKeySetId &keySetId) { 293 294 if (!mObj || mObj->mDrm == NULL) { 295 return MEDIADRM_INVALID_OBJECT_ERROR; 296 } 297 List<idvec_t>::iterator iter; 298 if (!findId(mObj, sessionId, iter)) { 299 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 300 } 301 Vector<uint8_t> keySet; 302 keySet.appendArray(keySetId.ptr, keySetId.length); 303 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet)); 304} 305 306EXPORT 307mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) { 308 if (!mObj || mObj->mDrm == NULL) { 309 return MEDIADRM_INVALID_OBJECT_ERROR; 310 } 311 List<idvec_t>::iterator iter; 312 status_t status; 313 if (!findId(mObj, keySetId, iter)) { 314 Vector<uint8_t> keySet; 315 keySet.appendArray(keySetId.ptr, keySetId.length); 316 status = mObj->mDrm->removeKeys(keySet); 317 } else { 318 status = mObj->mDrm->removeKeys(*iter); 319 mObj->mIds.erase(iter); 320 } 321 return translateStatus(status); 322} 323 324EXPORT 325mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 326 AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) { 327 328 if (!mObj || mObj->mDrm == NULL) { 329 return MEDIADRM_INVALID_OBJECT_ERROR; 330 } 331 List<idvec_t>::iterator iter; 332 if (!findId(mObj, sessionId, iter)) { 333 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 334 } 335 336 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults); 337 if (status != OK) { 338 numPairs = 0; 339 return translateStatus(status); 340 } 341 342 if (mObj->mQueryResults.size() > numPairs) { 343 numPairs = mObj->mQueryResults.size(); 344 return MEDIADRM_SHORT_BUFFER; 345 } 346 347 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) { 348 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string(); 349 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string(); 350 } 351 numPairs = mObj->mQueryResults.size(); 352 return MEDIADRM_OK; 353} 354 355EXPORT 356mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest, 357 size_t &provisionRequestSize, const char *&serverUrl) { 358 if (!mObj || mObj->mDrm == NULL) { 359 return MEDIADRM_INVALID_OBJECT_ERROR; 360 } 361 if (!provisionRequestSize || !serverUrl) { 362 return MEDIADRM_INVALID_PARAMETER_ERROR; 363 } 364 365 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""), 366 mObj->mProvisionRequest, mObj->mProvisionUrl); 367 if (status != OK) { 368 return translateStatus(status); 369 } else { 370 provisionRequest = mObj->mProvisionRequest.array(); 371 provisionRequestSize = mObj->mProvisionRequest.size(); 372 serverUrl = mObj->mProvisionUrl.string(); 373 } 374 return MEDIADRM_OK; 375} 376 377EXPORT 378mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, 379 const uint8_t *response, size_t responseSize) { 380 if (!mObj || mObj->mDrm == NULL) { 381 return MEDIADRM_INVALID_OBJECT_ERROR; 382 } 383 if (!response || !responseSize) { 384 return MEDIADRM_INVALID_PARAMETER_ERROR; 385 } 386 387 Vector<uint8_t> mdResponse; 388 mdResponse.appendArray(response, responseSize); 389 390 Vector<uint8_t> unused; 391 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused)); 392} 393 394EXPORT 395mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, 396 AMediaDrmSecureStop *secureStops, size_t &numSecureStops) { 397 398 if (!mObj || mObj->mDrm == NULL) { 399 return MEDIADRM_INVALID_OBJECT_ERROR; 400 } 401 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops); 402 if (status != OK) { 403 numSecureStops = 0; 404 return translateStatus(status); 405 } 406 if (numSecureStops < mObj->mSecureStops.size()) { 407 return MEDIADRM_SHORT_BUFFER; 408 } 409 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin(); 410 size_t i = 0; 411 while (iter != mObj->mSecureStops.end()) { 412 secureStops[i].ptr = iter->array(); 413 secureStops[i].length = iter->size(); 414 ++iter; 415 ++i; 416 } 417 numSecureStops = mObj->mSecureStops.size(); 418 return MEDIADRM_OK; 419} 420 421EXPORT 422mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, 423 const AMediaDrmSecureStop &ssRelease) { 424 425 if (!mObj || mObj->mDrm == NULL) { 426 return MEDIADRM_INVALID_OBJECT_ERROR; 427 } 428 429 Vector<uint8_t> release; 430 release.appendArray(ssRelease.ptr, ssRelease.length); 431 return translateStatus(mObj->mDrm->releaseSecureStops(release)); 432} 433 434 435EXPORT 436mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, 437 const char *&propertyValue) { 438 439 if (!mObj || mObj->mDrm == NULL) { 440 return MEDIADRM_INVALID_OBJECT_ERROR; 441 } 442 443 status_t status = mObj->mDrm->getPropertyString(String8(propertyName), 444 mObj->mPropertyString); 445 446 if (status == OK) { 447 propertyValue = mObj->mPropertyString.string(); 448 } else { 449 propertyValue = NULL; 450 } 451 return translateStatus(status); 452} 453 454EXPORT 455mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, 456 const char *propertyName, AMediaDrmByteArray &propertyValue) { 457 if (!mObj || mObj->mDrm == NULL) { 458 return MEDIADRM_INVALID_OBJECT_ERROR; 459 } 460 461 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName), 462 mObj->mPropertyByteArray); 463 464 if (status == OK) { 465 propertyValue.ptr = mObj->mPropertyByteArray.array(); 466 propertyValue.length = mObj->mPropertyByteArray.size(); 467 } else { 468 propertyValue.ptr = NULL; 469 propertyValue.length = 0; 470 } 471 return translateStatus(status); 472} 473 474EXPORT 475mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, 476 const char *propertyName, const char *value) { 477 if (!mObj || mObj->mDrm == NULL) { 478 return MEDIADRM_INVALID_OBJECT_ERROR; 479 } 480 481 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName), 482 String8(value))); 483} 484 485EXPORT 486mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, 487 const char *propertyName, const uint8_t *value, size_t valueSize) { 488 489 Vector<uint8_t> byteArray; 490 byteArray.appendArray(value, valueSize); 491 492 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName), 493 byteArray)); 494} 495 496 497static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj, 498 const AMediaDrmSessionId &sessionId, 499 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 500 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) { 501 502 if (!mObj || mObj->mDrm == NULL) { 503 return MEDIADRM_INVALID_OBJECT_ERROR; 504 } 505 List<idvec_t>::iterator iter; 506 if (!findId(mObj, sessionId, iter)) { 507 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 508 } 509 510 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm)); 511 if (status != OK) { 512 return translateStatus(status); 513 } 514 515 Vector<uint8_t> keyIdVec; 516 const size_t kKeyIdSize = 16; 517 keyIdVec.appendArray(keyId, kKeyIdSize); 518 519 Vector<uint8_t> inputVec; 520 inputVec.appendArray(input, dataSize); 521 522 Vector<uint8_t> ivVec; 523 const size_t kIvSize = 16; 524 ivVec.appendArray(iv, kIvSize); 525 526 Vector<uint8_t> outputVec; 527 if (encrypt) { 528 status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 529 } else { 530 status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 531 } 532 if (status == OK) { 533 memcpy(output, outputVec.array(), outputVec.size()); 534 } 535 return translateStatus(status); 536} 537 538EXPORT 539mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 540 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 541 const uint8_t *input, uint8_t *output, size_t dataSize) { 542 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, 543 input, output, dataSize, true); 544} 545 546EXPORT 547mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 548 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 549 const uint8_t *input, uint8_t *output, size_t dataSize) { 550 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, 551 input, output, dataSize, false); 552} 553 554EXPORT 555mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 556 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, 557 uint8_t *signature, size_t *signatureSize) { 558 559 if (!mObj || mObj->mDrm == NULL) { 560 return MEDIADRM_INVALID_OBJECT_ERROR; 561 } 562 List<idvec_t>::iterator iter; 563 if (!findId(mObj, sessionId, iter)) { 564 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 565 } 566 567 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 568 if (status != OK) { 569 return translateStatus(status); 570 } 571 572 Vector<uint8_t> keyIdVec; 573 const size_t kKeyIdSize = 16; 574 keyIdVec.appendArray(keyId, kKeyIdSize); 575 576 Vector<uint8_t> messageVec; 577 messageVec.appendArray(message, messageSize); 578 579 Vector<uint8_t> signatureVec; 580 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec); 581 if (signatureVec.size() > *signatureSize) { 582 return MEDIADRM_SHORT_BUFFER; 583 } 584 if (status == OK) { 585 memcpy(signature, signatureVec.array(), signatureVec.size()); 586 } 587 return translateStatus(status); 588} 589 590EXPORT 591mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 592 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, 593 const uint8_t *signature, size_t signatureSize) { 594 595 if (!mObj || mObj->mDrm == NULL) { 596 return MEDIADRM_INVALID_OBJECT_ERROR; 597 } 598 List<idvec_t>::iterator iter; 599 if (!findId(mObj, sessionId, iter)) { 600 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 601 } 602 603 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 604 if (status != OK) { 605 return translateStatus(status); 606 } 607 608 Vector<uint8_t> keyIdVec; 609 const size_t kKeyIdSize = 16; 610 keyIdVec.appendArray(keyId, kKeyIdSize); 611 612 Vector<uint8_t> messageVec; 613 messageVec.appendArray(message, messageSize); 614 615 Vector<uint8_t> signatureVec; 616 signatureVec.appendArray(signature, signatureSize); 617 618 bool match; 619 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match); 620 if (status == OK) { 621 return match ? MEDIADRM_OK : MEDIADRM_VERIFY_FAILED; 622 } 623 return translateStatus(status); 624} 625 626} // extern "C" 627 628