OSDN Git Service

[automerger skipped] Merge "Optimise the hit test algorithm" into oc-mr1-dev
[android-x86/frameworks-base.git] / media / jni / android_media_MediaDrm.cpp
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/stagefright/foundation/ADebug.h>
35 #include <media/stagefright/MediaErrors.h>
36 #include <mediadrm/IDrm.h>
37 #include <mediadrm/IMediaDrmService.h>
38
39 using ::android::os::PersistableBundle;
40
41
42 namespace 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
69 struct RequestFields {
70     jfieldID data;
71     jfieldID defaultUrl;
72     jfieldID requestType;
73 };
74
75 struct ArrayListFields {
76     jmethodID init;
77     jmethodID add;
78 };
79
80 struct HashmapFields {
81     jmethodID init;
82     jmethodID get;
83     jmethodID put;
84     jmethodID entrySet;
85 };
86
87 struct SetFields {
88     jmethodID iterator;
89 };
90
91 struct IteratorFields {
92     jmethodID next;
93     jmethodID hasNext;
94 };
95
96 struct EntryFields {
97     jmethodID getKey;
98     jmethodID getValue;
99 };
100
101 struct EventTypes {
102     jint kEventProvisionRequired;
103     jint kEventKeyRequired;
104     jint kEventKeyExpired;
105     jint kEventVendorDefined;
106     jint kEventSessionReclaimed;
107 } gEventTypes;
108
109 struct EventWhat {
110     jint kWhatDrmEvent;
111     jint kWhatExpirationUpdate;
112     jint kWhatKeyStatusChange;
113 } gEventWhat;
114
115 struct KeyTypes {
116     jint kKeyTypeStreaming;
117     jint kKeyTypeOffline;
118     jint kKeyTypeRelease;
119 } gKeyTypes;
120
121 struct KeyRequestTypes {
122     jint kKeyRequestTypeInitial;
123     jint kKeyRequestTypeRenewal;
124     jint kKeyRequestTypeRelease;
125     jint kKeyRequestTypeNone;
126     jint kKeyRequestTypeUpdate;
127 } gKeyRequestTypes;
128
129 struct CertificateTypes {
130     jint kCertificateTypeNone;
131     jint kCertificateTypeX509;
132 } gCertificateTypes;
133
134 struct CertificateFields {
135     jfieldID wrappedPrivateKey;
136     jfieldID certificateData;
137 };
138
139 struct StateExceptionFields {
140     jmethodID init;
141     jclass classId;
142 };
143
144 struct 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
154 struct 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
165 struct 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
186 static fields_t gFields;
187
188 namespace {
189
190 // Helper function to convert a native PersistableBundle to a Java
191 // PersistableBundle.
192 jobject 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
235 class JNIDrmListener: public DrmListener
236 {
237 public:
238     JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
239     ~JNIDrmListener();
240     virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
241 private:
242     JNIDrmListener();
243     jclass      mClass;     // Reference to MediaDrm class
244     jobject     mObject;    // Weak ref to MediaDrm Java object to call on
245 };
246
247 JNIDrmListener::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
265 JNIDrmListener::~JNIDrmListener()
266 {
267     // remove global references
268     JNIEnv *env = AndroidRuntime::getJNIEnv();
269     env->DeleteGlobalRef(mObject);
270     env->DeleteGlobalRef(mClass);
271 }
272
273 void 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
331 static 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
340 static 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
412 static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
413     JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
414     return jdrm ? jdrm->getDrm() : NULL;
415 }
416
417 JDrm::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
427 JDrm::~JDrm() {
428     JNIEnv *env = AndroidRuntime::getJNIEnv();
429
430     env->DeleteWeakGlobalRef(mObject);
431     mObject = NULL;
432 }
433
434 // static
435 sp<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
453 sp<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
469 status_t JDrm::setListener(const sp<DrmListener>& listener) {
470     Mutex::Autolock lock(mLock);
471     mListener = listener;
472     return OK;
473 }
474
475 void 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
487 void JDrm::disconnect() {
488     if (mDrm != NULL) {
489         mDrm->destroyPlugin();
490         mDrm.clear();
491     }
492 }
493
494
495 // static
496 bool 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
506 status_t JDrm::initCheck() const {
507     return mDrm == NULL ? NO_INIT : OK;
508 }
509
510 // JNI conversion utilities
511 static 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
519 static 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
528 static 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
551 static 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
602 static 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
615 static 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
632 using namespace android;
633
634 static 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
648 static 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
656 static 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
669 static 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
677 static 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, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
733     gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
734     GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
735     gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
736     GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
737     gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
738     GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
739     gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
740     GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_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
821 static 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
863 static 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
889 static 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
928 static 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
943 static 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
1043 static 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
1069 static 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
1086 static 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
1109 static 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
1129 static 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
1174 static 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
1211 static 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
1230 static 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
1251 static 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
1270 static 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
1285 static 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
1300 static 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
1314 static 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
1334 static 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
1353 static 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
1372 static 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
1389 static 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
1406 static 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
1441 static 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
1467 static 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
1493 static 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
1521 static 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
1549 static 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
1573 static 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
1598 static 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
1629 static 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
1659 static 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
1689 static 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
1717 static jobject
1718 android_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
1738 static 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
1770 static 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
1881 int register_android_media_Drm(JNIEnv *env) {
1882     return AndroidRuntime::registerNativeMethods(env,
1883                 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1884 }