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