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