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