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