android_media_MediaDrm.cpp revision 35d6a4f75bc3e02e5983fb800bc7538d51d01a45
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(
442    JNIEnv *env, jobject &hashMap, bool* pIsOK) {
443    jclass clazz = gFields.stringClassId;
444    KeyedVector<String8, String8> keyedVector;
445    *pIsOK = true;
446
447    jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
448    if (entrySet) {
449        jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
450        if (iterator) {
451            jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
452            while (hasNext) {
453                jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
454                if (entry) {
455                    jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
456                    if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
457                        jniThrowException(env, "java/lang/IllegalArgumentException",
458                                          "HashMap key is not a String");
459                        env->DeleteLocalRef(entry);
460                        *pIsOK = false;
461                        break;
462                    }
463                    jstring jkey = static_cast<jstring>(obj);
464
465                    obj = env->CallObjectMethod(entry, gFields.entry.getValue);
466                    if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
467                        jniThrowException(env, "java/lang/IllegalArgumentException",
468                                          "HashMap value is not a String");
469                        env->DeleteLocalRef(entry);
470                        *pIsOK = false;
471                        break;
472                    }
473                    jstring jvalue = static_cast<jstring>(obj);
474
475                    String8 key = JStringToString8(env, jkey);
476                    String8 value = JStringToString8(env, jvalue);
477                    keyedVector.add(key, value);
478
479                    env->DeleteLocalRef(jkey);
480                    env->DeleteLocalRef(jvalue);
481                    hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
482                }
483                env->DeleteLocalRef(entry);
484            }
485            env->DeleteLocalRef(iterator);
486        }
487        env->DeleteLocalRef(entrySet);
488    }
489    return keyedVector;
490}
491
492static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
493    jclass clazz = gFields.hashmapClassId;
494    jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
495    for (size_t i = 0; i < map.size(); ++i) {
496        jstring jkey = env->NewStringUTF(map.keyAt(i).string());
497        jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
498        env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
499        env->DeleteLocalRef(jkey);
500        env->DeleteLocalRef(jvalue);
501    }
502    return hashMap;
503}
504
505static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
506                                                   List<Vector<uint8_t> > list) {
507    jclass clazz = gFields.arraylistClassId;
508    jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
509    List<Vector<uint8_t> >::iterator iter = list.begin();
510    while (iter != list.end()) {
511        jbyteArray byteArray = VectorToJByteArray(env, *iter);
512        env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
513        env->DeleteLocalRef(byteArray);
514        iter++;
515    }
516
517    return arrayList;
518}
519
520}  // namespace android
521
522using namespace android;
523
524static sp<JDrm> setDrm(
525        JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
526    sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
527    if (drm != NULL) {
528        drm->incStrong(thiz);
529    }
530    if (old != NULL) {
531        old->decStrong(thiz);
532    }
533    env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
534
535    return old;
536}
537
538static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
539{
540    if (drm == NULL) {
541        jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
542        return false;
543    }
544
545    if (jsessionId == NULL) {
546        jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
547        return false;
548    }
549    return true;
550}
551
552static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
553    sp<JDrm> drm = setDrm(env, thiz, NULL);
554    if (drm != NULL) {
555        drm->setListener(NULL);
556        drm->disconnect();
557    }
558}
559
560static void android_media_MediaDrm_native_init(JNIEnv *env) {
561    jclass clazz;
562    FIND_CLASS(clazz, "android/media/MediaDrm");
563    GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
564    GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
565                         "(Ljava/lang/Object;IILjava/lang/Object;)V");
566
567    jfieldID field;
568    GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
569    gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
570    GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
571    gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
572    GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
573    gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
574    GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
575    gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
576
577    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
578    gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
579    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
580    gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
581    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
582    gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
583
584    GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
585    gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
586    GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
587    gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
588
589    FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
590    GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
591    GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
592
593    FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
594    GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
595    GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
596
597    FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
598    GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
599    GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
600    gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
601
602    FIND_CLASS(clazz, "java/util/ArrayList");
603    GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
604    GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
605
606    FIND_CLASS(clazz, "java/util/HashMap");
607    GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
608    GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
609    GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
610                  "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
611    GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
612
613    FIND_CLASS(clazz, "java/util/Set");
614    GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
615
616    FIND_CLASS(clazz, "java/util/Iterator");
617    GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
618    GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
619
620    FIND_CLASS(clazz, "java/util/Map$Entry");
621    GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
622    GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
623
624    FIND_CLASS(clazz, "java/util/HashMap");
625    gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
626
627    FIND_CLASS(clazz, "java/lang/String");
628    gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
629
630    FIND_CLASS(clazz, "java/util/ArrayList");
631    gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
632
633    FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
634    GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
635    gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
636}
637
638static void android_media_MediaDrm_native_setup(
639        JNIEnv *env, jobject thiz,
640        jobject weak_this, jbyteArray uuidObj) {
641
642    if (uuidObj == NULL) {
643        jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
644        return;
645    }
646
647    Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
648
649    if (uuid.size() != 16) {
650        jniThrowException(env, "java/lang/IllegalArgumentException",
651                          "invalid UUID size, expected 16 bytes");
652        return;
653    }
654
655    sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
656
657    status_t err = drm->initCheck();
658
659    if (err != OK) {
660        jniThrowException(
661                env,
662                "android/media/UnsupportedSchemeException",
663                "Failed to instantiate drm object.");
664        return;
665    }
666
667    sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
668    drm->setListener(listener);
669    setDrm(env, thiz, drm);
670}
671
672static void android_media_MediaDrm_native_finalize(
673        JNIEnv *env, jobject thiz) {
674    android_media_MediaDrm_release(env, thiz);
675}
676
677static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
678    JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
679
680    if (uuidObj == NULL) {
681        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
682        return false;
683    }
684
685    Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
686
687    if (uuid.size() != 16) {
688        jniThrowException(
689                env,
690                "java/lang/IllegalArgumentException",
691                "invalid UUID size, expected 16 bytes");
692        return false;
693    }
694
695    String8 mimeType;
696    if (jmimeType != NULL) {
697        mimeType = JStringToString8(env, jmimeType);
698    }
699
700    return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
701}
702
703static jbyteArray android_media_MediaDrm_openSession(
704    JNIEnv *env, jobject thiz) {
705    sp<IDrm> drm = GetDrm(env, thiz);
706
707    if (drm == NULL) {
708        jniThrowException(env, "java/lang/IllegalStateException",
709                          "MediaDrm obj is null");
710        return NULL;
711    }
712
713    Vector<uint8_t> sessionId;
714    status_t err = drm->openSession(sessionId);
715
716    if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
717        return NULL;
718    }
719
720    return VectorToJByteArray(env, sessionId);
721}
722
723static void android_media_MediaDrm_closeSession(
724    JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
725    sp<IDrm> drm = GetDrm(env, thiz);
726
727    if (!CheckSession(env, drm, jsessionId)) {
728        return;
729    }
730
731    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
732
733    status_t err = drm->closeSession(sessionId);
734
735    throwExceptionAsNecessary(env, err, "Failed to close session");
736}
737
738static jobject android_media_MediaDrm_getKeyRequest(
739    JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
740    jstring jmimeType, jint jkeyType, jobject joptParams) {
741    sp<IDrm> drm = GetDrm(env, thiz);
742
743    if (!CheckSession(env, drm, jsessionId)) {
744        return NULL;
745    }
746
747    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
748
749    Vector<uint8_t> initData;
750    if (jinitData != NULL) {
751        initData = JByteArrayToVector(env, jinitData);
752    }
753
754    String8 mimeType;
755    if (jmimeType != NULL) {
756        mimeType = JStringToString8(env, jmimeType);
757    }
758
759    DrmPlugin::KeyType keyType;
760    if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
761        keyType = DrmPlugin::kKeyType_Streaming;
762    } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
763        keyType = DrmPlugin::kKeyType_Offline;
764    } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
765        keyType = DrmPlugin::kKeyType_Release;
766    } else {
767        jniThrowException(env, "java/lang/IllegalArgumentException",
768                          "invalid keyType");
769        return NULL;
770    }
771
772    KeyedVector<String8, String8> optParams;
773    if (joptParams != NULL) {
774        bool isOK;
775        optParams = HashMapToKeyedVector(env, joptParams, &isOK);
776        if (!isOK) {
777            return NULL;
778        }
779    }
780
781    Vector<uint8_t> request;
782    String8 defaultUrl;
783
784    status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
785                                          keyType, optParams, request, defaultUrl);
786
787    if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
788        return NULL;
789    }
790
791    // Fill out return obj
792    jclass clazz;
793    FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
794
795    jobject keyObj = NULL;
796
797    if (clazz) {
798        keyObj = env->AllocObject(clazz);
799        jbyteArray jrequest = VectorToJByteArray(env, request);
800        env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
801
802        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
803        env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
804    }
805
806    return keyObj;
807}
808
809static jbyteArray android_media_MediaDrm_provideKeyResponse(
810    JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
811    sp<IDrm> drm = GetDrm(env, thiz);
812
813    if (!CheckSession(env, drm, jsessionId)) {
814        return NULL;
815    }
816
817    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
818
819    if (jresponse == NULL) {
820        jniThrowException(env, "java/lang/IllegalArgumentException",
821                          "key response is null");
822        return NULL;
823    }
824    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
825    Vector<uint8_t> keySetId;
826
827    status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
828
829    if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
830        return NULL;
831    }
832    return VectorToJByteArray(env, keySetId);
833}
834
835static void android_media_MediaDrm_removeKeys(
836    JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
837    sp<IDrm> drm = GetDrm(env, thiz);
838
839    if (jkeysetId == NULL) {
840        jniThrowException(env, "java/lang/IllegalArgumentException",
841                          "keySetId is null");
842        return;
843    }
844
845    Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
846
847    status_t err = drm->removeKeys(keySetId);
848
849    throwExceptionAsNecessary(env, err, "Failed to remove keys");
850}
851
852static void android_media_MediaDrm_restoreKeys(
853    JNIEnv *env, jobject thiz, jbyteArray jsessionId,
854    jbyteArray jkeysetId) {
855
856    sp<IDrm> drm = GetDrm(env, thiz);
857
858    if (!CheckSession(env, drm, jsessionId)) {
859        return;
860    }
861
862    if (jkeysetId == NULL) {
863        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
864        return;
865    }
866
867    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
868    Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
869
870    status_t err = drm->restoreKeys(sessionId, keySetId);
871
872    throwExceptionAsNecessary(env, err, "Failed to restore keys");
873}
874
875static jobject android_media_MediaDrm_queryKeyStatus(
876    JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
877    sp<IDrm> drm = GetDrm(env, thiz);
878
879    if (!CheckSession(env, drm, jsessionId)) {
880        return NULL;
881    }
882    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
883
884    KeyedVector<String8, String8> infoMap;
885
886    status_t err = drm->queryKeyStatus(sessionId, infoMap);
887
888    if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
889        return NULL;
890    }
891
892    return KeyedVectorToHashMap(env, infoMap);
893}
894
895static jobject android_media_MediaDrm_getProvisionRequestNative(
896    JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
897    sp<IDrm> drm = GetDrm(env, thiz);
898
899    if (drm == NULL) {
900        jniThrowException(env, "java/lang/IllegalStateException",
901                          "MediaDrm obj is null");
902        return NULL;
903    }
904
905    Vector<uint8_t> request;
906    String8 defaultUrl;
907
908    String8 certType;
909    if (jcertType == gCertificateTypes.kCertificateTypeX509) {
910        certType = "X.509";
911    } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
912        certType = "none";
913    } else {
914        certType = "invalid";
915    }
916
917    String8 certAuthority = JStringToString8(env, jcertAuthority);
918    status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
919
920    if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
921        return NULL;
922    }
923
924    // Fill out return obj
925    jclass clazz;
926    FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
927
928    jobject provisionObj = NULL;
929
930    if (clazz) {
931        provisionObj = env->AllocObject(clazz);
932        jbyteArray jrequest = VectorToJByteArray(env, request);
933        env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
934
935        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
936        env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
937    }
938
939    return provisionObj;
940}
941
942static jobject android_media_MediaDrm_provideProvisionResponseNative(
943    JNIEnv *env, jobject thiz, jbyteArray jresponse) {
944    sp<IDrm> drm = GetDrm(env, thiz);
945
946    if (drm == NULL) {
947        jniThrowException(env, "java/lang/IllegalStateException",
948                          "MediaDrm obj is null");
949        return NULL;
950    }
951
952    if (jresponse == NULL) {
953        jniThrowException(env, "java/lang/IllegalArgumentException",
954                          "provision response is null");
955        return NULL;
956    }
957
958    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
959    Vector<uint8_t> certificate, wrappedKey;
960
961    status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
962
963    // Fill out return obj
964    jclass clazz = gFields.certificateClassId;
965
966    jobject certificateObj = NULL;
967
968    if (clazz && certificate.size() && wrappedKey.size()) {
969        certificateObj = env->AllocObject(clazz);
970        jbyteArray jcertificate = VectorToJByteArray(env, certificate);
971        env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
972
973        jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
974        env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
975    }
976
977    throwExceptionAsNecessary(env, err, "Failed to handle provision response");
978    return certificateObj;
979}
980
981static void android_media_MediaDrm_unprovisionDeviceNative(
982    JNIEnv *env, jobject thiz) {
983    sp<IDrm> drm = GetDrm(env, thiz);
984
985    if (drm == NULL) {
986        jniThrowException(env, "java/lang/IllegalStateException",
987                          "MediaDrm obj is null");
988        return;
989    }
990
991    status_t err = drm->unprovisionDevice();
992
993    throwExceptionAsNecessary(env, err, "Failed to handle provision response");
994    return;
995}
996
997static jobject android_media_MediaDrm_getSecureStops(
998    JNIEnv *env, jobject thiz) {
999    sp<IDrm> drm = GetDrm(env, thiz);
1000
1001    if (drm == NULL) {
1002        jniThrowException(env, "java/lang/IllegalStateException",
1003                          "MediaDrm obj is null");
1004        return NULL;
1005    }
1006
1007    List<Vector<uint8_t> > secureStops;
1008
1009    status_t err = drm->getSecureStops(secureStops);
1010
1011    if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1012        return NULL;
1013    }
1014
1015    return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1016}
1017
1018static void android_media_MediaDrm_releaseSecureStops(
1019    JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1020    sp<IDrm> drm = GetDrm(env, thiz);
1021
1022    if (drm == NULL) {
1023        jniThrowException(env, "java/lang/IllegalStateException",
1024                          "MediaDrm obj is null");
1025        return;
1026    }
1027
1028    Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1029
1030    status_t err = drm->releaseSecureStops(ssRelease);
1031
1032    throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1033}
1034
1035static jstring android_media_MediaDrm_getPropertyString(
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    String8 value;
1053
1054    status_t err = drm->getPropertyString(name, value);
1055
1056    if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1057        return NULL;
1058    }
1059
1060    return env->NewStringUTF(value.string());
1061}
1062
1063static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1064    JNIEnv *env, jobject thiz, jstring jname) {
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 NULL;
1071    }
1072
1073    if (jname == NULL) {
1074        jniThrowException(env, "java/lang/IllegalArgumentException",
1075                          "property name String is null");
1076        return NULL;
1077    }
1078
1079    String8 name = JStringToString8(env, jname);
1080    Vector<uint8_t> value;
1081
1082    status_t err = drm->getPropertyByteArray(name, value);
1083
1084    if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1085        return NULL;
1086    }
1087
1088    return VectorToJByteArray(env, value);
1089}
1090
1091static void android_media_MediaDrm_setPropertyString(
1092    JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1093    sp<IDrm> drm = GetDrm(env, thiz);
1094
1095    if (drm == NULL) {
1096        jniThrowException(env, "java/lang/IllegalStateException",
1097                          "MediaDrm obj is null");
1098        return;
1099    }
1100
1101    if (jname == NULL) {
1102        jniThrowException(env, "java/lang/IllegalArgumentException",
1103                          "property name String is null");
1104        return;
1105    }
1106
1107    if (jvalue == NULL) {
1108        jniThrowException(env, "java/lang/IllegalArgumentException",
1109                          "property value String is null");
1110        return;
1111    }
1112
1113    String8 name = JStringToString8(env, jname);
1114    String8 value = JStringToString8(env, jvalue);
1115
1116    status_t err = drm->setPropertyString(name, value);
1117
1118    throwExceptionAsNecessary(env, err, "Failed to set property");
1119}
1120
1121static void android_media_MediaDrm_setPropertyByteArray(
1122    JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1123    sp<IDrm> drm = GetDrm(env, thiz);
1124
1125    if (drm == NULL) {
1126        jniThrowException(env, "java/lang/IllegalStateException",
1127                          "MediaDrm obj is null");
1128        return;
1129    }
1130
1131    if (jname == NULL) {
1132        jniThrowException(env, "java/lang/IllegalArgumentException",
1133                          "property name String is null");
1134        return;
1135    }
1136
1137    if (jvalue == NULL) {
1138        jniThrowException(env, "java/lang/IllegalArgumentException",
1139                          "property value byte array is null");
1140        return;
1141    }
1142
1143    String8 name = JStringToString8(env, jname);
1144    Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1145
1146    status_t err = drm->setPropertyByteArray(name, value);
1147
1148    throwExceptionAsNecessary(env, err, "Failed to set property");
1149}
1150
1151static void android_media_MediaDrm_setCipherAlgorithmNative(
1152    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1153    jstring jalgorithm) {
1154
1155    sp<IDrm> drm = GetDrm(env, jdrm);
1156
1157    if (!CheckSession(env, drm, jsessionId)) {
1158        return;
1159    }
1160
1161    if (jalgorithm == NULL) {
1162        jniThrowException(env, "java/lang/IllegalArgumentException",
1163                          "algorithm String is null");
1164        return;
1165    }
1166
1167    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1168    String8 algorithm = JStringToString8(env, jalgorithm);
1169
1170    status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1171
1172    throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1173}
1174
1175static void android_media_MediaDrm_setMacAlgorithmNative(
1176    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1177    jstring jalgorithm) {
1178
1179    sp<IDrm> drm = GetDrm(env, jdrm);
1180
1181    if (!CheckSession(env, drm, jsessionId)) {
1182        return;
1183    }
1184
1185    if (jalgorithm == NULL) {
1186        jniThrowException(env, "java/lang/IllegalArgumentException",
1187                          "algorithm String is null");
1188        return;
1189    }
1190
1191    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1192    String8 algorithm = JStringToString8(env, jalgorithm);
1193
1194    status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1195
1196    throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1197}
1198
1199
1200static jbyteArray android_media_MediaDrm_encryptNative(
1201    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1202    jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1203
1204    sp<IDrm> drm = GetDrm(env, jdrm);
1205
1206    if (!CheckSession(env, drm, jsessionId)) {
1207        return NULL;
1208    }
1209
1210    if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1211        jniThrowException(env, "java/lang/IllegalArgumentException",
1212                          "required argument is null");
1213        return NULL;
1214    }
1215
1216    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1217    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1218    Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1219    Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1220    Vector<uint8_t> output;
1221
1222    status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1223
1224    if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1225        return NULL;
1226    }
1227
1228    return VectorToJByteArray(env, output);
1229}
1230
1231static jbyteArray android_media_MediaDrm_decryptNative(
1232    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1233    jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1234
1235    sp<IDrm> drm = GetDrm(env, jdrm);
1236
1237    if (!CheckSession(env, drm, jsessionId)) {
1238        return NULL;
1239    }
1240
1241    if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1242        jniThrowException(env, "java/lang/IllegalArgumentException",
1243                          "required argument is null");
1244        return NULL;
1245    }
1246
1247    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1248    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1249    Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1250    Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1251    Vector<uint8_t> output;
1252
1253    status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1254    if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1255        return NULL;
1256    }
1257
1258    return VectorToJByteArray(env, output);
1259}
1260
1261static jbyteArray android_media_MediaDrm_signNative(
1262    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1263    jbyteArray jkeyId, jbyteArray jmessage) {
1264
1265    sp<IDrm> drm = GetDrm(env, jdrm);
1266
1267    if (!CheckSession(env, drm, jsessionId)) {
1268        return NULL;
1269    }
1270
1271    if (jkeyId == NULL || jmessage == NULL) {
1272        jniThrowException(env, "java/lang/IllegalArgumentException",
1273                          "required argument is null");
1274        return NULL;
1275    }
1276
1277    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1278    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1279    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1280    Vector<uint8_t> signature;
1281
1282    status_t err = drm->sign(sessionId, keyId, message, signature);
1283
1284    if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1285        return NULL;
1286    }
1287
1288    return VectorToJByteArray(env, signature);
1289}
1290
1291static jboolean android_media_MediaDrm_verifyNative(
1292    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1293    jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1294
1295    sp<IDrm> drm = GetDrm(env, jdrm);
1296
1297    if (!CheckSession(env, drm, jsessionId)) {
1298        return false;
1299    }
1300
1301    if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
1302        jniThrowException(env, "java/lang/IllegalArgumentException",
1303                          "required argument is null");
1304        return false;
1305    }
1306
1307    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1308    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1309    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1310    Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1311    bool match;
1312
1313    status_t err = drm->verify(sessionId, keyId, message, signature, match);
1314
1315    throwExceptionAsNecessary(env, err, "Failed to verify");
1316    return match;
1317}
1318
1319
1320static jbyteArray android_media_MediaDrm_signRSANative(
1321    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1322    jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1323
1324    sp<IDrm> drm = GetDrm(env, jdrm);
1325
1326    if (!CheckSession(env, drm, jsessionId)) {
1327        return NULL;
1328    }
1329
1330    if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1331        jniThrowException(env, "java/lang/IllegalArgumentException",
1332                          "required argument is null");
1333        return NULL;
1334    }
1335
1336    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1337    String8 algorithm = JStringToString8(env, jalgorithm);
1338    Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1339    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1340    Vector<uint8_t> signature;
1341
1342    status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1343
1344    if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1345        return NULL;
1346    }
1347
1348    return VectorToJByteArray(env, signature);
1349}
1350
1351
1352static JNINativeMethod gMethods[] = {
1353    { "release", "()V", (void *)android_media_MediaDrm_release },
1354    { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1355
1356    { "native_setup", "(Ljava/lang/Object;[B)V",
1357      (void *)android_media_MediaDrm_native_setup },
1358
1359    { "native_finalize", "()V",
1360      (void *)android_media_MediaDrm_native_finalize },
1361
1362    { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
1363      (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1364
1365    { "openSession", "()[B",
1366      (void *)android_media_MediaDrm_openSession },
1367
1368    { "closeSession", "([B)V",
1369      (void *)android_media_MediaDrm_closeSession },
1370
1371    { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1372      "Landroid/media/MediaDrm$KeyRequest;",
1373      (void *)android_media_MediaDrm_getKeyRequest },
1374
1375    { "provideKeyResponse", "([B[B)[B",
1376      (void *)android_media_MediaDrm_provideKeyResponse },
1377
1378    { "removeKeys", "([B)V",
1379      (void *)android_media_MediaDrm_removeKeys },
1380
1381    { "restoreKeys", "([B[B)V",
1382      (void *)android_media_MediaDrm_restoreKeys },
1383
1384    { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1385      (void *)android_media_MediaDrm_queryKeyStatus },
1386
1387    { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1388      (void *)android_media_MediaDrm_getProvisionRequestNative },
1389
1390    { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1391      (void *)android_media_MediaDrm_provideProvisionResponseNative },
1392
1393    { "unprovisionDevice", "()V",
1394      (void *)android_media_MediaDrm_unprovisionDeviceNative },
1395
1396    { "getSecureStops", "()Ljava/util/List;",
1397      (void *)android_media_MediaDrm_getSecureStops },
1398
1399    { "releaseSecureStops", "([B)V",
1400      (void *)android_media_MediaDrm_releaseSecureStops },
1401
1402    { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1403      (void *)android_media_MediaDrm_getPropertyString },
1404
1405    { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1406      (void *)android_media_MediaDrm_getPropertyByteArray },
1407
1408    { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1409      (void *)android_media_MediaDrm_setPropertyString },
1410
1411    { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1412      (void *)android_media_MediaDrm_setPropertyByteArray },
1413
1414    { "setCipherAlgorithmNative",
1415      "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1416      (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1417
1418    { "setMacAlgorithmNative",
1419      "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1420      (void *)android_media_MediaDrm_setMacAlgorithmNative },
1421
1422    { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1423      (void *)android_media_MediaDrm_encryptNative },
1424
1425    { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1426      (void *)android_media_MediaDrm_decryptNative },
1427
1428    { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1429      (void *)android_media_MediaDrm_signNative },
1430
1431    { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1432      (void *)android_media_MediaDrm_verifyNative },
1433
1434    { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1435      (void *)android_media_MediaDrm_signRSANative },
1436};
1437
1438int register_android_media_Drm(JNIEnv *env) {
1439    return AndroidRuntime::registerNativeMethods(env,
1440                "android/media/MediaDrm", gMethods, NELEM(gMethods));
1441}
1442