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