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