NdkMediaDrm.cpp revision 497ca097bf373ac69405131bd257915c97b31dc0
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 130bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) { 131 sp<IDrm> drm = CreateDrm(); 132 133 if (drm == NULL) { 134 return false; 135 } 136 137 String8 mimeStr = mimeType ? String8(mimeType) : String8(""); 138 return drm->isCryptoSchemeSupported(uuid, mimeStr); 139} 140 141AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { 142 AMediaDrm *mObj = new AMediaDrm(); 143 mObj->mDrm = CreateDrmFromUUID(uuid); 144 return mObj; 145} 146 147void AMediaDrm_release(AMediaDrm *mObj) { 148 if (mObj->mDrm != NULL) { 149 mObj->mDrm->setListener(NULL); 150 mObj->mDrm->destroyPlugin(); 151 mObj->mDrm.clear(); 152 } 153 delete mObj; 154} 155 156#if 0 157void AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) { 158 mObj->mListener = listener; 159} 160#endif 161 162 163static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) { 164 iter = mObj->mIds.begin(); 165 while (iter != mObj->mIds.end()) { 166 if (iter->array() == id.ptr && iter->size() == id.length) { 167 return true; 168 } 169 } 170 return false; 171} 172 173mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) { 174 if (!mObj || mObj->mDrm == NULL) { 175 return MEDIADRM_INVALID_OBJECT_ERROR; 176 } 177 Vector<uint8_t> session; 178 status_t status = mObj->mDrm->openSession(session); 179 if (status == OK) { 180 mObj->mIds.push_front(session); 181 List<idvec_t>::iterator iter = mObj->mIds.begin(); 182 sessionId.ptr = iter->array(); 183 sessionId.length = iter->size(); 184 } 185 return MEDIADRM_OK; 186} 187 188mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) { 189 if (!mObj || mObj->mDrm == NULL) { 190 return MEDIADRM_INVALID_OBJECT_ERROR; 191 } 192 193 List<idvec_t>::iterator iter; 194 if (!findId(mObj, sessionId, iter)) { 195 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 196 } 197 mObj->mDrm->closeSession(*iter); 198 mObj->mIds.erase(iter); 199 return MEDIADRM_OK; 200} 201 202mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope, 203 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, 204 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, 205 const uint8_t *&keyRequest, size_t &keyRequestSize) { 206 207 if (!mObj || mObj->mDrm == NULL) { 208 return MEDIADRM_INVALID_OBJECT_ERROR; 209 } 210 if (!mimeType) { 211 return MEDIADRM_INVALID_PARAMETER_ERROR; 212 } 213 214 List<idvec_t>::iterator iter; 215 if (!findId(mObj, scope, iter)) { 216 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 217 } 218 219 Vector<uint8_t> mdInit; 220 mdInit.appendArray(init, initSize); 221 DrmPlugin::KeyType mdKeyType; 222 switch (keyType) { 223 case KEY_TYPE_STREAMING: 224 mdKeyType = DrmPlugin::kKeyType_Streaming; 225 break; 226 case KEY_TYPE_OFFLINE: 227 mdKeyType = DrmPlugin::kKeyType_Offline; 228 break; 229 case KEY_TYPE_RELEASE: 230 mdKeyType = DrmPlugin::kKeyType_Release; 231 break; 232 default: 233 return MEDIADRM_INVALID_PARAMETER_ERROR; 234 } 235 KeyedVector<String8, String8> mdOptionalParameters; 236 for (size_t i = 0; i < numOptionalParameters; i++) { 237 mdOptionalParameters.add(String8(optionalParameters[i].mKey), 238 String8(optionalParameters[i].mValue)); 239 } 240 String8 defaultUrl; 241 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType), 242 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl); 243 if (status != OK) { 244 return translateStatus(status); 245 } else { 246 keyRequest = mObj->mKeyRequest.array(); 247 keyRequestSize = mObj->mKeyRequest.size(); 248 } 249 return MEDIADRM_OK; 250} 251 252mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope, 253 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) { 254 255 if (!mObj || mObj->mDrm == NULL) { 256 return MEDIADRM_INVALID_OBJECT_ERROR; 257 } 258 if (!response || !responseSize) { 259 return MEDIADRM_INVALID_PARAMETER_ERROR; 260 } 261 262 List<idvec_t>::iterator iter; 263 if (!findId(mObj, scope, iter)) { 264 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 265 } 266 Vector<uint8_t> mdResponse; 267 mdResponse.appendArray(response, responseSize); 268 269 Vector<uint8_t> mdKeySetId; 270 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId); 271 if (status == OK) { 272 mObj->mIds.push_front(mdKeySetId); 273 List<idvec_t>::iterator iter = mObj->mIds.begin(); 274 keySetId.ptr = iter->array(); 275 keySetId.length = iter->size(); 276 } else { 277 keySetId.ptr = NULL; 278 keySetId.length = 0; 279 } 280 return MEDIADRM_OK; 281} 282 283mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 284 const AMediaDrmKeySetId &keySetId) { 285 286 if (!mObj || mObj->mDrm == NULL) { 287 return MEDIADRM_INVALID_OBJECT_ERROR; 288 } 289 List<idvec_t>::iterator iter; 290 if (!findId(mObj, sessionId, iter)) { 291 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 292 } 293 Vector<uint8_t> keySet; 294 keySet.appendArray(keySetId.ptr, keySetId.length); 295 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet)); 296} 297 298mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) { 299 if (!mObj || mObj->mDrm == NULL) { 300 return MEDIADRM_INVALID_OBJECT_ERROR; 301 } 302 List<idvec_t>::iterator iter; 303 status_t status; 304 if (!findId(mObj, keySetId, iter)) { 305 Vector<uint8_t> keySet; 306 keySet.appendArray(keySetId.ptr, keySetId.length); 307 status = mObj->mDrm->removeKeys(keySet); 308 } else { 309 status = mObj->mDrm->removeKeys(*iter); 310 mObj->mIds.erase(iter); 311 } 312 return translateStatus(status); 313} 314 315mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 316 AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) { 317 318 if (!mObj || mObj->mDrm == NULL) { 319 return MEDIADRM_INVALID_OBJECT_ERROR; 320 } 321 List<idvec_t>::iterator iter; 322 if (!findId(mObj, sessionId, iter)) { 323 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 324 } 325 326 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults); 327 if (status != OK) { 328 numPairs = 0; 329 return translateStatus(status); 330 } 331 332 if (mObj->mQueryResults.size() > numPairs) { 333 numPairs = mObj->mQueryResults.size(); 334 return MEDIADRM_SHORT_BUFFER; 335 } 336 337 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) { 338 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string(); 339 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string(); 340 } 341 numPairs = mObj->mQueryResults.size(); 342 return MEDIADRM_OK; 343} 344 345mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest, 346 size_t &provisionRequestSize, const char *&serverUrl) { 347 if (!mObj || mObj->mDrm == NULL) { 348 return MEDIADRM_INVALID_OBJECT_ERROR; 349 } 350 if (!provisionRequestSize || !serverUrl) { 351 return MEDIADRM_INVALID_PARAMETER_ERROR; 352 } 353 354 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""), 355 mObj->mProvisionRequest, mObj->mProvisionUrl); 356 if (status != OK) { 357 return translateStatus(status); 358 } else { 359 provisionRequest = mObj->mProvisionRequest.array(); 360 provisionRequestSize = mObj->mProvisionRequest.size(); 361 serverUrl = mObj->mProvisionUrl.string(); 362 } 363 return MEDIADRM_OK; 364} 365 366mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, 367 const uint8_t *response, size_t responseSize) { 368 if (!mObj || mObj->mDrm == NULL) { 369 return MEDIADRM_INVALID_OBJECT_ERROR; 370 } 371 if (!response || !responseSize) { 372 return MEDIADRM_INVALID_PARAMETER_ERROR; 373 } 374 375 Vector<uint8_t> mdResponse; 376 mdResponse.appendArray(response, responseSize); 377 378 Vector<uint8_t> unused; 379 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused)); 380} 381 382mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, 383 AMediaDrmSecureStop *secureStops, size_t &numSecureStops) { 384 385 if (!mObj || mObj->mDrm == NULL) { 386 return MEDIADRM_INVALID_OBJECT_ERROR; 387 } 388 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops); 389 if (status != OK) { 390 numSecureStops = 0; 391 return translateStatus(status); 392 } 393 if (numSecureStops < mObj->mSecureStops.size()) { 394 return MEDIADRM_SHORT_BUFFER; 395 } 396 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin(); 397 size_t i = 0; 398 while (iter != mObj->mSecureStops.end()) { 399 secureStops[i].ptr = iter->array(); 400 secureStops[i].length = iter->size(); 401 ++iter; 402 ++i; 403 } 404 numSecureStops = mObj->mSecureStops.size(); 405 return MEDIADRM_OK; 406} 407 408mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, 409 const AMediaDrmSecureStop &ssRelease) { 410 411 if (!mObj || mObj->mDrm == NULL) { 412 return MEDIADRM_INVALID_OBJECT_ERROR; 413 } 414 415 Vector<uint8_t> release; 416 release.appendArray(ssRelease.ptr, ssRelease.length); 417 return translateStatus(mObj->mDrm->releaseSecureStops(release)); 418} 419 420 421mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, 422 const char *&propertyValue) { 423 424 if (!mObj || mObj->mDrm == NULL) { 425 return MEDIADRM_INVALID_OBJECT_ERROR; 426 } 427 428 status_t status = mObj->mDrm->getPropertyString(String8(propertyName), 429 mObj->mPropertyString); 430 431 if (status == OK) { 432 propertyValue = mObj->mPropertyString.string(); 433 } else { 434 propertyValue = NULL; 435 } 436 return translateStatus(status); 437} 438 439mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, 440 const char *propertyName, AMediaDrmByteArray &propertyValue) { 441 if (!mObj || mObj->mDrm == NULL) { 442 return MEDIADRM_INVALID_OBJECT_ERROR; 443 } 444 445 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName), 446 mObj->mPropertyByteArray); 447 448 if (status == OK) { 449 propertyValue.ptr = mObj->mPropertyByteArray.array(); 450 propertyValue.length = mObj->mPropertyByteArray.size(); 451 } else { 452 propertyValue.ptr = NULL; 453 propertyValue.length = 0; 454 } 455 return translateStatus(status); 456} 457 458mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, 459 const char *propertyName, const char *value) { 460 if (!mObj || mObj->mDrm == NULL) { 461 return MEDIADRM_INVALID_OBJECT_ERROR; 462 } 463 464 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName), 465 String8(value))); 466} 467 468mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, 469 const char *propertyName, const uint8_t *value, size_t valueSize) { 470 471 Vector<uint8_t> byteArray; 472 byteArray.appendArray(value, valueSize); 473 474 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName), 475 byteArray)); 476} 477 478 479static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj, 480 const AMediaDrmSessionId &sessionId, 481 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 482 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) { 483 484 if (!mObj || mObj->mDrm == NULL) { 485 return MEDIADRM_INVALID_OBJECT_ERROR; 486 } 487 List<idvec_t>::iterator iter; 488 if (!findId(mObj, sessionId, iter)) { 489 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 490 } 491 492 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm)); 493 if (status != OK) { 494 return translateStatus(status); 495 } 496 497 Vector<uint8_t> keyIdVec; 498 const size_t kKeyIdSize = 16; 499 keyIdVec.appendArray(keyId, kKeyIdSize); 500 501 Vector<uint8_t> inputVec; 502 inputVec.appendArray(input, dataSize); 503 504 Vector<uint8_t> ivVec; 505 const size_t kIvSize = 16; 506 ivVec.appendArray(iv, kIvSize); 507 508 Vector<uint8_t> outputVec; 509 if (encrypt) { 510 status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 511 } else { 512 status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 513 } 514 if (status == OK) { 515 memcpy(output, outputVec.array(), outputVec.size()); 516 } 517 return translateStatus(status); 518} 519 520mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 521 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 522 const uint8_t *input, uint8_t *output, size_t dataSize) { 523 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, 524 input, output, dataSize, true); 525} 526 527mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 528 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 529 const uint8_t *input, uint8_t *output, size_t dataSize) { 530 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, 531 input, output, dataSize, false); 532} 533 534mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 535 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, 536 uint8_t *signature, size_t *signatureSize) { 537 538 if (!mObj || mObj->mDrm == NULL) { 539 return MEDIADRM_INVALID_OBJECT_ERROR; 540 } 541 List<idvec_t>::iterator iter; 542 if (!findId(mObj, sessionId, iter)) { 543 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 544 } 545 546 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 547 if (status != OK) { 548 return translateStatus(status); 549 } 550 551 Vector<uint8_t> keyIdVec; 552 const size_t kKeyIdSize = 16; 553 keyIdVec.appendArray(keyId, kKeyIdSize); 554 555 Vector<uint8_t> messageVec; 556 messageVec.appendArray(message, messageSize); 557 558 Vector<uint8_t> signatureVec; 559 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec); 560 if (signatureVec.size() > *signatureSize) { 561 return MEDIADRM_SHORT_BUFFER; 562 } 563 if (status == OK) { 564 memcpy(signature, signatureVec.array(), signatureVec.size()); 565 } 566 return translateStatus(status); 567} 568 569mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 570 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, 571 const uint8_t *signature, size_t signatureSize) { 572 573 if (!mObj || mObj->mDrm == NULL) { 574 return MEDIADRM_INVALID_OBJECT_ERROR; 575 } 576 List<idvec_t>::iterator iter; 577 if (!findId(mObj, sessionId, iter)) { 578 return MEDIADRM_SESSION_NOT_OPENED_ERROR; 579 } 580 581 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 582 if (status != OK) { 583 return translateStatus(status); 584 } 585 586 Vector<uint8_t> keyIdVec; 587 const size_t kKeyIdSize = 16; 588 keyIdVec.appendArray(keyId, kKeyIdSize); 589 590 Vector<uint8_t> messageVec; 591 messageVec.appendArray(message, messageSize); 592 593 Vector<uint8_t> signatureVec; 594 signatureVec.appendArray(signature, signatureSize); 595 596 bool match; 597 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match); 598 if (status == OK) { 599 return match ? MEDIADRM_OK : MEDIADRM_VERIFY_FAILED; 600 } 601 return translateStatus(status); 602} 603 604} // extern "C" 605 606