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