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