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