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