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