android_media_MediaDrm.cpp revision 35d6a4f75bc3e02e5983fb800bc7538d51d01a45
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} gEventTypes; 96 97struct KeyTypes { 98 jint kKeyTypeStreaming; 99 jint kKeyTypeOffline; 100 jint kKeyTypeRelease; 101} gKeyTypes; 102 103struct CertificateTypes { 104 jint kCertificateTypeNone; 105 jint kCertificateTypeX509; 106} gCertificateTypes; 107 108struct CertificateFields { 109 jfieldID wrappedPrivateKey; 110 jfieldID certificateData; 111}; 112 113struct StateExceptionFields { 114 jmethodID init; 115 jclass classId; 116}; 117 118struct 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 136static fields_t gFields; 137 138// ---------------------------------------------------------------------------- 139// ref-counted object for callbacks 140class JNIDrmListener: public DrmListener 141{ 142public: 143 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz); 144 ~JNIDrmListener(); 145 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL); 146private: 147 JNIDrmListener(); 148 jclass mClass; // Reference to MediaDrm class 149 jobject mObject; // Weak ref to MediaDrm Java object to call on 150}; 151 152JNIDrmListener::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 170JNIDrmListener::~JNIDrmListener() 171{ 172 // remove global references 173 JNIEnv *env = AndroidRuntime::getJNIEnv(); 174 env->DeleteGlobalRef(mObject); 175 env->DeleteGlobalRef(mClass); 176} 177 178void 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 221static 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 230static 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 298static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) { 299 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context); 300 return jdrm ? jdrm->getDrm() : NULL; 301} 302 303JDrm::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 312JDrm::~JDrm() { 313 JNIEnv *env = AndroidRuntime::getJNIEnv(); 314 315 env->DeleteWeakGlobalRef(mObject); 316 mObject = NULL; 317} 318 319// static 320sp<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 343sp<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 359status_t JDrm::setListener(const sp<DrmListener>& listener) { 360 Mutex::Autolock lock(mLock); 361 mListener = listener; 362 return OK; 363} 364 365void 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 377void JDrm::disconnect() { 378 if (mDrm != NULL) { 379 mDrm->destroyPlugin(); 380 mDrm.clear(); 381 } 382} 383 384 385// static 386bool 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 396status_t JDrm::initCheck() const { 397 return mDrm == NULL ? NO_INIT : OK; 398} 399 400// JNI conversion utilities 401static 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 409static 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 418static 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 441static KeyedVector<String8, String8> HashMapToKeyedVector( 442 JNIEnv *env, jobject &hashMap, bool* pIsOK) { 443 jclass clazz = gFields.stringClassId; 444 KeyedVector<String8, String8> keyedVector; 445 *pIsOK = true; 446 447 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet); 448 if (entrySet) { 449 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator); 450 if (iterator) { 451 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext); 452 while (hasNext) { 453 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next); 454 if (entry) { 455 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey); 456 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) { 457 jniThrowException(env, "java/lang/IllegalArgumentException", 458 "HashMap key is not a String"); 459 env->DeleteLocalRef(entry); 460 *pIsOK = false; 461 break; 462 } 463 jstring jkey = static_cast<jstring>(obj); 464 465 obj = env->CallObjectMethod(entry, gFields.entry.getValue); 466 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) { 467 jniThrowException(env, "java/lang/IllegalArgumentException", 468 "HashMap value is not a String"); 469 env->DeleteLocalRef(entry); 470 *pIsOK = false; 471 break; 472 } 473 jstring jvalue = static_cast<jstring>(obj); 474 475 String8 key = JStringToString8(env, jkey); 476 String8 value = JStringToString8(env, jvalue); 477 keyedVector.add(key, value); 478 479 env->DeleteLocalRef(jkey); 480 env->DeleteLocalRef(jvalue); 481 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext); 482 } 483 env->DeleteLocalRef(entry); 484 } 485 env->DeleteLocalRef(iterator); 486 } 487 env->DeleteLocalRef(entrySet); 488 } 489 return keyedVector; 490} 491 492static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) { 493 jclass clazz = gFields.hashmapClassId; 494 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init); 495 for (size_t i = 0; i < map.size(); ++i) { 496 jstring jkey = env->NewStringUTF(map.keyAt(i).string()); 497 jstring jvalue = env->NewStringUTF(map.valueAt(i).string()); 498 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue); 499 env->DeleteLocalRef(jkey); 500 env->DeleteLocalRef(jvalue); 501 } 502 return hashMap; 503} 504 505static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env, 506 List<Vector<uint8_t> > list) { 507 jclass clazz = gFields.arraylistClassId; 508 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init); 509 List<Vector<uint8_t> >::iterator iter = list.begin(); 510 while (iter != list.end()) { 511 jbyteArray byteArray = VectorToJByteArray(env, *iter); 512 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray); 513 env->DeleteLocalRef(byteArray); 514 iter++; 515 } 516 517 return arrayList; 518} 519 520} // namespace android 521 522using namespace android; 523 524static sp<JDrm> setDrm( 525 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) { 526 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context); 527 if (drm != NULL) { 528 drm->incStrong(thiz); 529 } 530 if (old != NULL) { 531 old->decStrong(thiz); 532 } 533 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get())); 534 535 return old; 536} 537 538static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId) 539{ 540 if (drm == NULL) { 541 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); 542 return false; 543 } 544 545 if (jsessionId == NULL) { 546 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null"); 547 return false; 548 } 549 return true; 550} 551 552static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) { 553 sp<JDrm> drm = setDrm(env, thiz, NULL); 554 if (drm != NULL) { 555 drm->setListener(NULL); 556 drm->disconnect(); 557 } 558} 559 560static void android_media_MediaDrm_native_init(JNIEnv *env) { 561 jclass clazz; 562 FIND_CLASS(clazz, "android/media/MediaDrm"); 563 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J"); 564 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative", 565 "(Ljava/lang/Object;IILjava/lang/Object;)V"); 566 567 jfieldID field; 568 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I"); 569 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field); 570 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I"); 571 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field); 572 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I"); 573 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field); 574 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I"); 575 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field); 576 577 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I"); 578 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field); 579 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I"); 580 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field); 581 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I"); 582 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field); 583 584 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I"); 585 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field); 586 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I"); 587 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field); 588 589 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); 590 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); 591 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); 592 593 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest"); 594 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B"); 595 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); 596 597 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate"); 598 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B"); 599 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B"); 600 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz)); 601 602 FIND_CLASS(clazz, "java/util/ArrayList"); 603 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V"); 604 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z"); 605 606 FIND_CLASS(clazz, "java/util/HashMap"); 607 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V"); 608 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 609 GET_METHOD_ID(gFields.hashmap.put, clazz, "put", 610 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 611 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;"); 612 613 FIND_CLASS(clazz, "java/util/Set"); 614 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;"); 615 616 FIND_CLASS(clazz, "java/util/Iterator"); 617 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;"); 618 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z"); 619 620 FIND_CLASS(clazz, "java/util/Map$Entry"); 621 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;"); 622 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;"); 623 624 FIND_CLASS(clazz, "java/util/HashMap"); 625 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz)); 626 627 FIND_CLASS(clazz, "java/lang/String"); 628 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz)); 629 630 FIND_CLASS(clazz, "java/util/ArrayList"); 631 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz)); 632 633 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException"); 634 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V"); 635 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz)); 636} 637 638static void android_media_MediaDrm_native_setup( 639 JNIEnv *env, jobject thiz, 640 jobject weak_this, jbyteArray uuidObj) { 641 642 if (uuidObj == NULL) { 643 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null"); 644 return; 645 } 646 647 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj); 648 649 if (uuid.size() != 16) { 650 jniThrowException(env, "java/lang/IllegalArgumentException", 651 "invalid UUID size, expected 16 bytes"); 652 return; 653 } 654 655 sp<JDrm> drm = new JDrm(env, thiz, uuid.array()); 656 657 status_t err = drm->initCheck(); 658 659 if (err != OK) { 660 jniThrowException( 661 env, 662 "android/media/UnsupportedSchemeException", 663 "Failed to instantiate drm object."); 664 return; 665 } 666 667 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this); 668 drm->setListener(listener); 669 setDrm(env, thiz, drm); 670} 671 672static void android_media_MediaDrm_native_finalize( 673 JNIEnv *env, jobject thiz) { 674 android_media_MediaDrm_release(env, thiz); 675} 676 677static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative( 678 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) { 679 680 if (uuidObj == NULL) { 681 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 682 return false; 683 } 684 685 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj); 686 687 if (uuid.size() != 16) { 688 jniThrowException( 689 env, 690 "java/lang/IllegalArgumentException", 691 "invalid UUID size, expected 16 bytes"); 692 return false; 693 } 694 695 String8 mimeType; 696 if (jmimeType != NULL) { 697 mimeType = JStringToString8(env, jmimeType); 698 } 699 700 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType); 701} 702 703static jbyteArray android_media_MediaDrm_openSession( 704 JNIEnv *env, jobject thiz) { 705 sp<IDrm> drm = GetDrm(env, thiz); 706 707 if (drm == NULL) { 708 jniThrowException(env, "java/lang/IllegalStateException", 709 "MediaDrm obj is null"); 710 return NULL; 711 } 712 713 Vector<uint8_t> sessionId; 714 status_t err = drm->openSession(sessionId); 715 716 if (throwExceptionAsNecessary(env, err, "Failed to open session")) { 717 return NULL; 718 } 719 720 return VectorToJByteArray(env, sessionId); 721} 722 723static void android_media_MediaDrm_closeSession( 724 JNIEnv *env, jobject thiz, jbyteArray jsessionId) { 725 sp<IDrm> drm = GetDrm(env, thiz); 726 727 if (!CheckSession(env, drm, jsessionId)) { 728 return; 729 } 730 731 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 732 733 status_t err = drm->closeSession(sessionId); 734 735 throwExceptionAsNecessary(env, err, "Failed to close session"); 736} 737 738static jobject android_media_MediaDrm_getKeyRequest( 739 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData, 740 jstring jmimeType, jint jkeyType, jobject joptParams) { 741 sp<IDrm> drm = GetDrm(env, thiz); 742 743 if (!CheckSession(env, drm, jsessionId)) { 744 return NULL; 745 } 746 747 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 748 749 Vector<uint8_t> initData; 750 if (jinitData != NULL) { 751 initData = JByteArrayToVector(env, jinitData); 752 } 753 754 String8 mimeType; 755 if (jmimeType != NULL) { 756 mimeType = JStringToString8(env, jmimeType); 757 } 758 759 DrmPlugin::KeyType keyType; 760 if (jkeyType == gKeyTypes.kKeyTypeStreaming) { 761 keyType = DrmPlugin::kKeyType_Streaming; 762 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) { 763 keyType = DrmPlugin::kKeyType_Offline; 764 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) { 765 keyType = DrmPlugin::kKeyType_Release; 766 } else { 767 jniThrowException(env, "java/lang/IllegalArgumentException", 768 "invalid keyType"); 769 return NULL; 770 } 771 772 KeyedVector<String8, String8> optParams; 773 if (joptParams != NULL) { 774 bool isOK; 775 optParams = HashMapToKeyedVector(env, joptParams, &isOK); 776 if (!isOK) { 777 return NULL; 778 } 779 } 780 781 Vector<uint8_t> request; 782 String8 defaultUrl; 783 784 status_t err = drm->getKeyRequest(sessionId, initData, mimeType, 785 keyType, optParams, request, defaultUrl); 786 787 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) { 788 return NULL; 789 } 790 791 // Fill out return obj 792 jclass clazz; 793 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); 794 795 jobject keyObj = NULL; 796 797 if (clazz) { 798 keyObj = env->AllocObject(clazz); 799 jbyteArray jrequest = VectorToJByteArray(env, request); 800 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest); 801 802 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string()); 803 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl); 804 } 805 806 return keyObj; 807} 808 809static jbyteArray android_media_MediaDrm_provideKeyResponse( 810 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) { 811 sp<IDrm> drm = GetDrm(env, thiz); 812 813 if (!CheckSession(env, drm, jsessionId)) { 814 return NULL; 815 } 816 817 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 818 819 if (jresponse == NULL) { 820 jniThrowException(env, "java/lang/IllegalArgumentException", 821 "key response is null"); 822 return NULL; 823 } 824 Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); 825 Vector<uint8_t> keySetId; 826 827 status_t err = drm->provideKeyResponse(sessionId, response, keySetId); 828 829 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) { 830 return NULL; 831 } 832 return VectorToJByteArray(env, keySetId); 833} 834 835static void android_media_MediaDrm_removeKeys( 836 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) { 837 sp<IDrm> drm = GetDrm(env, thiz); 838 839 if (jkeysetId == NULL) { 840 jniThrowException(env, "java/lang/IllegalArgumentException", 841 "keySetId is null"); 842 return; 843 } 844 845 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId)); 846 847 status_t err = drm->removeKeys(keySetId); 848 849 throwExceptionAsNecessary(env, err, "Failed to remove keys"); 850} 851 852static void android_media_MediaDrm_restoreKeys( 853 JNIEnv *env, jobject thiz, jbyteArray jsessionId, 854 jbyteArray jkeysetId) { 855 856 sp<IDrm> drm = GetDrm(env, thiz); 857 858 if (!CheckSession(env, drm, jsessionId)) { 859 return; 860 } 861 862 if (jkeysetId == NULL) { 863 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 864 return; 865 } 866 867 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 868 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId)); 869 870 status_t err = drm->restoreKeys(sessionId, keySetId); 871 872 throwExceptionAsNecessary(env, err, "Failed to restore keys"); 873} 874 875static jobject android_media_MediaDrm_queryKeyStatus( 876 JNIEnv *env, jobject thiz, jbyteArray jsessionId) { 877 sp<IDrm> drm = GetDrm(env, thiz); 878 879 if (!CheckSession(env, drm, jsessionId)) { 880 return NULL; 881 } 882 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 883 884 KeyedVector<String8, String8> infoMap; 885 886 status_t err = drm->queryKeyStatus(sessionId, infoMap); 887 888 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) { 889 return NULL; 890 } 891 892 return KeyedVectorToHashMap(env, infoMap); 893} 894 895static jobject android_media_MediaDrm_getProvisionRequestNative( 896 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) { 897 sp<IDrm> drm = GetDrm(env, thiz); 898 899 if (drm == NULL) { 900 jniThrowException(env, "java/lang/IllegalStateException", 901 "MediaDrm obj is null"); 902 return NULL; 903 } 904 905 Vector<uint8_t> request; 906 String8 defaultUrl; 907 908 String8 certType; 909 if (jcertType == gCertificateTypes.kCertificateTypeX509) { 910 certType = "X.509"; 911 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) { 912 certType = "none"; 913 } else { 914 certType = "invalid"; 915 } 916 917 String8 certAuthority = JStringToString8(env, jcertAuthority); 918 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl); 919 920 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) { 921 return NULL; 922 } 923 924 // Fill out return obj 925 jclass clazz; 926 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest"); 927 928 jobject provisionObj = NULL; 929 930 if (clazz) { 931 provisionObj = env->AllocObject(clazz); 932 jbyteArray jrequest = VectorToJByteArray(env, request); 933 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest); 934 935 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string()); 936 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl); 937 } 938 939 return provisionObj; 940} 941 942static jobject android_media_MediaDrm_provideProvisionResponseNative( 943 JNIEnv *env, jobject thiz, jbyteArray jresponse) { 944 sp<IDrm> drm = GetDrm(env, thiz); 945 946 if (drm == NULL) { 947 jniThrowException(env, "java/lang/IllegalStateException", 948 "MediaDrm obj is null"); 949 return NULL; 950 } 951 952 if (jresponse == NULL) { 953 jniThrowException(env, "java/lang/IllegalArgumentException", 954 "provision response is null"); 955 return NULL; 956 } 957 958 Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); 959 Vector<uint8_t> certificate, wrappedKey; 960 961 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey); 962 963 // Fill out return obj 964 jclass clazz = gFields.certificateClassId; 965 966 jobject certificateObj = NULL; 967 968 if (clazz && certificate.size() && wrappedKey.size()) { 969 certificateObj = env->AllocObject(clazz); 970 jbyteArray jcertificate = VectorToJByteArray(env, certificate); 971 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate); 972 973 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey); 974 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey); 975 } 976 977 throwExceptionAsNecessary(env, err, "Failed to handle provision response"); 978 return certificateObj; 979} 980 981static void android_media_MediaDrm_unprovisionDeviceNative( 982 JNIEnv *env, jobject thiz) { 983 sp<IDrm> drm = GetDrm(env, thiz); 984 985 if (drm == NULL) { 986 jniThrowException(env, "java/lang/IllegalStateException", 987 "MediaDrm obj is null"); 988 return; 989 } 990 991 status_t err = drm->unprovisionDevice(); 992 993 throwExceptionAsNecessary(env, err, "Failed to handle provision response"); 994 return; 995} 996 997static jobject android_media_MediaDrm_getSecureStops( 998 JNIEnv *env, jobject thiz) { 999 sp<IDrm> drm = GetDrm(env, thiz); 1000 1001 if (drm == NULL) { 1002 jniThrowException(env, "java/lang/IllegalStateException", 1003 "MediaDrm obj is null"); 1004 return NULL; 1005 } 1006 1007 List<Vector<uint8_t> > secureStops; 1008 1009 status_t err = drm->getSecureStops(secureStops); 1010 1011 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) { 1012 return NULL; 1013 } 1014 1015 return ListOfVectorsToArrayListOfByteArray(env, secureStops); 1016} 1017 1018static void android_media_MediaDrm_releaseSecureStops( 1019 JNIEnv *env, jobject thiz, jbyteArray jssRelease) { 1020 sp<IDrm> drm = GetDrm(env, thiz); 1021 1022 if (drm == NULL) { 1023 jniThrowException(env, "java/lang/IllegalStateException", 1024 "MediaDrm obj is null"); 1025 return; 1026 } 1027 1028 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease)); 1029 1030 status_t err = drm->releaseSecureStops(ssRelease); 1031 1032 throwExceptionAsNecessary(env, err, "Failed to release secure stops"); 1033} 1034 1035static jstring android_media_MediaDrm_getPropertyString( 1036 JNIEnv *env, jobject thiz, jstring jname) { 1037 sp<IDrm> drm = GetDrm(env, thiz); 1038 1039 if (drm == NULL) { 1040 jniThrowException(env, "java/lang/IllegalStateException", 1041 "MediaDrm obj is null"); 1042 return NULL; 1043 } 1044 1045 if (jname == NULL) { 1046 jniThrowException(env, "java/lang/IllegalArgumentException", 1047 "property name String is null"); 1048 return NULL; 1049 } 1050 1051 String8 name = JStringToString8(env, jname); 1052 String8 value; 1053 1054 status_t err = drm->getPropertyString(name, value); 1055 1056 if (throwExceptionAsNecessary(env, err, "Failed to get property")) { 1057 return NULL; 1058 } 1059 1060 return env->NewStringUTF(value.string()); 1061} 1062 1063static jbyteArray android_media_MediaDrm_getPropertyByteArray( 1064 JNIEnv *env, jobject thiz, jstring jname) { 1065 sp<IDrm> drm = GetDrm(env, thiz); 1066 1067 if (drm == NULL) { 1068 jniThrowException(env, "java/lang/IllegalStateException", 1069 "MediaDrm obj is null"); 1070 return NULL; 1071 } 1072 1073 if (jname == NULL) { 1074 jniThrowException(env, "java/lang/IllegalArgumentException", 1075 "property name String is null"); 1076 return NULL; 1077 } 1078 1079 String8 name = JStringToString8(env, jname); 1080 Vector<uint8_t> value; 1081 1082 status_t err = drm->getPropertyByteArray(name, value); 1083 1084 if (throwExceptionAsNecessary(env, err, "Failed to get property")) { 1085 return NULL; 1086 } 1087 1088 return VectorToJByteArray(env, value); 1089} 1090 1091static void android_media_MediaDrm_setPropertyString( 1092 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) { 1093 sp<IDrm> drm = GetDrm(env, thiz); 1094 1095 if (drm == NULL) { 1096 jniThrowException(env, "java/lang/IllegalStateException", 1097 "MediaDrm obj is null"); 1098 return; 1099 } 1100 1101 if (jname == NULL) { 1102 jniThrowException(env, "java/lang/IllegalArgumentException", 1103 "property name String is null"); 1104 return; 1105 } 1106 1107 if (jvalue == NULL) { 1108 jniThrowException(env, "java/lang/IllegalArgumentException", 1109 "property value String is null"); 1110 return; 1111 } 1112 1113 String8 name = JStringToString8(env, jname); 1114 String8 value = JStringToString8(env, jvalue); 1115 1116 status_t err = drm->setPropertyString(name, value); 1117 1118 throwExceptionAsNecessary(env, err, "Failed to set property"); 1119} 1120 1121static void android_media_MediaDrm_setPropertyByteArray( 1122 JNIEnv *env, jobject thiz, jstring jname, jbyteArray 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 byte array is null"); 1140 return; 1141 } 1142 1143 String8 name = JStringToString8(env, jname); 1144 Vector<uint8_t> value = JByteArrayToVector(env, jvalue); 1145 1146 status_t err = drm->setPropertyByteArray(name, value); 1147 1148 throwExceptionAsNecessary(env, err, "Failed to set property"); 1149} 1150 1151static void android_media_MediaDrm_setCipherAlgorithmNative( 1152 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1153 jstring jalgorithm) { 1154 1155 sp<IDrm> drm = GetDrm(env, jdrm); 1156 1157 if (!CheckSession(env, drm, jsessionId)) { 1158 return; 1159 } 1160 1161 if (jalgorithm == NULL) { 1162 jniThrowException(env, "java/lang/IllegalArgumentException", 1163 "algorithm String is null"); 1164 return; 1165 } 1166 1167 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1168 String8 algorithm = JStringToString8(env, jalgorithm); 1169 1170 status_t err = drm->setCipherAlgorithm(sessionId, algorithm); 1171 1172 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm"); 1173} 1174 1175static void android_media_MediaDrm_setMacAlgorithmNative( 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->setMacAlgorithm(sessionId, algorithm); 1195 1196 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm"); 1197} 1198 1199 1200static jbyteArray android_media_MediaDrm_encryptNative( 1201 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1202 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) { 1203 1204 sp<IDrm> drm = GetDrm(env, jdrm); 1205 1206 if (!CheckSession(env, drm, jsessionId)) { 1207 return NULL; 1208 } 1209 1210 if (jkeyId == NULL || jinput == NULL || jiv == NULL) { 1211 jniThrowException(env, "java/lang/IllegalArgumentException", 1212 "required argument is null"); 1213 return NULL; 1214 } 1215 1216 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1217 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1218 Vector<uint8_t> input(JByteArrayToVector(env, jinput)); 1219 Vector<uint8_t> iv(JByteArrayToVector(env, jiv)); 1220 Vector<uint8_t> output; 1221 1222 status_t err = drm->encrypt(sessionId, keyId, input, iv, output); 1223 1224 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) { 1225 return NULL; 1226 } 1227 1228 return VectorToJByteArray(env, output); 1229} 1230 1231static jbyteArray android_media_MediaDrm_decryptNative( 1232 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1233 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) { 1234 1235 sp<IDrm> drm = GetDrm(env, jdrm); 1236 1237 if (!CheckSession(env, drm, jsessionId)) { 1238 return NULL; 1239 } 1240 1241 if (jkeyId == NULL || jinput == NULL || jiv == NULL) { 1242 jniThrowException(env, "java/lang/IllegalArgumentException", 1243 "required argument is null"); 1244 return NULL; 1245 } 1246 1247 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1248 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId)); 1249 Vector<uint8_t> input(JByteArrayToVector(env, jinput)); 1250 Vector<uint8_t> iv(JByteArrayToVector(env, jiv)); 1251 Vector<uint8_t> output; 1252 1253 status_t err = drm->decrypt(sessionId, keyId, input, iv, output); 1254 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) { 1255 return NULL; 1256 } 1257 1258 return VectorToJByteArray(env, output); 1259} 1260 1261static jbyteArray android_media_MediaDrm_signNative( 1262 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1263 jbyteArray jkeyId, jbyteArray jmessage) { 1264 1265 sp<IDrm> drm = GetDrm(env, jdrm); 1266 1267 if (!CheckSession(env, drm, jsessionId)) { 1268 return NULL; 1269 } 1270 1271 if (jkeyId == NULL || jmessage == 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> message(JByteArrayToVector(env, jmessage)); 1280 Vector<uint8_t> signature; 1281 1282 status_t err = drm->sign(sessionId, keyId, message, signature); 1283 1284 if (throwExceptionAsNecessary(env, err, "Failed to sign")) { 1285 return NULL; 1286 } 1287 1288 return VectorToJByteArray(env, signature); 1289} 1290 1291static jboolean android_media_MediaDrm_verifyNative( 1292 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1293 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) { 1294 1295 sp<IDrm> drm = GetDrm(env, jdrm); 1296 1297 if (!CheckSession(env, drm, jsessionId)) { 1298 return false; 1299 } 1300 1301 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) { 1302 jniThrowException(env, "java/lang/IllegalArgumentException", 1303 "required argument is null"); 1304 return false; 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(JByteArrayToVector(env, jsignature)); 1311 bool match; 1312 1313 status_t err = drm->verify(sessionId, keyId, message, signature, match); 1314 1315 throwExceptionAsNecessary(env, err, "Failed to verify"); 1316 return match; 1317} 1318 1319 1320static jbyteArray android_media_MediaDrm_signRSANative( 1321 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId, 1322 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) { 1323 1324 sp<IDrm> drm = GetDrm(env, jdrm); 1325 1326 if (!CheckSession(env, drm, jsessionId)) { 1327 return NULL; 1328 } 1329 1330 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) { 1331 jniThrowException(env, "java/lang/IllegalArgumentException", 1332 "required argument is null"); 1333 return NULL; 1334 } 1335 1336 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 1337 String8 algorithm = JStringToString8(env, jalgorithm); 1338 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey)); 1339 Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); 1340 Vector<uint8_t> signature; 1341 1342 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature); 1343 1344 if (throwExceptionAsNecessary(env, err, "Failed to sign")) { 1345 return NULL; 1346 } 1347 1348 return VectorToJByteArray(env, signature); 1349} 1350 1351 1352static JNINativeMethod gMethods[] = { 1353 { "release", "()V", (void *)android_media_MediaDrm_release }, 1354 { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, 1355 1356 { "native_setup", "(Ljava/lang/Object;[B)V", 1357 (void *)android_media_MediaDrm_native_setup }, 1358 1359 { "native_finalize", "()V", 1360 (void *)android_media_MediaDrm_native_finalize }, 1361 1362 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z", 1363 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative }, 1364 1365 { "openSession", "()[B", 1366 (void *)android_media_MediaDrm_openSession }, 1367 1368 { "closeSession", "([B)V", 1369 (void *)android_media_MediaDrm_closeSession }, 1370 1371 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)" 1372 "Landroid/media/MediaDrm$KeyRequest;", 1373 (void *)android_media_MediaDrm_getKeyRequest }, 1374 1375 { "provideKeyResponse", "([B[B)[B", 1376 (void *)android_media_MediaDrm_provideKeyResponse }, 1377 1378 { "removeKeys", "([B)V", 1379 (void *)android_media_MediaDrm_removeKeys }, 1380 1381 { "restoreKeys", "([B[B)V", 1382 (void *)android_media_MediaDrm_restoreKeys }, 1383 1384 { "queryKeyStatus", "([B)Ljava/util/HashMap;", 1385 (void *)android_media_MediaDrm_queryKeyStatus }, 1386 1387 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;", 1388 (void *)android_media_MediaDrm_getProvisionRequestNative }, 1389 1390 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;", 1391 (void *)android_media_MediaDrm_provideProvisionResponseNative }, 1392 1393 { "unprovisionDevice", "()V", 1394 (void *)android_media_MediaDrm_unprovisionDeviceNative }, 1395 1396 { "getSecureStops", "()Ljava/util/List;", 1397 (void *)android_media_MediaDrm_getSecureStops }, 1398 1399 { "releaseSecureStops", "([B)V", 1400 (void *)android_media_MediaDrm_releaseSecureStops }, 1401 1402 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", 1403 (void *)android_media_MediaDrm_getPropertyString }, 1404 1405 { "getPropertyByteArray", "(Ljava/lang/String;)[B", 1406 (void *)android_media_MediaDrm_getPropertyByteArray }, 1407 1408 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V", 1409 (void *)android_media_MediaDrm_setPropertyString }, 1410 1411 { "setPropertyByteArray", "(Ljava/lang/String;[B)V", 1412 (void *)android_media_MediaDrm_setPropertyByteArray }, 1413 1414 { "setCipherAlgorithmNative", 1415 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V", 1416 (void *)android_media_MediaDrm_setCipherAlgorithmNative }, 1417 1418 { "setMacAlgorithmNative", 1419 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V", 1420 (void *)android_media_MediaDrm_setMacAlgorithmNative }, 1421 1422 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B", 1423 (void *)android_media_MediaDrm_encryptNative }, 1424 1425 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B", 1426 (void *)android_media_MediaDrm_decryptNative }, 1427 1428 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B", 1429 (void *)android_media_MediaDrm_signNative }, 1430 1431 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z", 1432 (void *)android_media_MediaDrm_verifyNative }, 1433 1434 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B", 1435 (void *)android_media_MediaDrm_signRSANative }, 1436}; 1437 1438int register_android_media_Drm(JNIEnv *env) { 1439 return AndroidRuntime::registerNativeMethods(env, 1440 "android/media/MediaDrm", gMethods, NELEM(gMethods)); 1441} 1442