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