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