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