android_media_MediaDrm.cpp revision 2979986b576ffbf0e22057cf135626bc54b9880b
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 = String8::format("DRM vendor-defined error: %d", err);
267        drmMessage = vendorMessage.string();
268    }
269
270    if (err == BAD_VALUE) {
271        jniThrowException(env, "java/lang/IllegalArgumentException", msg);
272        return true;
273    } else if (err == ERROR_DRM_NOT_PROVISIONED) {
274        jniThrowException(env, "android/media/NotProvisionedException", msg);
275        return true;
276    } else if (err == ERROR_DRM_RESOURCE_BUSY) {
277        jniThrowException(env, "android/media/ResourceBusyException", msg);
278        return true;
279    } else if (err == ERROR_DRM_DEVICE_REVOKED) {
280        jniThrowException(env, "android/media/DeniedByServerException", msg);
281        return true;
282    } else if (err != OK) {
283        String8 errbuf;
284        if (drmMessage != NULL) {
285            if (msg == NULL) {
286                msg = drmMessage;
287            } else {
288                errbuf = String8::format("%s: %s", msg, drmMessage);
289                msg = errbuf.string();
290            }
291        }
292        throwStateException(env, msg, err);
293        return true;
294    }
295    return false;
296}
297
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 void android_media_MediaDrm_unprovisionDeviceNative(
970    JNIEnv *env, jobject thiz) {
971    sp<IDrm> drm = GetDrm(env, thiz);
972
973    if (drm == NULL) {
974        jniThrowException(env, "java/lang/IllegalStateException",
975                          "MediaDrm obj is null");
976        return;
977    }
978
979    status_t err = drm->unprovisionDevice();
980
981    throwExceptionAsNecessary(env, err, "Failed to handle provision response");
982    return;
983}
984
985static jobject android_media_MediaDrm_getSecureStops(
986    JNIEnv *env, jobject thiz) {
987    sp<IDrm> drm = GetDrm(env, thiz);
988
989    if (drm == NULL) {
990        jniThrowException(env, "java/lang/IllegalStateException",
991                          "MediaDrm obj is null");
992        return NULL;
993    }
994
995    List<Vector<uint8_t> > secureStops;
996
997    status_t err = drm->getSecureStops(secureStops);
998
999    if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1000        return NULL;
1001    }
1002
1003    return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1004}
1005
1006static void android_media_MediaDrm_releaseSecureStops(
1007    JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1008    sp<IDrm> drm = GetDrm(env, thiz);
1009
1010    if (drm == NULL) {
1011        jniThrowException(env, "java/lang/IllegalStateException",
1012                          "MediaDrm obj is null");
1013        return;
1014    }
1015
1016    Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1017
1018    status_t err = drm->releaseSecureStops(ssRelease);
1019
1020    throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1021}
1022
1023static jstring android_media_MediaDrm_getPropertyString(
1024    JNIEnv *env, jobject thiz, jstring jname) {
1025    sp<IDrm> drm = GetDrm(env, thiz);
1026
1027    if (drm == NULL) {
1028        jniThrowException(env, "java/lang/IllegalStateException",
1029                          "MediaDrm obj is null");
1030        return NULL;
1031    }
1032
1033    if (jname == NULL) {
1034        jniThrowException(env, "java/lang/IllegalArgumentException",
1035                          "property name String is null");
1036        return NULL;
1037    }
1038
1039    String8 name = JStringToString8(env, jname);
1040    String8 value;
1041
1042    status_t err = drm->getPropertyString(name, value);
1043
1044    if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1045        return NULL;
1046    }
1047
1048    return env->NewStringUTF(value.string());
1049}
1050
1051static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1052    JNIEnv *env, jobject thiz, jstring jname) {
1053    sp<IDrm> drm = GetDrm(env, thiz);
1054
1055    if (drm == NULL) {
1056        jniThrowException(env, "java/lang/IllegalStateException",
1057                          "MediaDrm obj is null");
1058        return NULL;
1059    }
1060
1061    if (jname == NULL) {
1062        jniThrowException(env, "java/lang/IllegalArgumentException",
1063                          "property name String is null");
1064        return NULL;
1065    }
1066
1067    String8 name = JStringToString8(env, jname);
1068    Vector<uint8_t> value;
1069
1070    status_t err = drm->getPropertyByteArray(name, value);
1071
1072    if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1073        return NULL;
1074    }
1075
1076    return VectorToJByteArray(env, value);
1077}
1078
1079static void android_media_MediaDrm_setPropertyString(
1080    JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1081    sp<IDrm> drm = GetDrm(env, thiz);
1082
1083    if (drm == NULL) {
1084        jniThrowException(env, "java/lang/IllegalStateException",
1085                          "MediaDrm obj is null");
1086        return;
1087    }
1088
1089    if (jname == NULL) {
1090        jniThrowException(env, "java/lang/IllegalArgumentException",
1091                          "property name String is null");
1092        return;
1093    }
1094
1095    if (jvalue == NULL) {
1096        jniThrowException(env, "java/lang/IllegalArgumentException",
1097                          "property value String is null");
1098        return;
1099    }
1100
1101    String8 name = JStringToString8(env, jname);
1102    String8 value = JStringToString8(env, jvalue);
1103
1104    status_t err = drm->setPropertyString(name, value);
1105
1106    throwExceptionAsNecessary(env, err, "Failed to set property");
1107}
1108
1109static void android_media_MediaDrm_setPropertyByteArray(
1110    JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1111    sp<IDrm> drm = GetDrm(env, thiz);
1112
1113    if (drm == NULL) {
1114        jniThrowException(env, "java/lang/IllegalStateException",
1115                          "MediaDrm obj is null");
1116        return;
1117    }
1118
1119    if (jname == NULL) {
1120        jniThrowException(env, "java/lang/IllegalArgumentException",
1121                          "property name String is null");
1122        return;
1123    }
1124
1125    if (jvalue == NULL) {
1126        jniThrowException(env, "java/lang/IllegalArgumentException",
1127                          "property value byte array is null");
1128        return;
1129    }
1130
1131    String8 name = JStringToString8(env, jname);
1132    Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1133
1134    status_t err = drm->setPropertyByteArray(name, value);
1135
1136    throwExceptionAsNecessary(env, err, "Failed to set property");
1137}
1138
1139static void android_media_MediaDrm_setCipherAlgorithmNative(
1140    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1141    jstring jalgorithm) {
1142
1143    sp<IDrm> drm = GetDrm(env, jdrm);
1144
1145    if (!CheckSession(env, drm, jsessionId)) {
1146        return;
1147    }
1148
1149    if (jalgorithm == NULL) {
1150        jniThrowException(env, "java/lang/IllegalArgumentException",
1151                          "algorithm String is null");
1152        return;
1153    }
1154
1155    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1156    String8 algorithm = JStringToString8(env, jalgorithm);
1157
1158    status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1159
1160    throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1161}
1162
1163static void android_media_MediaDrm_setMacAlgorithmNative(
1164    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1165    jstring jalgorithm) {
1166
1167    sp<IDrm> drm = GetDrm(env, jdrm);
1168
1169    if (!CheckSession(env, drm, jsessionId)) {
1170        return;
1171    }
1172
1173    if (jalgorithm == NULL) {
1174        jniThrowException(env, "java/lang/IllegalArgumentException",
1175                          "algorithm String is null");
1176        return;
1177    }
1178
1179    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1180    String8 algorithm = JStringToString8(env, jalgorithm);
1181
1182    status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1183
1184    throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1185}
1186
1187
1188static jbyteArray android_media_MediaDrm_encryptNative(
1189    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1190    jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1191
1192    sp<IDrm> drm = GetDrm(env, jdrm);
1193
1194    if (!CheckSession(env, drm, jsessionId)) {
1195        return NULL;
1196    }
1197
1198    if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1199        jniThrowException(env, "java/lang/IllegalArgumentException",
1200                          "required argument is null");
1201        return NULL;
1202    }
1203
1204    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1205    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1206    Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1207    Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1208    Vector<uint8_t> output;
1209
1210    status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1211
1212    if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1213        return NULL;
1214    }
1215
1216    return VectorToJByteArray(env, output);
1217}
1218
1219static jbyteArray android_media_MediaDrm_decryptNative(
1220    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1221    jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1222
1223    sp<IDrm> drm = GetDrm(env, jdrm);
1224
1225    if (!CheckSession(env, drm, jsessionId)) {
1226        return NULL;
1227    }
1228
1229    if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1230        jniThrowException(env, "java/lang/IllegalArgumentException",
1231                          "required argument is null");
1232        return NULL;
1233    }
1234
1235    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1236    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1237    Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1238    Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1239    Vector<uint8_t> output;
1240
1241    status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1242    if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1243        return NULL;
1244    }
1245
1246    return VectorToJByteArray(env, output);
1247}
1248
1249static jbyteArray android_media_MediaDrm_signNative(
1250    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1251    jbyteArray jkeyId, jbyteArray jmessage) {
1252
1253    sp<IDrm> drm = GetDrm(env, jdrm);
1254
1255    if (!CheckSession(env, drm, jsessionId)) {
1256        return NULL;
1257    }
1258
1259    if (jkeyId == NULL || jmessage == NULL) {
1260        jniThrowException(env, "java/lang/IllegalArgumentException",
1261                          "required argument is null");
1262        return NULL;
1263    }
1264
1265    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1266    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1267    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1268    Vector<uint8_t> signature;
1269
1270    status_t err = drm->sign(sessionId, keyId, message, signature);
1271
1272    if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1273        return NULL;
1274    }
1275
1276    return VectorToJByteArray(env, signature);
1277}
1278
1279static jboolean android_media_MediaDrm_verifyNative(
1280    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1281    jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1282
1283    sp<IDrm> drm = GetDrm(env, jdrm);
1284
1285    if (!CheckSession(env, drm, jsessionId)) {
1286        return false;
1287    }
1288
1289    if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
1290        jniThrowException(env, "java/lang/IllegalArgumentException",
1291                          "required argument is null");
1292        return false;
1293    }
1294
1295    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1296    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1297    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1298    Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1299    bool match;
1300
1301    status_t err = drm->verify(sessionId, keyId, message, signature, match);
1302
1303    throwExceptionAsNecessary(env, err, "Failed to verify");
1304    return match;
1305}
1306
1307
1308static jbyteArray android_media_MediaDrm_signRSANative(
1309    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1310    jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1311
1312    sp<IDrm> drm = GetDrm(env, jdrm);
1313
1314    if (!CheckSession(env, drm, jsessionId)) {
1315        return NULL;
1316    }
1317
1318    if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1319        jniThrowException(env, "java/lang/IllegalArgumentException",
1320                          "required argument is null");
1321        return NULL;
1322    }
1323
1324    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1325    String8 algorithm = JStringToString8(env, jalgorithm);
1326    Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1327    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1328    Vector<uint8_t> signature;
1329
1330    status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1331
1332    if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1333        return NULL;
1334    }
1335
1336    return VectorToJByteArray(env, signature);
1337}
1338
1339
1340static JNINativeMethod gMethods[] = {
1341    { "release", "()V", (void *)android_media_MediaDrm_release },
1342    { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1343
1344    { "native_setup", "(Ljava/lang/Object;[B)V",
1345      (void *)android_media_MediaDrm_native_setup },
1346
1347    { "native_finalize", "()V",
1348      (void *)android_media_MediaDrm_native_finalize },
1349
1350    { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
1351      (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1352
1353    { "openSession", "()[B",
1354      (void *)android_media_MediaDrm_openSession },
1355
1356    { "closeSession", "([B)V",
1357      (void *)android_media_MediaDrm_closeSession },
1358
1359    { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1360      "Landroid/media/MediaDrm$KeyRequest;",
1361      (void *)android_media_MediaDrm_getKeyRequest },
1362
1363    { "provideKeyResponse", "([B[B)[B",
1364      (void *)android_media_MediaDrm_provideKeyResponse },
1365
1366    { "removeKeys", "([B)V",
1367      (void *)android_media_MediaDrm_removeKeys },
1368
1369    { "restoreKeys", "([B[B)V",
1370      (void *)android_media_MediaDrm_restoreKeys },
1371
1372    { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1373      (void *)android_media_MediaDrm_queryKeyStatus },
1374
1375    { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1376      (void *)android_media_MediaDrm_getProvisionRequestNative },
1377
1378    { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1379      (void *)android_media_MediaDrm_provideProvisionResponseNative },
1380
1381    { "unprovisionDevice", "()V",
1382      (void *)android_media_MediaDrm_unprovisionDeviceNative },
1383
1384    { "getSecureStops", "()Ljava/util/List;",
1385      (void *)android_media_MediaDrm_getSecureStops },
1386
1387    { "releaseSecureStops", "([B)V",
1388      (void *)android_media_MediaDrm_releaseSecureStops },
1389
1390    { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1391      (void *)android_media_MediaDrm_getPropertyString },
1392
1393    { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1394      (void *)android_media_MediaDrm_getPropertyByteArray },
1395
1396    { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1397      (void *)android_media_MediaDrm_setPropertyString },
1398
1399    { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1400      (void *)android_media_MediaDrm_setPropertyByteArray },
1401
1402    { "setCipherAlgorithmNative",
1403      "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1404      (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1405
1406    { "setMacAlgorithmNative",
1407      "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1408      (void *)android_media_MediaDrm_setMacAlgorithmNative },
1409
1410    { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1411      (void *)android_media_MediaDrm_encryptNative },
1412
1413    { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1414      (void *)android_media_MediaDrm_decryptNative },
1415
1416    { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1417      (void *)android_media_MediaDrm_signNative },
1418
1419    { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1420      (void *)android_media_MediaDrm_verifyNative },
1421
1422    { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1423      (void *)android_media_MediaDrm_signRSANative },
1424};
1425
1426int register_android_media_Drm(JNIEnv *env) {
1427    return AndroidRuntime::registerNativeMethods(env,
1428                "android/media/MediaDrm", gMethods, NELEM(gMethods));
1429}
1430