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