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 jbyteArray android_media_MediaDrm_getSecureStop( 1007 JNIEnv *env, jobject thiz, jbyteArray ssid) { 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 NULL; 1014 } 1015 1016 Vector<uint8_t> secureStop; 1017 1018 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop); 1019 1020 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) { 1021 return NULL; 1022 } 1023 1024 return VectorToJByteArray(env, secureStop); 1025 } 1026 1027 static void android_media_MediaDrm_releaseSecureStops( 1028 JNIEnv *env, jobject thiz, jbyteArray jssRelease) { 1029 sp<IDrm> drm = GetDrm(env, thiz); 1030 1031 if (drm == NULL) { 1032 jniThrowException(env, "java/lang/IllegalStateException", 1033 "MediaDrm obj is null"); 1034 return; 1035 } 1036 1037 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease)); 1038 1039 status_t err = drm->releaseSecureStops(ssRelease); 1040 1041 throwExceptionAsNecessary(env, err, "Failed to release secure stops"); 1042 } 1043 1044 static void android_media_MediaDrm_releaseAllSecureStops( 1045 JNIEnv *env, jobject thiz) { 1046 sp<IDrm> drm = GetDrm(env, thiz); 1047 1048 if (drm == NULL) { 1049 jniThrowException(env, "java/lang/IllegalStateException", 1050 "MediaDrm obj is null"); 1051 return; 1052 } 1053 1054 status_t err = drm->releaseAllSecureStops(); 1055 1056 throwExceptionAsNecessary(env, err, "Failed to release all secure stops"); 1057 } 1058 1059 static jstring android_media_MediaDrm_getPropertyString( 1060 JNIEnv *env, jobject thiz, jstring jname) { 1061 sp<IDrm> drm = GetDrm(env, thiz); 1062 1063 if (drm == NULL) { 1064 jniThrowException(env, "java/lang/IllegalStateException", 1065 "MediaDrm obj is null"); 1066 return NULL; 1067 } 1068 1069 if (jname == NULL) { 1070 jniThrowException(env, "java/lang/IllegalArgumentException", 1071 "property name String is null"); 1072 return NULL; 1073 } 1074 1075 String8 name = JStringToString8(env, jname); 1076 String8 value; 1077 1078 status_t err = drm->getPropertyString(name, value); 1079 1080 if (throwExceptionAsNecessary(env, err, "Failed to get property")) { 1081 return NULL; 1082 } 1083 1084 return env->NewStringUTF(value.string()); 1085 } 1086 1087 static jbyteArray android_media_MediaDrm_getPropertyByteArray( 1088 JNIEnv *env, jobject thiz, jstring jname) { 1089 sp<IDrm> drm = GetDrm(env, thiz); 1090 1091 if (drm == NULL) { 1092 jniThrowException(env, "java/lang/IllegalStateException", 1093 "MediaDrm obj is null"); 1094 return NULL; 1095 } 1096 1097 if (jname == NULL) { 1098 jniThrowException(env, "java/lang/IllegalArgumentException", 1099 "property name String is null"); 1100 return NULL; 1101 } 1102 1103 String8 name = JStringToString8(env, jname); 1104 Vector<uint8_t> value; 1105 1106 status_t err = drm->getPropertyByteArray(name, value); 1107 1108 if (throwExceptionAsNecessary(env, err, "Failed to get property")) { 1109 return NULL; 1110 } 1111 1112 return VectorToJByteArray(env, value); 1113 } 1114 1115 static void android_media_MediaDrm_setPropertyString( 1116 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) { 1117 sp<IDrm> drm = GetDrm(env, thiz); 1118 1119 if (drm == NULL) { 1120 jniThrowException(env, "java/lang/IllegalStateException", 1121 "MediaDrm obj is null"); 1122 return; 1123 } 1124 1125 if (jname == NULL) { 1126 jniThrowException(env, "java/lang/IllegalArgumentException", 1127 "property name String is null"); 1128 return; 1129 } 1130 1131 if (jvalue == NULL) { 1132 jniThrowException(env, "java/lang/IllegalArgumentException", 1133 "property value String is null"); 1134 return; 1135 } 1136 1137 String8 name = JStringToString8(env, jname); 1138 String8 value = JStringToString8(env, jvalue); 1139 1140 status_t err = drm->setPropertyString(name, value); 1141 1142 throwExceptionAsNecessary(env, err, "Failed to set property"); 1143 } 1144 1145 static void android_media_MediaDrm_setPropertyByteArray( 1146 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) { 1147 sp<IDrm> drm = GetDrm(env, thiz); 1148 1149 if (drm == NULL) { 1150 jniThrowException(env, "java/lang/IllegalStateException", 1151 "MediaDrm obj is null"); 1152 return; 1153 } 1154 1155 if (jname == NULL) { 1156 jniThrowException(env, "java/lang/IllegalArgumentException", 1157 "property name String is null"); 1158 return; 1159 } 1160 1161 if (jvalue == NULL) { 1162 jniThrowException(env, "java/lang/IllegalArgumentException", 1163 "property value byte array is null"); 1164 return; 1165 } 1166 1167 String8 name = JStringToString8(env, jname); 1168 Vector<uint8_t> value = JByteArrayToVector(env, jvalue); 1169 1170 status_t err = drm->setPropertyByteArray(name, value); 1171 1172 throwExceptionAsNecessary(env, err, "Failed to set property"); 1173 } 1174 1175 static void android_media_MediaDrm_setCipherAlgorithmNative( 1176 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, 1177 jstring jalgorithm) { 1178 1179 sp<IDrm> drm = GetDrm(env, jdrm); 1180 1181 if (!CheckSession(env, drm, jsessionId)) { 1182 return; 1183 } 1184 1185 if (jalgorithm == NULL) { 1186 jniThrowException(env, "java/lang/IllegalArgumentException", 1187 "algorithm String is null"); 1188 return; 1189 } 1190 1191 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1192 String8 algorithm = JStringToString8(env, jalgorithm); 1193 1194 status_t err = drm->setCipherAlgorithm(sessionId, algorithm); 1195 1196 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm"); 1197 } 1198 1199 static void android_media_MediaDrm_setMacAlgorithmNative( 1200 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, 1201 jstring jalgorithm) { 1202 1203 sp<IDrm> drm = GetDrm(env, jdrm); 1204 1205 if (!CheckSession(env, drm, jsessionId)) { 1206 return; 1207 } 1208 1209 if (jalgorithm == NULL) { 1210 jniThrowException(env, "java/lang/IllegalArgumentException", 1211 "algorithm String is null"); 1212 return; 1213 } 1214 1215 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1216 String8 algorithm = JStringToString8(env, jalgorithm); 1217 1218 status_t err = drm->setMacAlgorithm(sessionId, algorithm); 1219 1220 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm"); 1221 } 1222 1223 1224 static jbyteArray android_media_MediaDrm_encryptNative( 1225 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, 1226 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) { 1227 1228 sp<IDrm> drm = GetDrm(env, jdrm); 1229 1230 if (!CheckSession(env, drm, jsessionId)) { 1231 return NULL; 1232 } 1233 1234 if (jkeyId == NULL || jinput == NULL || jiv == NULL) { 1235 jniThrowException(env, "java/lang/IllegalArgumentException", 1236 "required argument is null"); 1237 return NULL; 1238 } 1239 1240 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1241 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1242 Vector<uint8_t> input(JByteArrayToVector(env, jinput)); 1243 Vector<uint8_t> iv(JByteArrayToVector(env, jiv)); 1244 Vector<uint8_t> output; 1245 1246 status_t err = drm->encrypt(sessionId, keyId, input, iv, output); 1247 1248 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) { 1249 return NULL; 1250 } 1251 1252 return VectorToJByteArray(env, output); 1253 } 1254 1255 static jbyteArray android_media_MediaDrm_decryptNative( 1256 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, 1257 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) { 1258 1259 sp<IDrm> drm = GetDrm(env, jdrm); 1260 1261 if (!CheckSession(env, drm, jsessionId)) { 1262 return NULL; 1263 } 1264 1265 if (jkeyId == NULL || jinput == NULL || jiv == NULL) { 1266 jniThrowException(env, "java/lang/IllegalArgumentException", 1267 "required argument is null"); 1268 return NULL; 1269 } 1270 1271 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1272 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1273 Vector<uint8_t> input(JByteArrayToVector(env, jinput)); 1274 Vector<uint8_t> iv(JByteArrayToVector(env, jiv)); 1275 Vector<uint8_t> output; 1276 1277 status_t err = drm->decrypt(sessionId, keyId, input, iv, output); 1278 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) { 1279 return NULL; 1280 } 1281 1282 return VectorToJByteArray(env, output); 1283 } 1284 1285 static jbyteArray android_media_MediaDrm_signNative( 1286 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, 1287 jbyteArray jkeyId, jbyteArray jmessage) { 1288 1289 sp<IDrm> drm = GetDrm(env, jdrm); 1290 1291 if (!CheckSession(env, drm, jsessionId)) { 1292 return NULL; 1293 } 1294 1295 if (jkeyId == NULL || jmessage == NULL) { 1296 jniThrowException(env, "java/lang/IllegalArgumentException", 1297 "required argument is null"); 1298 return NULL; 1299 } 1300 1301 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1302 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1303 Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); 1304 Vector<uint8_t> signature; 1305 1306 status_t err = drm->sign(sessionId, keyId, message, signature); 1307 1308 if (throwExceptionAsNecessary(env, err, "Failed to sign")) { 1309 return NULL; 1310 } 1311 1312 return VectorToJByteArray(env, signature); 1313 } 1314 1315 static jboolean android_media_MediaDrm_verifyNative( 1316 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, 1317 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) { 1318 1319 sp<IDrm> drm = GetDrm(env, jdrm); 1320 1321 if (!CheckSession(env, drm, jsessionId)) { 1322 return false; 1323 } 1324 1325 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) { 1326 jniThrowException(env, "java/lang/IllegalArgumentException", 1327 "required argument is null"); 1328 return false; 1329 } 1330 1331 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1332 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1333 Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); 1334 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature)); 1335 bool match; 1336 1337 status_t err = drm->verify(sessionId, keyId, message, signature, match); 1338 1339 throwExceptionAsNecessary(env, err, "Failed to verify"); 1340 return match; 1341 } 1342 1343 1344 static jbyteArray android_media_MediaDrm_signRSANative( 1345 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, 1346 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) { 1347 1348 sp<IDrm> drm = GetDrm(env, jdrm); 1349 1350 if (!CheckSession(env, drm, jsessionId)) { 1351 return NULL; 1352 } 1353 1354 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) { 1355 jniThrowException(env, "java/lang/IllegalArgumentException", 1356 "required argument is null"); 1357 return NULL; 1358 } 1359 1360 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1361 String8 algorithm = JStringToString8(env, jalgorithm); 1362 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey)); 1363 Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); 1364 Vector<uint8_t> signature; 1365 1366 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature); 1367 1368 if (throwExceptionAsNecessary(env, err, "Failed to sign")) { 1369 return NULL; 1370 } 1371 1372 return VectorToJByteArray(env, signature); 1373 } 1374 1375 1376 static JNINativeMethod gMethods[] = { 1377 { "release", "()V", (void *)android_media_MediaDrm_release }, 1378 { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, 1379 1380 { "native_setup", "(Ljava/lang/Object;[B)V", 1381 (void *)android_media_MediaDrm_native_setup }, 1382 1383 { "native_finalize", "()V", 1384 (void *)android_media_MediaDrm_native_finalize }, 1385 1386 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z", 1387 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative }, 1388 1389 { "openSession", "()[B", 1390 (void *)android_media_MediaDrm_openSession }, 1391 1392 { "closeSession", "([B)V", 1393 (void *)android_media_MediaDrm_closeSession }, 1394 1395 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)" 1396 "Landroid/media/MediaDrm$KeyRequest;", 1397 (void *)android_media_MediaDrm_getKeyRequest }, 1398 1399 { "provideKeyResponse", "([B[B)[B", 1400 (void *)android_media_MediaDrm_provideKeyResponse }, 1401 1402 { "removeKeys", "([B)V", 1403 (void *)android_media_MediaDrm_removeKeys }, 1404 1405 { "restoreKeys", "([B[B)V", 1406 (void *)android_media_MediaDrm_restoreKeys }, 1407 1408 { "queryKeyStatus", "([B)Ljava/util/HashMap;", 1409 (void *)android_media_MediaDrm_queryKeyStatus }, 1410 1411 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;", 1412 (void *)android_media_MediaDrm_getProvisionRequestNative }, 1413 1414 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;", 1415 (void *)android_media_MediaDrm_provideProvisionResponseNative }, 1416 1417 { "unprovisionDevice", "()V", 1418 (void *)android_media_MediaDrm_unprovisionDeviceNative }, 1419 1420 { "getSecureStops", "()Ljava/util/List;", 1421 (void *)android_media_MediaDrm_getSecureStops }, 1422 1423 { "getSecureStop", "([B)[B", 1424 (void *)android_media_MediaDrm_getSecureStop }, 1425 1426 { "releaseSecureStops", "([B)V", 1427 (void *)android_media_MediaDrm_releaseSecureStops }, 1428 1429 { "releaseAllSecureStops", "()V", 1430 (void *)android_media_MediaDrm_releaseAllSecureStops }, 1431 1432 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", 1433 (void *)android_media_MediaDrm_getPropertyString }, 1434 1435 { "getPropertyByteArray", "(Ljava/lang/String;)[B", 1436 (void *)android_media_MediaDrm_getPropertyByteArray }, 1437 1438 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V", 1439 (void *)android_media_MediaDrm_setPropertyString }, 1440 1441 { "setPropertyByteArray", "(Ljava/lang/String;[B)V", 1442 (void *)android_media_MediaDrm_setPropertyByteArray }, 1443 1444 { "setCipherAlgorithmNative", 1445 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V", 1446 (void *)android_media_MediaDrm_setCipherAlgorithmNative }, 1447 1448 { "setMacAlgorithmNative", 1449 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V", 1450 (void *)android_media_MediaDrm_setMacAlgorithmNative }, 1451 1452 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B", 1453 (void *)android_media_MediaDrm_encryptNative }, 1454 1455 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B", 1456 (void *)android_media_MediaDrm_decryptNative }, 1457 1458 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B", 1459 (void *)android_media_MediaDrm_signNative }, 1460 1461 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z", 1462 (void *)android_media_MediaDrm_verifyNative }, 1463 1464 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B", 1465 (void *)android_media_MediaDrm_signRSANative }, 1466 }; 1467 1468 int register_android_media_Drm(JNIEnv *env) { 1469 return AndroidRuntime::registerNativeMethods(env, 1470 "android/media/MediaDrm", gMethods, NELEM(gMethods)); 1471 } 1472