android_media_MediaDrm.cpp revision dc614f86a5a61d0b4287796dfa028c637f615d34
1/* 2 * Copyright 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 "MediaDrm-JNI" 19#include <utils/Log.h> 20 21#include "android_media_MediaDrm.h" 22 23#include "android_runtime/AndroidRuntime.h" 24#include "android_runtime/Log.h" 25#include "android_os_Parcel.h" 26#include "jni.h" 27#include "JNIHelp.h" 28 29#include <binder/IServiceManager.h> 30#include <binder/Parcel.h> 31#include <cutils/properties.h> 32#include <media/IDrm.h> 33#include <media/IMediaDrmService.h> 34#include <media/IMediaPlayerService.h> 35#include <media/stagefright/foundation/ADebug.h> 36#include <media/stagefright/MediaErrors.h> 37 38namespace android { 39 40#define FIND_CLASS(var, className) \ 41 var = env->FindClass(className); \ 42 LOG_FATAL_IF(! var, "Unable to find class " className); 43 44#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 45 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 46 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 47 48#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \ 49 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \ 50 LOG_FATAL_IF(! var, "Unable to find method " fieldName); 51 52#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 53 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \ 54 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 55 56#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \ 57 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \ 58 LOG_FATAL_IF(! var, "Unable to find static method " fieldName); 59 60 61struct RequestFields { 62 jfieldID data; 63 jfieldID defaultUrl; 64 jfieldID requestType; 65}; 66 67struct ArrayListFields { 68 jmethodID init; 69 jmethodID add; 70}; 71 72struct HashmapFields { 73 jmethodID init; 74 jmethodID get; 75 jmethodID put; 76 jmethodID entrySet; 77}; 78 79struct SetFields { 80 jmethodID iterator; 81}; 82 83struct IteratorFields { 84 jmethodID next; 85 jmethodID hasNext; 86}; 87 88struct EntryFields { 89 jmethodID getKey; 90 jmethodID getValue; 91}; 92 93struct EventTypes { 94 jint kEventProvisionRequired; 95 jint kEventKeyRequired; 96 jint kEventKeyExpired; 97 jint kEventVendorDefined; 98 jint kEventSessionReclaimed; 99} gEventTypes; 100 101struct EventWhat { 102 jint kWhatDrmEvent; 103 jint kWhatExpirationUpdate; 104 jint kWhatKeyStatusChange; 105} gEventWhat; 106 107struct KeyTypes { 108 jint kKeyTypeStreaming; 109 jint kKeyTypeOffline; 110 jint kKeyTypeRelease; 111} gKeyTypes; 112 113struct KeyRequestTypes { 114 jint kKeyRequestTypeInitial; 115 jint kKeyRequestTypeRenewal; 116 jint kKeyRequestTypeRelease; 117} gKeyRequestTypes; 118 119struct CertificateTypes { 120 jint kCertificateTypeNone; 121 jint kCertificateTypeX509; 122} gCertificateTypes; 123 124struct CertificateFields { 125 jfieldID wrappedPrivateKey; 126 jfieldID certificateData; 127}; 128 129struct StateExceptionFields { 130 jmethodID init; 131 jclass classId; 132}; 133 134struct fields_t { 135 jfieldID context; 136 jmethodID post_event; 137 RequestFields keyRequest; 138 RequestFields provisionRequest; 139 ArrayListFields arraylist; 140 HashmapFields hashmap; 141 SetFields set; 142 IteratorFields iterator; 143 EntryFields entry; 144 CertificateFields certificate; 145 StateExceptionFields stateException; 146 jclass certificateClassId; 147 jclass hashmapClassId; 148 jclass arraylistClassId; 149 jclass stringClassId; 150}; 151 152static fields_t gFields; 153 154// ---------------------------------------------------------------------------- 155// ref-counted object for callbacks 156class JNIDrmListener: public DrmListener 157{ 158public: 159 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz); 160 ~JNIDrmListener(); 161 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL); 162private: 163 JNIDrmListener(); 164 jclass mClass; // Reference to MediaDrm class 165 jobject mObject; // Weak ref to MediaDrm Java object to call on 166}; 167 168JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz) 169{ 170 // Hold onto the MediaDrm class for use in calling the static method 171 // that posts events to the application thread. 172 jclass clazz = env->GetObjectClass(thiz); 173 if (clazz == NULL) { 174 ALOGE("Can't find android/media/MediaDrm"); 175 jniThrowException(env, "java/lang/Exception", 176 "Can't find android/media/MediaDrm"); 177 return; 178 } 179 mClass = (jclass)env->NewGlobalRef(clazz); 180 181 // We use a weak reference so the MediaDrm object can be garbage collected. 182 // The reference is only used as a proxy for callbacks. 183 mObject = env->NewGlobalRef(weak_thiz); 184} 185 186JNIDrmListener::~JNIDrmListener() 187{ 188 // remove global references 189 JNIEnv *env = AndroidRuntime::getJNIEnv(); 190 env->DeleteGlobalRef(mObject); 191 env->DeleteGlobalRef(mClass); 192} 193 194void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, 195 const Parcel *obj) 196{ 197 jint jwhat; 198 jint jeventType = 0; 199 200 // translate DrmPlugin event types into their java equivalents 201 switch (eventType) { 202 case DrmPlugin::kDrmPluginEventProvisionRequired: 203 jwhat = gEventWhat.kWhatDrmEvent; 204 jeventType = gEventTypes.kEventProvisionRequired; 205 break; 206 case DrmPlugin::kDrmPluginEventKeyNeeded: 207 jwhat = gEventWhat.kWhatDrmEvent; 208 jeventType = gEventTypes.kEventKeyRequired; 209 break; 210 case DrmPlugin::kDrmPluginEventKeyExpired: 211 jwhat = gEventWhat.kWhatDrmEvent; 212 jeventType = gEventTypes.kEventKeyExpired; 213 break; 214 case DrmPlugin::kDrmPluginEventVendorDefined: 215 jwhat = gEventWhat.kWhatDrmEvent; 216 jeventType = gEventTypes.kEventVendorDefined; 217 break; 218 case DrmPlugin::kDrmPluginEventSessionReclaimed: 219 jwhat = gEventWhat.kWhatDrmEvent; 220 jeventType = gEventTypes.kEventSessionReclaimed; 221 break; 222 case DrmPlugin::kDrmPluginEventExpirationUpdate: 223 jwhat = gEventWhat.kWhatExpirationUpdate; 224 break; 225 case DrmPlugin::kDrmPluginEventKeysChange: 226 jwhat = gEventWhat.kWhatKeyStatusChange; 227 break; 228 default: 229 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType); 230 return; 231 } 232 233 JNIEnv *env = AndroidRuntime::getJNIEnv(); 234 if (obj && obj->dataSize() > 0) { 235 jobject jParcel = createJavaParcelObject(env); 236 if (jParcel != NULL) { 237 Parcel* nativeParcel = parcelForJavaObject(env, jParcel); 238 nativeParcel->setData(obj->data(), obj->dataSize()); 239 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject, 240 jwhat, jeventType, extra, jParcel); 241 env->DeleteLocalRef(jParcel); 242 } 243 } 244 245 if (env->ExceptionCheck()) { 246 ALOGW("An exception occurred while notifying an event."); 247 LOGW_EX(env); 248 env->ExceptionClear(); 249 } 250} 251 252static void throwStateException(JNIEnv *env, const char *msg, status_t err) { 253 ALOGE("Illegal state exception: %s (%d)", msg, err); 254 255 jobject exception = env->NewObject(gFields.stateException.classId, 256 gFields.stateException.init, static_cast<int>(err), 257 env->NewStringUTF(msg)); 258 env->Throw(static_cast<jthrowable>(exception)); 259} 260 261static bool throwExceptionAsNecessary( 262 JNIEnv *env, status_t err, const char *msg = NULL) { 263 264 const char *drmMessage = NULL; 265 266 switch (err) { 267 case ERROR_DRM_UNKNOWN: 268 drmMessage = "General DRM error"; 269 break; 270 case ERROR_DRM_NO_LICENSE: 271 drmMessage = "No license"; 272 break; 273 case ERROR_DRM_LICENSE_EXPIRED: 274 drmMessage = "License expired"; 275 break; 276 case ERROR_DRM_SESSION_NOT_OPENED: 277 drmMessage = "Session not opened"; 278 break; 279 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED: 280 drmMessage = "Not initialized"; 281 break; 282 case ERROR_DRM_DECRYPT: 283 drmMessage = "Decrypt error"; 284 break; 285 case ERROR_DRM_CANNOT_HANDLE: 286 drmMessage = "Unsupported scheme or data format"; 287 break; 288 case ERROR_DRM_TAMPER_DETECTED: 289 drmMessage = "Invalid state"; 290 break; 291 default: 292 break; 293 } 294 295 String8 vendorMessage; 296 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) { 297 vendorMessage = String8::format("DRM vendor-defined error: %d", err); 298 drmMessage = vendorMessage.string(); 299 } 300 301 if (err == BAD_VALUE) { 302 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 303 return true; 304 } else if (err == ERROR_DRM_NOT_PROVISIONED) { 305 jniThrowException(env, "android/media/NotProvisionedException", msg); 306 return true; 307 } else if (err == ERROR_DRM_RESOURCE_BUSY) { 308 jniThrowException(env, "android/media/ResourceBusyException", msg); 309 return true; 310 } else if (err == ERROR_DRM_DEVICE_REVOKED) { 311 jniThrowException(env, "android/media/DeniedByServerException", msg); 312 return true; 313 } else if (err == DEAD_OBJECT) { 314 jniThrowException(env, "android/media/MediaDrmResetException", 315 "mediaserver died"); 316 return true; 317 } else if (err != OK) { 318 String8 errbuf; 319 if (drmMessage != NULL) { 320 if (msg == NULL) { 321 msg = drmMessage; 322 } else { 323 errbuf = String8::format("%s: %s", msg, drmMessage); 324 msg = errbuf.string(); 325 } 326 } 327 throwStateException(env, msg, err); 328 return true; 329 } 330 return false; 331} 332 333static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) { 334 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context); 335 return jdrm ? jdrm->getDrm() : NULL; 336} 337 338JDrm::JDrm( 339 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) { 340 mObject = env->NewWeakGlobalRef(thiz); 341 mDrm = MakeDrm(uuid); 342 if (mDrm != NULL) { 343 mDrm->setListener(this); 344 } 345} 346 347JDrm::~JDrm() { 348 JNIEnv *env = AndroidRuntime::getJNIEnv(); 349 350 env->DeleteWeakGlobalRef(mObject); 351 mObject = NULL; 352} 353 354// static 355sp<IDrm> JDrm::MakeDrm() { 356 sp<IServiceManager> sm = defaultServiceManager(); 357 sp<IDrm> drm; 358 359 char value[PROPERTY_VALUE_MAX]; 360 if (property_get("media.mediadrmservice.enable", value, NULL) 361 && (!strcmp("1", value) || !strcasecmp("true", value))) { 362 sp<IBinder> binder = 363 sm->getService(String16("media.drm")); 364 sp<IMediaDrmService> service = 365 interface_cast<IMediaDrmService>(binder); 366 if (service == NULL) { 367 return NULL; 368 } 369 drm = service->makeDrm(); 370 } else { 371 sp<IBinder> binder = 372 sm->getService(String16("media.player")); 373 sp<IMediaPlayerService> service = 374 interface_cast<IMediaPlayerService>(binder); 375 if (service == NULL) { 376 return NULL; 377 } 378 drm = service->makeDrm(); 379 } 380 381 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) { 382 return NULL; 383 } 384 385 return drm; 386} 387 388// static 389sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) { 390 sp<IDrm> drm = MakeDrm(); 391 392 if (drm == NULL) { 393 return NULL; 394 } 395 396 status_t err = drm->createPlugin(uuid); 397 398 if (err != OK) { 399 return NULL; 400 } 401 402 return drm; 403} 404 405status_t JDrm::setListener(const sp<DrmListener>& listener) { 406 Mutex::Autolock lock(mLock); 407 mListener = listener; 408 return OK; 409} 410 411void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) { 412 sp<DrmListener> listener; 413 mLock.lock(); 414 listener = mListener; 415 mLock.unlock(); 416 417 if (listener != NULL) { 418 Mutex::Autolock lock(mNotifyLock); 419 listener->notify(eventType, extra, obj); 420 } 421} 422 423void JDrm::disconnect() { 424 if (mDrm != NULL) { 425 mDrm->destroyPlugin(); 426 mDrm.clear(); 427 } 428} 429 430 431// static 432bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { 433 sp<IDrm> drm = MakeDrm(); 434 435 if (drm == NULL) { 436 return false; 437 } 438 439 return drm->isCryptoSchemeSupported(uuid, mimeType); 440} 441 442status_t JDrm::initCheck() const { 443 return mDrm == NULL ? NO_INIT : OK; 444} 445 446// JNI conversion utilities 447static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) { 448 Vector<uint8_t> vector; 449 size_t length = env->GetArrayLength(byteArray); 450 vector.insertAt((size_t)0, length); 451 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray()); 452 return vector; 453} 454 455static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) { 456 size_t length = vector.size(); 457 jbyteArray result = env->NewByteArray(length); 458 if (result != NULL) { 459 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array()); 460 } 461 return result; 462} 463 464static String8 JStringToString8(JNIEnv *env, jstring const &jstr) { 465 String8 result; 466 467 const char *s = env->GetStringUTFChars(jstr, NULL); 468 if (s) { 469 result = s; 470 env->ReleaseStringUTFChars(jstr, s); 471 } 472 return result; 473} 474 475/* 476 import java.util.HashMap; 477 import java.util.Set; 478 import java.Map.Entry; 479 import jav.util.Iterator; 480 481 HashMap<k, v> hm; 482 Set<Entry<k, v> > s = hm.entrySet(); 483 Iterator i = s.iterator(); 484 Entry e = s.next(); 485*/ 486 487static KeyedVector<String8, String8> HashMapToKeyedVector( 488 JNIEnv *env, jobject &hashMap, bool* pIsOK) { 489 jclass clazz = gFields.stringClassId; 490 KeyedVector<String8, String8> keyedVector; 491 *pIsOK = true; 492 493 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet); 494 if (entrySet) { 495 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator); 496 if (iterator) { 497 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext); 498 while (hasNext) { 499 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next); 500 if (entry) { 501 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey); 502 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) { 503 jniThrowException(env, "java/lang/IllegalArgumentException", 504 "HashMap key is not a String"); 505 env->DeleteLocalRef(entry); 506 *pIsOK = false; 507 break; 508 } 509 jstring jkey = static_cast<jstring>(obj); 510 511 obj = env->CallObjectMethod(entry, gFields.entry.getValue); 512 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) { 513 jniThrowException(env, "java/lang/IllegalArgumentException", 514 "HashMap value is not a String"); 515 env->DeleteLocalRef(entry); 516 *pIsOK = false; 517 break; 518 } 519 jstring jvalue = static_cast<jstring>(obj); 520 521 String8 key = JStringToString8(env, jkey); 522 String8 value = JStringToString8(env, jvalue); 523 keyedVector.add(key, value); 524 525 env->DeleteLocalRef(jkey); 526 env->DeleteLocalRef(jvalue); 527 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext); 528 } 529 env->DeleteLocalRef(entry); 530 } 531 env->DeleteLocalRef(iterator); 532 } 533 env->DeleteLocalRef(entrySet); 534 } 535 return keyedVector; 536} 537 538static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) { 539 jclass clazz = gFields.hashmapClassId; 540 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init); 541 for (size_t i = 0; i < map.size(); ++i) { 542 jstring jkey = env->NewStringUTF(map.keyAt(i).string()); 543 jstring jvalue = env->NewStringUTF(map.valueAt(i).string()); 544 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue); 545 env->DeleteLocalRef(jkey); 546 env->DeleteLocalRef(jvalue); 547 } 548 return hashMap; 549} 550 551static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env, 552 List<Vector<uint8_t> > list) { 553 jclass clazz = gFields.arraylistClassId; 554 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init); 555 List<Vector<uint8_t> >::iterator iter = list.begin(); 556 while (iter != list.end()) { 557 jbyteArray byteArray = VectorToJByteArray(env, *iter); 558 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray); 559 env->DeleteLocalRef(byteArray); 560 iter++; 561 } 562 563 return arrayList; 564} 565 566} // namespace android 567 568using namespace android; 569 570static sp<JDrm> setDrm( 571 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) { 572 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context); 573 if (drm != NULL) { 574 drm->incStrong(thiz); 575 } 576 if (old != NULL) { 577 old->decStrong(thiz); 578 } 579 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get())); 580 581 return old; 582} 583 584static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId) 585{ 586 if (drm == NULL) { 587 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); 588 return false; 589 } 590 591 if (jsessionId == NULL) { 592 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null"); 593 return false; 594 } 595 return true; 596} 597 598static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) { 599 sp<JDrm> drm = setDrm(env, thiz, NULL); 600 if (drm != NULL) { 601 drm->setListener(NULL); 602 drm->disconnect(); 603 } 604} 605 606static void android_media_MediaDrm_native_init(JNIEnv *env) { 607 jclass clazz; 608 FIND_CLASS(clazz, "android/media/MediaDrm"); 609 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J"); 610 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative", 611 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 612 613 jfieldID field; 614 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I"); 615 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field); 616 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I"); 617 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field); 618 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I"); 619 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field); 620 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I"); 621 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field); 622 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I"); 623 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field); 624 625 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I"); 626 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field); 627 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I"); 628 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field); 629 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I"); 630 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field); 631 632 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I"); 633 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field); 634 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I"); 635 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field); 636 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I"); 637 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field); 638 639 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I"); 640 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field); 641 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I"); 642 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field); 643 644 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); 645 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); 646 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); 647 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I"); 648 649 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I"); 650 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field); 651 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I"); 652 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field); 653 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I"); 654 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field); 655 656 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest"); 657 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B"); 658 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); 659 660 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate"); 661 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B"); 662 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B"); 663 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz)); 664 665 FIND_CLASS(clazz, "java/util/ArrayList"); 666 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V"); 667 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z"); 668 669 FIND_CLASS(clazz, "java/util/HashMap"); 670 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V"); 671 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 672 GET_METHOD_ID(gFields.hashmap.put, clazz, "put", 673 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 674 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;"); 675 676 FIND_CLASS(clazz, "java/util/Set"); 677 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;"); 678 679 FIND_CLASS(clazz, "java/util/Iterator"); 680 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;"); 681 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z"); 682 683 FIND_CLASS(clazz, "java/util/Map$Entry"); 684 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;"); 685 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;"); 686 687 FIND_CLASS(clazz, "java/util/HashMap"); 688 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz)); 689 690 FIND_CLASS(clazz, "java/lang/String"); 691 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz)); 692 693 FIND_CLASS(clazz, "java/util/ArrayList"); 694 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz)); 695 696 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException"); 697 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V"); 698 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz)); 699} 700 701static void android_media_MediaDrm_native_setup( 702 JNIEnv *env, jobject thiz, 703 jobject weak_this, jbyteArray uuidObj) { 704 705 if (uuidObj == NULL) { 706 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null"); 707 return; 708 } 709 710 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj); 711 712 if (uuid.size() != 16) { 713 jniThrowException(env, "java/lang/IllegalArgumentException", 714 "invalid UUID size, expected 16 bytes"); 715 return; 716 } 717 718 sp<JDrm> drm = new JDrm(env, thiz, uuid.array()); 719 720 status_t err = drm->initCheck(); 721 722 if (err != OK) { 723 jniThrowException( 724 env, 725 "android/media/UnsupportedSchemeException", 726 "Failed to instantiate drm object."); 727 return; 728 } 729 730 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this); 731 drm->setListener(listener); 732 setDrm(env, thiz, drm); 733} 734 735static void android_media_MediaDrm_native_finalize( 736 JNIEnv *env, jobject thiz) { 737 android_media_MediaDrm_release(env, thiz); 738} 739 740static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative( 741 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) { 742 743 if (uuidObj == NULL) { 744 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 745 return false; 746 } 747 748 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj); 749 750 if (uuid.size() != 16) { 751 jniThrowException( 752 env, 753 "java/lang/IllegalArgumentException", 754 "invalid UUID size, expected 16 bytes"); 755 return false; 756 } 757 758 String8 mimeType; 759 if (jmimeType != NULL) { 760 mimeType = JStringToString8(env, jmimeType); 761 } 762 763 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType); 764} 765 766static jbyteArray android_media_MediaDrm_openSession( 767 JNIEnv *env, jobject thiz) { 768 sp<IDrm> drm = GetDrm(env, thiz); 769 770 if (drm == NULL) { 771 jniThrowException(env, "java/lang/IllegalStateException", 772 "MediaDrm obj is null"); 773 return NULL; 774 } 775 776 Vector<uint8_t> sessionId; 777 status_t err = drm->openSession(sessionId); 778 779 if (throwExceptionAsNecessary(env, err, "Failed to open session")) { 780 return NULL; 781 } 782 783 return VectorToJByteArray(env, sessionId); 784} 785 786static void android_media_MediaDrm_closeSession( 787 JNIEnv *env, jobject thiz, jbyteArray jsessionId) { 788 sp<IDrm> drm = GetDrm(env, thiz); 789 790 if (!CheckSession(env, drm, jsessionId)) { 791 return; 792 } 793 794 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 795 796 status_t err = drm->closeSession(sessionId); 797 798 throwExceptionAsNecessary(env, err, "Failed to close session"); 799} 800 801static jobject android_media_MediaDrm_getKeyRequest( 802 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData, 803 jstring jmimeType, jint jkeyType, jobject joptParams) { 804 sp<IDrm> drm = GetDrm(env, thiz); 805 806 if (!CheckSession(env, drm, jsessionId)) { 807 return NULL; 808 } 809 810 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 811 812 Vector<uint8_t> initData; 813 if (jinitData != NULL) { 814 initData = JByteArrayToVector(env, jinitData); 815 } 816 817 String8 mimeType; 818 if (jmimeType != NULL) { 819 mimeType = JStringToString8(env, jmimeType); 820 } 821 822 DrmPlugin::KeyType keyType; 823 if (jkeyType == gKeyTypes.kKeyTypeStreaming) { 824 keyType = DrmPlugin::kKeyType_Streaming; 825 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) { 826 keyType = DrmPlugin::kKeyType_Offline; 827 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) { 828 keyType = DrmPlugin::kKeyType_Release; 829 } else { 830 jniThrowException(env, "java/lang/IllegalArgumentException", 831 "invalid keyType"); 832 return NULL; 833 } 834 835 KeyedVector<String8, String8> optParams; 836 if (joptParams != NULL) { 837 bool isOK; 838 optParams = HashMapToKeyedVector(env, joptParams, &isOK); 839 if (!isOK) { 840 return NULL; 841 } 842 } 843 844 Vector<uint8_t> request; 845 String8 defaultUrl; 846 DrmPlugin::KeyRequestType keyRequestType; 847 848 status_t err = drm->getKeyRequest(sessionId, initData, mimeType, 849 keyType, optParams, request, defaultUrl, &keyRequestType); 850 851 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) { 852 return NULL; 853 } 854 855 // Fill out return obj 856 jclass clazz; 857 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); 858 859 jobject keyObj = NULL; 860 861 if (clazz) { 862 keyObj = env->AllocObject(clazz); 863 jbyteArray jrequest = VectorToJByteArray(env, request); 864 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest); 865 866 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string()); 867 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl); 868 869 switch (keyRequestType) { 870 case DrmPlugin::kKeyRequestType_Initial: 871 env->SetIntField(keyObj, gFields.keyRequest.requestType, 872 gKeyRequestTypes.kKeyRequestTypeInitial); 873 break; 874 case DrmPlugin::kKeyRequestType_Renewal: 875 env->SetIntField(keyObj, gFields.keyRequest.requestType, 876 gKeyRequestTypes.kKeyRequestTypeRenewal); 877 break; 878 case DrmPlugin::kKeyRequestType_Release: 879 env->SetIntField(keyObj, gFields.keyRequest.requestType, 880 gKeyRequestTypes.kKeyRequestTypeRelease); 881 break; 882 default: 883 throwStateException(env, "DRM plugin failure: unknown key request type", 884 ERROR_DRM_UNKNOWN); 885 break; 886 } 887 } 888 889 return keyObj; 890} 891 892static jbyteArray android_media_MediaDrm_provideKeyResponse( 893 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) { 894 sp<IDrm> drm = GetDrm(env, thiz); 895 896 if (!CheckSession(env, drm, jsessionId)) { 897 return NULL; 898 } 899 900 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 901 902 if (jresponse == NULL) { 903 jniThrowException(env, "java/lang/IllegalArgumentException", 904 "key response is null"); 905 return NULL; 906 } 907 Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); 908 Vector<uint8_t> keySetId; 909 910 status_t err = drm->provideKeyResponse(sessionId, response, keySetId); 911 912 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) { 913 return NULL; 914 } 915 return VectorToJByteArray(env, keySetId); 916} 917 918static void android_media_MediaDrm_removeKeys( 919 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) { 920 sp<IDrm> drm = GetDrm(env, thiz); 921 922 if (jkeysetId == NULL) { 923 jniThrowException(env, "java/lang/IllegalArgumentException", 924 "keySetId is null"); 925 return; 926 } 927 928 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId)); 929 930 status_t err = drm->removeKeys(keySetId); 931 932 throwExceptionAsNecessary(env, err, "Failed to remove keys"); 933} 934 935static void android_media_MediaDrm_restoreKeys( 936 JNIEnv *env, jobject thiz, jbyteArray jsessionId, 937 jbyteArray jkeysetId) { 938 939 sp<IDrm> drm = GetDrm(env, thiz); 940 941 if (!CheckSession(env, drm, jsessionId)) { 942 return; 943 } 944 945 if (jkeysetId == NULL) { 946 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 947 return; 948 } 949 950 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 951 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId)); 952 953 status_t err = drm->restoreKeys(sessionId, keySetId); 954 955 throwExceptionAsNecessary(env, err, "Failed to restore keys"); 956} 957 958static jobject android_media_MediaDrm_queryKeyStatus( 959 JNIEnv *env, jobject thiz, jbyteArray jsessionId) { 960 sp<IDrm> drm = GetDrm(env, thiz); 961 962 if (!CheckSession(env, drm, jsessionId)) { 963 return NULL; 964 } 965 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 966 967 KeyedVector<String8, String8> infoMap; 968 969 status_t err = drm->queryKeyStatus(sessionId, infoMap); 970 971 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) { 972 return NULL; 973 } 974 975 return KeyedVectorToHashMap(env, infoMap); 976} 977 978static jobject android_media_MediaDrm_getProvisionRequestNative( 979 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) { 980 sp<IDrm> drm = GetDrm(env, thiz); 981 982 if (drm == NULL) { 983 jniThrowException(env, "java/lang/IllegalStateException", 984 "MediaDrm obj is null"); 985 return NULL; 986 } 987 988 Vector<uint8_t> request; 989 String8 defaultUrl; 990 991 String8 certType; 992 if (jcertType == gCertificateTypes.kCertificateTypeX509) { 993 certType = "X.509"; 994 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) { 995 certType = "none"; 996 } else { 997 certType = "invalid"; 998 } 999 1000 String8 certAuthority = JStringToString8(env, jcertAuthority); 1001 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl); 1002 1003 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) { 1004 return NULL; 1005 } 1006 1007 // Fill out return obj 1008 jclass clazz; 1009 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest"); 1010 1011 jobject provisionObj = NULL; 1012 1013 if (clazz) { 1014 provisionObj = env->AllocObject(clazz); 1015 jbyteArray jrequest = VectorToJByteArray(env, request); 1016 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest); 1017 1018 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string()); 1019 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl); 1020 } 1021 1022 return provisionObj; 1023} 1024 1025static jobject android_media_MediaDrm_provideProvisionResponseNative( 1026 JNIEnv *env, jobject thiz, jbyteArray jresponse) { 1027 sp<IDrm> drm = GetDrm(env, thiz); 1028 1029 if (drm == NULL) { 1030 jniThrowException(env, "java/lang/IllegalStateException", 1031 "MediaDrm obj is null"); 1032 return NULL; 1033 } 1034 1035 if (jresponse == NULL) { 1036 jniThrowException(env, "java/lang/IllegalArgumentException", 1037 "provision response is null"); 1038 return NULL; 1039 } 1040 1041 Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); 1042 Vector<uint8_t> certificate, wrappedKey; 1043 1044 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey); 1045 1046 // Fill out return obj 1047 jclass clazz = gFields.certificateClassId; 1048 1049 jobject certificateObj = NULL; 1050 1051 if (clazz && certificate.size() && wrappedKey.size()) { 1052 certificateObj = env->AllocObject(clazz); 1053 jbyteArray jcertificate = VectorToJByteArray(env, certificate); 1054 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate); 1055 1056 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey); 1057 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey); 1058 } 1059 1060 throwExceptionAsNecessary(env, err, "Failed to handle provision response"); 1061 return certificateObj; 1062} 1063 1064static jobject android_media_MediaDrm_getSecureStops( 1065 JNIEnv *env, jobject thiz) { 1066 sp<IDrm> drm = GetDrm(env, thiz); 1067 1068 if (drm == NULL) { 1069 jniThrowException(env, "java/lang/IllegalStateException", 1070 "MediaDrm obj is null"); 1071 return NULL; 1072 } 1073 1074 List<Vector<uint8_t> > secureStops; 1075 1076 status_t err = drm->getSecureStops(secureStops); 1077 1078 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) { 1079 return NULL; 1080 } 1081 1082 return ListOfVectorsToArrayListOfByteArray(env, secureStops); 1083} 1084 1085static jbyteArray android_media_MediaDrm_getSecureStop( 1086 JNIEnv *env, jobject thiz, jbyteArray ssid) { 1087 sp<IDrm> drm = GetDrm(env, thiz); 1088 1089 if (drm == NULL) { 1090 jniThrowException(env, "java/lang/IllegalStateException", 1091 "MediaDrm obj is null"); 1092 return NULL; 1093 } 1094 1095 Vector<uint8_t> secureStop; 1096 1097 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop); 1098 1099 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) { 1100 return NULL; 1101 } 1102 1103 return VectorToJByteArray(env, secureStop); 1104} 1105 1106static void android_media_MediaDrm_releaseSecureStops( 1107 JNIEnv *env, jobject thiz, jbyteArray jssRelease) { 1108 sp<IDrm> drm = GetDrm(env, thiz); 1109 1110 if (drm == NULL) { 1111 jniThrowException(env, "java/lang/IllegalStateException", 1112 "MediaDrm obj is null"); 1113 return; 1114 } 1115 1116 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease)); 1117 1118 status_t err = drm->releaseSecureStops(ssRelease); 1119 1120 throwExceptionAsNecessary(env, err, "Failed to release secure stops"); 1121} 1122 1123static void android_media_MediaDrm_releaseAllSecureStops( 1124 JNIEnv *env, jobject thiz) { 1125 sp<IDrm> drm = GetDrm(env, thiz); 1126 1127 if (drm == NULL) { 1128 jniThrowException(env, "java/lang/IllegalStateException", 1129 "MediaDrm obj is null"); 1130 return; 1131 } 1132 1133 status_t err = drm->releaseAllSecureStops(); 1134 1135 throwExceptionAsNecessary(env, err, "Failed to release all secure stops"); 1136} 1137 1138static jstring android_media_MediaDrm_getPropertyString( 1139 JNIEnv *env, jobject thiz, jstring jname) { 1140 sp<IDrm> drm = GetDrm(env, thiz); 1141 1142 if (drm == NULL) { 1143 jniThrowException(env, "java/lang/IllegalStateException", 1144 "MediaDrm obj is null"); 1145 return NULL; 1146 } 1147 1148 if (jname == NULL) { 1149 jniThrowException(env, "java/lang/IllegalArgumentException", 1150 "property name String is null"); 1151 return NULL; 1152 } 1153 1154 String8 name = JStringToString8(env, jname); 1155 String8 value; 1156 1157 status_t err = drm->getPropertyString(name, value); 1158 1159 if (throwExceptionAsNecessary(env, err, "Failed to get property")) { 1160 return NULL; 1161 } 1162 1163 return env->NewStringUTF(value.string()); 1164} 1165 1166static jbyteArray android_media_MediaDrm_getPropertyByteArray( 1167 JNIEnv *env, jobject thiz, jstring jname) { 1168 sp<IDrm> drm = GetDrm(env, thiz); 1169 1170 if (drm == NULL) { 1171 jniThrowException(env, "java/lang/IllegalStateException", 1172 "MediaDrm obj is null"); 1173 return NULL; 1174 } 1175 1176 if (jname == NULL) { 1177 jniThrowException(env, "java/lang/IllegalArgumentException", 1178 "property name String is null"); 1179 return NULL; 1180 } 1181 1182 String8 name = JStringToString8(env, jname); 1183 Vector<uint8_t> value; 1184 1185 status_t err = drm->getPropertyByteArray(name, value); 1186 1187 if (throwExceptionAsNecessary(env, err, "Failed to get property")) { 1188 return NULL; 1189 } 1190 1191 return VectorToJByteArray(env, value); 1192} 1193 1194static void android_media_MediaDrm_setPropertyString( 1195 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) { 1196 sp<IDrm> drm = GetDrm(env, thiz); 1197 1198 if (drm == NULL) { 1199 jniThrowException(env, "java/lang/IllegalStateException", 1200 "MediaDrm obj is null"); 1201 return; 1202 } 1203 1204 if (jname == NULL) { 1205 jniThrowException(env, "java/lang/IllegalArgumentException", 1206 "property name String is null"); 1207 return; 1208 } 1209 1210 if (jvalue == NULL) { 1211 jniThrowException(env, "java/lang/IllegalArgumentException", 1212 "property value String is null"); 1213 return; 1214 } 1215 1216 String8 name = JStringToString8(env, jname); 1217 String8 value = JStringToString8(env, jvalue); 1218 1219 status_t err = drm->setPropertyString(name, value); 1220 1221 throwExceptionAsNecessary(env, err, "Failed to set property"); 1222} 1223 1224static void android_media_MediaDrm_setPropertyByteArray( 1225 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) { 1226 sp<IDrm> drm = GetDrm(env, thiz); 1227 1228 if (drm == NULL) { 1229 jniThrowException(env, "java/lang/IllegalStateException", 1230 "MediaDrm obj is null"); 1231 return; 1232 } 1233 1234 if (jname == NULL) { 1235 jniThrowException(env, "java/lang/IllegalArgumentException", 1236 "property name String is null"); 1237 return; 1238 } 1239 1240 if (jvalue == NULL) { 1241 jniThrowException(env, "java/lang/IllegalArgumentException", 1242 "property value byte array is null"); 1243 return; 1244 } 1245 1246 String8 name = JStringToString8(env, jname); 1247 Vector<uint8_t> value = JByteArrayToVector(env, jvalue); 1248 1249 status_t err = drm->setPropertyByteArray(name, value); 1250 1251 throwExceptionAsNecessary(env, err, "Failed to set property"); 1252} 1253 1254static void android_media_MediaDrm_setCipherAlgorithmNative( 1255 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1256 jstring jalgorithm) { 1257 1258 sp<IDrm> drm = GetDrm(env, jdrm); 1259 1260 if (!CheckSession(env, drm, jsessionId)) { 1261 return; 1262 } 1263 1264 if (jalgorithm == NULL) { 1265 jniThrowException(env, "java/lang/IllegalArgumentException", 1266 "algorithm String is null"); 1267 return; 1268 } 1269 1270 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1271 String8 algorithm = JStringToString8(env, jalgorithm); 1272 1273 status_t err = drm->setCipherAlgorithm(sessionId, algorithm); 1274 1275 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm"); 1276} 1277 1278static void android_media_MediaDrm_setMacAlgorithmNative( 1279 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1280 jstring jalgorithm) { 1281 1282 sp<IDrm> drm = GetDrm(env, jdrm); 1283 1284 if (!CheckSession(env, drm, jsessionId)) { 1285 return; 1286 } 1287 1288 if (jalgorithm == NULL) { 1289 jniThrowException(env, "java/lang/IllegalArgumentException", 1290 "algorithm String is null"); 1291 return; 1292 } 1293 1294 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1295 String8 algorithm = JStringToString8(env, jalgorithm); 1296 1297 status_t err = drm->setMacAlgorithm(sessionId, algorithm); 1298 1299 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm"); 1300} 1301 1302 1303static jbyteArray android_media_MediaDrm_encryptNative( 1304 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1305 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) { 1306 1307 sp<IDrm> drm = GetDrm(env, jdrm); 1308 1309 if (!CheckSession(env, drm, jsessionId)) { 1310 return NULL; 1311 } 1312 1313 if (jkeyId == NULL || jinput == NULL || jiv == NULL) { 1314 jniThrowException(env, "java/lang/IllegalArgumentException", 1315 "required argument is null"); 1316 return NULL; 1317 } 1318 1319 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1320 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1321 Vector<uint8_t> input(JByteArrayToVector(env, jinput)); 1322 Vector<uint8_t> iv(JByteArrayToVector(env, jiv)); 1323 Vector<uint8_t> output; 1324 1325 status_t err = drm->encrypt(sessionId, keyId, input, iv, output); 1326 1327 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) { 1328 return NULL; 1329 } 1330 1331 return VectorToJByteArray(env, output); 1332} 1333 1334static jbyteArray android_media_MediaDrm_decryptNative( 1335 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1336 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) { 1337 1338 sp<IDrm> drm = GetDrm(env, jdrm); 1339 1340 if (!CheckSession(env, drm, jsessionId)) { 1341 return NULL; 1342 } 1343 1344 if (jkeyId == NULL || jinput == NULL || jiv == NULL) { 1345 jniThrowException(env, "java/lang/IllegalArgumentException", 1346 "required argument is null"); 1347 return NULL; 1348 } 1349 1350 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1351 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1352 Vector<uint8_t> input(JByteArrayToVector(env, jinput)); 1353 Vector<uint8_t> iv(JByteArrayToVector(env, jiv)); 1354 Vector<uint8_t> output; 1355 1356 status_t err = drm->decrypt(sessionId, keyId, input, iv, output); 1357 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) { 1358 return NULL; 1359 } 1360 1361 return VectorToJByteArray(env, output); 1362} 1363 1364static jbyteArray android_media_MediaDrm_signNative( 1365 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1366 jbyteArray jkeyId, jbyteArray jmessage) { 1367 1368 sp<IDrm> drm = GetDrm(env, jdrm); 1369 1370 if (!CheckSession(env, drm, jsessionId)) { 1371 return NULL; 1372 } 1373 1374 if (jkeyId == NULL || jmessage == NULL) { 1375 jniThrowException(env, "java/lang/IllegalArgumentException", 1376 "required argument is null"); 1377 return NULL; 1378 } 1379 1380 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1381 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1382 Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); 1383 Vector<uint8_t> signature; 1384 1385 status_t err = drm->sign(sessionId, keyId, message, signature); 1386 1387 if (throwExceptionAsNecessary(env, err, "Failed to sign")) { 1388 return NULL; 1389 } 1390 1391 return VectorToJByteArray(env, signature); 1392} 1393 1394static jboolean android_media_MediaDrm_verifyNative( 1395 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1396 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) { 1397 1398 sp<IDrm> drm = GetDrm(env, jdrm); 1399 1400 if (!CheckSession(env, drm, jsessionId)) { 1401 return false; 1402 } 1403 1404 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) { 1405 jniThrowException(env, "java/lang/IllegalArgumentException", 1406 "required argument is null"); 1407 return false; 1408 } 1409 1410 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1411 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1412 Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); 1413 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature)); 1414 bool match; 1415 1416 status_t err = drm->verify(sessionId, keyId, message, signature, match); 1417 1418 throwExceptionAsNecessary(env, err, "Failed to verify"); 1419 return match; 1420} 1421 1422 1423static jbyteArray android_media_MediaDrm_signRSANative( 1424 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1425 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) { 1426 1427 sp<IDrm> drm = GetDrm(env, jdrm); 1428 1429 if (!CheckSession(env, drm, jsessionId)) { 1430 return NULL; 1431 } 1432 1433 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) { 1434 jniThrowException(env, "java/lang/IllegalArgumentException", 1435 "required argument is null"); 1436 return NULL; 1437 } 1438 1439 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1440 String8 algorithm = JStringToString8(env, jalgorithm); 1441 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey)); 1442 Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); 1443 Vector<uint8_t> signature; 1444 1445 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature); 1446 1447 if (throwExceptionAsNecessary(env, err, "Failed to sign")) { 1448 return NULL; 1449 } 1450 1451 return VectorToJByteArray(env, signature); 1452} 1453 1454 1455static const JNINativeMethod gMethods[] = { 1456 { "release", "()V", (void *)android_media_MediaDrm_release }, 1457 { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, 1458 1459 { "native_setup", "(Ljava/lang/Object;[B)V", 1460 (void *)android_media_MediaDrm_native_setup }, 1461 1462 { "native_finalize", "()V", 1463 (void *)android_media_MediaDrm_native_finalize }, 1464 1465 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z", 1466 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative }, 1467 1468 { "openSession", "()[B", 1469 (void *)android_media_MediaDrm_openSession }, 1470 1471 { "closeSession", "([B)V", 1472 (void *)android_media_MediaDrm_closeSession }, 1473 1474 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)" 1475 "Landroid/media/MediaDrm$KeyRequest;", 1476 (void *)android_media_MediaDrm_getKeyRequest }, 1477 1478 { "provideKeyResponse", "([B[B)[B", 1479 (void *)android_media_MediaDrm_provideKeyResponse }, 1480 1481 { "removeKeys", "([B)V", 1482 (void *)android_media_MediaDrm_removeKeys }, 1483 1484 { "restoreKeys", "([B[B)V", 1485 (void *)android_media_MediaDrm_restoreKeys }, 1486 1487 { "queryKeyStatus", "([B)Ljava/util/HashMap;", 1488 (void *)android_media_MediaDrm_queryKeyStatus }, 1489 1490 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;", 1491 (void *)android_media_MediaDrm_getProvisionRequestNative }, 1492 1493 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;", 1494 (void *)android_media_MediaDrm_provideProvisionResponseNative }, 1495 1496 { "getSecureStops", "()Ljava/util/List;", 1497 (void *)android_media_MediaDrm_getSecureStops }, 1498 1499 { "getSecureStop", "([B)[B", 1500 (void *)android_media_MediaDrm_getSecureStop }, 1501 1502 { "releaseSecureStops", "([B)V", 1503 (void *)android_media_MediaDrm_releaseSecureStops }, 1504 1505 { "releaseAllSecureStops", "()V", 1506 (void *)android_media_MediaDrm_releaseAllSecureStops }, 1507 1508 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", 1509 (void *)android_media_MediaDrm_getPropertyString }, 1510 1511 { "getPropertyByteArray", "(Ljava/lang/String;)[B", 1512 (void *)android_media_MediaDrm_getPropertyByteArray }, 1513 1514 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V", 1515 (void *)android_media_MediaDrm_setPropertyString }, 1516 1517 { "setPropertyByteArray", "(Ljava/lang/String;[B)V", 1518 (void *)android_media_MediaDrm_setPropertyByteArray }, 1519 1520 { "setCipherAlgorithmNative", 1521 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V", 1522 (void *)android_media_MediaDrm_setCipherAlgorithmNative }, 1523 1524 { "setMacAlgorithmNative", 1525 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V", 1526 (void *)android_media_MediaDrm_setMacAlgorithmNative }, 1527 1528 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B", 1529 (void *)android_media_MediaDrm_encryptNative }, 1530 1531 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B", 1532 (void *)android_media_MediaDrm_decryptNative }, 1533 1534 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B", 1535 (void *)android_media_MediaDrm_signNative }, 1536 1537 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z", 1538 (void *)android_media_MediaDrm_verifyNative }, 1539 1540 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B", 1541 (void *)android_media_MediaDrm_signRSANative }, 1542}; 1543 1544int register_android_media_Drm(JNIEnv *env) { 1545 return AndroidRuntime::registerNativeMethods(env, 1546 "android/media/MediaDrm", gMethods, NELEM(gMethods)); 1547} 1548