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