• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "MediaDrm-JNI"
19 #include <utils/Log.h>
20 
21 #include "android_media_MediaDrm.h"
22 
23 #include "android_runtime/AndroidRuntime.h"
24 #include "android_os_Parcel.h"
25 #include "jni.h"
26 #include "JNIHelp.h"
27 
28 #include <binder/IServiceManager.h>
29 #include <binder/Parcel.h>
30 #include <media/IDrm.h>
31 #include <media/IMediaPlayerService.h>
32 #include <media/stagefright/foundation/ADebug.h>
33 #include <media/stagefright/MediaErrors.h>
34 
35 namespace android {
36 
37 #define FIND_CLASS(var, className) \
38     var = env->FindClass(className); \
39     LOG_FATAL_IF(! var, "Unable to find class " className);
40 
41 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
42     var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
43     LOG_FATAL_IF(! var, "Unable to find field " fieldName);
44 
45 #define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
46     var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
47     LOG_FATAL_IF(! var, "Unable to find method " fieldName);
48 
49 #define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
50     var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
51     LOG_FATAL_IF(! var, "Unable to find field " fieldName);
52 
53 #define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
54     var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
55     LOG_FATAL_IF(! var, "Unable to find static method " fieldName);
56 
57 
58 struct RequestFields {
59     jfieldID data;
60     jfieldID defaultUrl;
61 };
62 
63 struct ArrayListFields {
64     jmethodID init;
65     jmethodID add;
66 };
67 
68 struct HashmapFields {
69     jmethodID init;
70     jmethodID get;
71     jmethodID put;
72     jmethodID entrySet;
73 };
74 
75 struct SetFields {
76     jmethodID iterator;
77 };
78 
79 struct IteratorFields {
80     jmethodID next;
81     jmethodID hasNext;
82 };
83 
84 struct EntryFields {
85     jmethodID getKey;
86     jmethodID getValue;
87 };
88 
89 struct EventTypes {
90     jint kEventProvisionRequired;
91     jint kEventKeyRequired;
92     jint kEventKeyExpired;
93     jint kEventVendorDefined;
94 } gEventTypes;
95 
96 struct KeyTypes {
97     jint kKeyTypeStreaming;
98     jint kKeyTypeOffline;
99     jint kKeyTypeRelease;
100 } gKeyTypes;
101 
102 struct fields_t {
103     jfieldID context;
104     jmethodID post_event;
105     RequestFields keyRequest;
106     RequestFields provisionRequest;
107     ArrayListFields arraylist;
108     HashmapFields hashmap;
109     SetFields set;
110     IteratorFields iterator;
111     EntryFields entry;
112 };
113 
114 static fields_t gFields;
115 
116 // ----------------------------------------------------------------------------
117 // ref-counted object for callbacks
118 class JNIDrmListener: public DrmListener
119 {
120 public:
121     JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
122     ~JNIDrmListener();
123     virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
124 private:
125     JNIDrmListener();
126     jclass      mClass;     // Reference to MediaDrm class
127     jobject     mObject;    // Weak ref to MediaDrm Java object to call on
128 };
129 
JNIDrmListener(JNIEnv * env,jobject thiz,jobject weak_thiz)130 JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
131 {
132     // Hold onto the MediaDrm class for use in calling the static method
133     // that posts events to the application thread.
134     jclass clazz = env->GetObjectClass(thiz);
135     if (clazz == NULL) {
136         ALOGE("Can't find android/media/MediaDrm");
137         jniThrowException(env, "java/lang/Exception",
138                           "Can't find android/media/MediaDrm");
139         return;
140     }
141     mClass = (jclass)env->NewGlobalRef(clazz);
142 
143     // We use a weak reference so the MediaDrm object can be garbage collected.
144     // The reference is only used as a proxy for callbacks.
145     mObject  = env->NewGlobalRef(weak_thiz);
146 }
147 
~JNIDrmListener()148 JNIDrmListener::~JNIDrmListener()
149 {
150     // remove global references
151     JNIEnv *env = AndroidRuntime::getJNIEnv();
152     env->DeleteGlobalRef(mObject);
153     env->DeleteGlobalRef(mClass);
154 }
155 
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)156 void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
157                             const Parcel *obj)
158 {
159     jint jeventType;
160 
161     // translate DrmPlugin event types into their java equivalents
162     switch(eventType) {
163         case DrmPlugin::kDrmPluginEventProvisionRequired:
164             jeventType = gEventTypes.kEventProvisionRequired;
165             break;
166         case DrmPlugin::kDrmPluginEventKeyNeeded:
167             jeventType = gEventTypes.kEventKeyRequired;
168             break;
169         case DrmPlugin::kDrmPluginEventKeyExpired:
170             jeventType = gEventTypes.kEventKeyExpired;
171             break;
172         case DrmPlugin::kDrmPluginEventVendorDefined:
173             jeventType = gEventTypes.kEventVendorDefined;
174             break;
175         default:
176             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
177             return;
178     }
179 
180     JNIEnv *env = AndroidRuntime::getJNIEnv();
181     if (obj && obj->dataSize() > 0) {
182         jobject jParcel = createJavaParcelObject(env);
183         if (jParcel != NULL) {
184             Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
185             nativeParcel->setData(obj->data(), obj->dataSize());
186             env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
187                     jeventType, extra, jParcel);
188         }
189     }
190 
191     if (env->ExceptionCheck()) {
192         ALOGW("An exception occurred while notifying an event.");
193         LOGW_EX(env);
194         env->ExceptionClear();
195     }
196 }
197 
198 
throwExceptionAsNecessary(JNIEnv * env,status_t err,const char * msg=NULL)199 static bool throwExceptionAsNecessary(
200         JNIEnv *env, status_t err, const char *msg = NULL) {
201 
202     const char *drmMessage = NULL;
203 
204     switch(err) {
205     case ERROR_DRM_UNKNOWN:
206         drmMessage = "General DRM error";
207         break;
208     case ERROR_DRM_NO_LICENSE:
209         drmMessage = "No license";
210         break;
211     case ERROR_DRM_LICENSE_EXPIRED:
212         drmMessage = "License expired";
213         break;
214     case ERROR_DRM_SESSION_NOT_OPENED:
215         drmMessage = "Session not opened";
216         break;
217     case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
218         drmMessage = "Not initialized";
219         break;
220     case ERROR_DRM_DECRYPT:
221         drmMessage = "Decrypt error";
222         break;
223     case ERROR_DRM_CANNOT_HANDLE:
224         drmMessage = "Unsupported scheme or data format";
225         break;
226     case ERROR_DRM_TAMPER_DETECTED:
227         drmMessage = "Invalid state";
228         break;
229     default:
230         break;
231     }
232 
233     String8 vendorMessage;
234     if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
235         vendorMessage.format("DRM vendor-defined error: %d", err);
236         drmMessage = vendorMessage.string();
237     }
238 
239     if (err == BAD_VALUE) {
240         jniThrowException(env, "java/lang/IllegalArgumentException", msg);
241         return true;
242     } else if (err == ERROR_DRM_NOT_PROVISIONED) {
243         jniThrowException(env, "android/media/NotProvisionedException", msg);
244         return true;
245     } else if (err == ERROR_DRM_DEVICE_REVOKED) {
246         jniThrowException(env, "android/media/DeniedByServerException", msg);
247         return true;
248     } else if (err != OK) {
249         String8 errbuf;
250         if (drmMessage != NULL) {
251             if (msg == NULL) {
252                 msg = drmMessage;
253             } else {
254                 errbuf.format("%s: %s", msg, drmMessage);
255                 msg = errbuf.string();
256             }
257         }
258         ALOGE("Illegal state exception: %s", msg);
259         jniThrowException(env, "java/lang/IllegalStateException", msg);
260         return true;
261     }
262     return false;
263 }
264 
GetDrm(JNIEnv * env,jobject thiz)265 static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
266     JDrm *jdrm = (JDrm *)env->GetIntField(thiz, gFields.context);
267     return jdrm ? jdrm->getDrm() : NULL;
268 }
269 
JDrm(JNIEnv * env,jobject thiz,const uint8_t uuid[16])270 JDrm::JDrm(
271         JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
272     mObject = env->NewWeakGlobalRef(thiz);
273     mDrm = MakeDrm(uuid);
274     if (mDrm != NULL) {
275         mDrm->setListener(this);
276     }
277 }
278 
~JDrm()279 JDrm::~JDrm() {
280     mDrm.clear();
281 
282     JNIEnv *env = AndroidRuntime::getJNIEnv();
283 
284     env->DeleteWeakGlobalRef(mObject);
285     mObject = NULL;
286 }
287 
288 // static
MakeDrm()289 sp<IDrm> JDrm::MakeDrm() {
290     sp<IServiceManager> sm = defaultServiceManager();
291 
292     sp<IBinder> binder =
293         sm->getService(String16("media.player"));
294 
295     sp<IMediaPlayerService> service =
296         interface_cast<IMediaPlayerService>(binder);
297 
298     if (service == NULL) {
299         return NULL;
300     }
301 
302     sp<IDrm> drm = service->makeDrm();
303 
304     if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
305         return NULL;
306     }
307 
308     return drm;
309 }
310 
311 // static
MakeDrm(const uint8_t uuid[16])312 sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
313     sp<IDrm> drm = MakeDrm();
314 
315     if (drm == NULL) {
316         return NULL;
317     }
318 
319     status_t err = drm->createPlugin(uuid);
320 
321     if (err != OK) {
322         return NULL;
323     }
324 
325     return drm;
326 }
327 
setListener(const sp<DrmListener> & listener)328 status_t JDrm::setListener(const sp<DrmListener>& listener) {
329     Mutex::Autolock lock(mLock);
330     mListener = listener;
331     return OK;
332 }
333 
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)334 void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
335     sp<DrmListener> listener;
336     mLock.lock();
337     listener = mListener;
338     mLock.unlock();
339 
340     if (listener != NULL) {
341         Mutex::Autolock lock(mNotifyLock);
342         listener->notify(eventType, extra, obj);
343     }
344 }
345 
346 
347 // static
IsCryptoSchemeSupported(const uint8_t uuid[16])348 bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
349     sp<IDrm> drm = MakeDrm();
350 
351     if (drm == NULL) {
352         return false;
353     }
354 
355     return drm->isCryptoSchemeSupported(uuid);
356 }
357 
initCheck() const358 status_t JDrm::initCheck() const {
359     return mDrm == NULL ? NO_INIT : OK;
360 }
361 
362 // JNI conversion utilities
JByteArrayToVector(JNIEnv * env,jbyteArray const & byteArray)363 static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
364     Vector<uint8_t> vector;
365     size_t length = env->GetArrayLength(byteArray);
366     vector.insertAt((size_t)0, length);
367     env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
368     return vector;
369 }
370 
VectorToJByteArray(JNIEnv * env,Vector<uint8_t> const & vector)371 static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
372     size_t length = vector.size();
373     jbyteArray result = env->NewByteArray(length);
374     if (result != NULL) {
375         env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
376     }
377     return result;
378 }
379 
JStringToString8(JNIEnv * env,jstring const & jstr)380 static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
381     String8 result;
382 
383     const char *s = env->GetStringUTFChars(jstr, NULL);
384     if (s) {
385         result = s;
386         env->ReleaseStringUTFChars(jstr, s);
387     }
388     return result;
389 }
390 
391 /*
392     import java.util.HashMap;
393     import java.util.Set;
394     import java.Map.Entry;
395     import jav.util.Iterator;
396 
397     HashMap<k, v> hm;
398     Set<Entry<k, v> > s = hm.entrySet();
399     Iterator i = s.iterator();
400     Entry e = s.next();
401 */
402 
HashMapToKeyedVector(JNIEnv * env,jobject & hashMap)403 static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
404     jclass clazz;
405     FIND_CLASS(clazz, "java/lang/String");
406     KeyedVector<String8, String8> keyedVector;
407 
408     jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
409     if (entrySet) {
410         jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
411         if (iterator) {
412             jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
413             while (hasNext) {
414                 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
415                 if (entry) {
416                     jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
417                     if (!env->IsInstanceOf(obj, clazz)) {
418                         jniThrowException(env, "java/lang/IllegalArgumentException",
419                                           "HashMap key is not a String");
420                     }
421                     jstring jkey = static_cast<jstring>(obj);
422 
423                     obj = env->CallObjectMethod(entry, gFields.entry.getValue);
424                     if (!env->IsInstanceOf(obj, clazz)) {
425                         jniThrowException(env, "java/lang/IllegalArgumentException",
426                                           "HashMap value is not a String");
427                     }
428                     jstring jvalue = static_cast<jstring>(obj);
429 
430                     String8 key = JStringToString8(env, jkey);
431                     String8 value = JStringToString8(env, jvalue);
432                     keyedVector.add(key, value);
433 
434                     env->DeleteLocalRef(jkey);
435                     env->DeleteLocalRef(jvalue);
436                     hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
437                 }
438                 env->DeleteLocalRef(entry);
439             }
440             env->DeleteLocalRef(iterator);
441         }
442         env->DeleteLocalRef(entrySet);
443     }
444     return keyedVector;
445 }
446 
KeyedVectorToHashMap(JNIEnv * env,KeyedVector<String8,String8> const & map)447 static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
448     jclass clazz;
449     FIND_CLASS(clazz, "java/util/HashMap");
450     jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
451     for (size_t i = 0; i < map.size(); ++i) {
452         jstring jkey = env->NewStringUTF(map.keyAt(i).string());
453         jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
454         env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
455         env->DeleteLocalRef(jkey);
456         env->DeleteLocalRef(jvalue);
457     }
458     return hashMap;
459 }
460 
ListOfVectorsToArrayListOfByteArray(JNIEnv * env,List<Vector<uint8_t>> list)461 static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
462                                                    List<Vector<uint8_t> > list) {
463     jclass clazz;
464     FIND_CLASS(clazz, "java/util/ArrayList");
465     jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
466     List<Vector<uint8_t> >::iterator iter = list.begin();
467     while (iter != list.end()) {
468         jbyteArray byteArray = VectorToJByteArray(env, *iter);
469         env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
470         env->DeleteLocalRef(byteArray);
471         iter++;
472     }
473 
474     return arrayList;
475 }
476 
477 }  // namespace android
478 
479 using namespace android;
480 
setDrm(JNIEnv * env,jobject thiz,const sp<JDrm> & drm)481 static sp<JDrm> setDrm(
482         JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
483     sp<JDrm> old = (JDrm *)env->GetIntField(thiz, gFields.context);
484     if (drm != NULL) {
485         drm->incStrong(thiz);
486     }
487     if (old != NULL) {
488         old->decStrong(thiz);
489     }
490     env->SetIntField(thiz, gFields.context, (int)drm.get());
491 
492     return old;
493 }
494 
CheckSession(JNIEnv * env,const sp<IDrm> & drm,jbyteArray const & jsessionId)495 static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
496 {
497     if (drm == NULL) {
498         jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
499         return false;
500     }
501 
502     if (jsessionId == NULL) {
503         jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
504         return false;
505     }
506     return true;
507 }
508 
android_media_MediaDrm_release(JNIEnv * env,jobject thiz)509 static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
510     sp<JDrm> drm = setDrm(env, thiz, NULL);
511     if (drm != NULL) {
512         drm->setListener(NULL);
513     }
514 }
515 
android_media_MediaDrm_native_init(JNIEnv * env)516 static void android_media_MediaDrm_native_init(JNIEnv *env) {
517     jclass clazz;
518     FIND_CLASS(clazz, "android/media/MediaDrm");
519     GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
520     GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
521                          "(Ljava/lang/Object;IILjava/lang/Object;)V");
522 
523     jfieldID field;
524     GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
525     gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
526     GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
527     gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
528     GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
529     gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
530     GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
531     gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
532 
533     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
534     gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
535     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
536     gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
537     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
538     gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
539 
540     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
541     GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
542     GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
543 
544     FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
545     GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
546     GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
547 
548     FIND_CLASS(clazz, "java/util/ArrayList");
549     GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
550     GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
551 
552     FIND_CLASS(clazz, "java/util/HashMap");
553     GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
554     GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
555     GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
556                   "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
557     GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
558 
559     FIND_CLASS(clazz, "java/util/Set");
560     GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
561 
562     FIND_CLASS(clazz, "java/util/Iterator");
563     GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
564     GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
565 
566     FIND_CLASS(clazz, "java/util/Map$Entry");
567     GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
568     GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
569 }
570 
android_media_MediaDrm_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jbyteArray uuidObj)571 static void android_media_MediaDrm_native_setup(
572         JNIEnv *env, jobject thiz,
573         jobject weak_this, jbyteArray uuidObj) {
574 
575     if (uuidObj == NULL) {
576         jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
577         return;
578     }
579 
580     Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
581 
582     if (uuid.size() != 16) {
583         jniThrowException(env, "java/lang/IllegalArgumentException",
584                           "invalid UUID size, expected 16 bytes");
585         return;
586     }
587 
588     sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
589 
590     status_t err = drm->initCheck();
591 
592     if (err != OK) {
593         jniThrowException(
594                 env,
595                 "android/media/UnsupportedSchemeException",
596                 "Failed to instantiate drm object.");
597         return;
598     }
599 
600     sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
601     drm->setListener(listener);
602     setDrm(env, thiz, drm);
603 }
604 
android_media_MediaDrm_native_finalize(JNIEnv * env,jobject thiz)605 static void android_media_MediaDrm_native_finalize(
606         JNIEnv *env, jobject thiz) {
607     android_media_MediaDrm_release(env, thiz);
608 }
609 
android_media_MediaDrm_isCryptoSchemeSupportedNative(JNIEnv * env,jobject thiz,jbyteArray uuidObj)610 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
611         JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
612 
613     if (uuidObj == NULL) {
614         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
615         return false;
616     }
617 
618     Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
619 
620     if (uuid.size() != 16) {
621         jniThrowException(
622                 env,
623                 "java/lang/IllegalArgumentException",
624                 "invalid UUID size, expected 16 bytes");
625         return false;
626     }
627 
628     return JDrm::IsCryptoSchemeSupported(uuid.array());
629 }
630 
android_media_MediaDrm_openSession(JNIEnv * env,jobject thiz)631 static jbyteArray android_media_MediaDrm_openSession(
632     JNIEnv *env, jobject thiz) {
633     sp<IDrm> drm = GetDrm(env, thiz);
634 
635     if (drm == NULL) {
636         jniThrowException(env, "java/lang/IllegalStateException",
637                           "MediaDrm obj is null");
638         return NULL;
639     }
640 
641     Vector<uint8_t> sessionId;
642     status_t err = drm->openSession(sessionId);
643 
644     if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
645         return NULL;
646     }
647 
648     return VectorToJByteArray(env, sessionId);
649 }
650 
android_media_MediaDrm_closeSession(JNIEnv * env,jobject thiz,jbyteArray jsessionId)651 static void android_media_MediaDrm_closeSession(
652     JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
653     sp<IDrm> drm = GetDrm(env, thiz);
654 
655     if (!CheckSession(env, drm, jsessionId)) {
656         return;
657     }
658 
659     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
660 
661     status_t err = drm->closeSession(sessionId);
662 
663     throwExceptionAsNecessary(env, err, "Failed to close session");
664 }
665 
android_media_MediaDrm_getKeyRequest(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jinitData,jstring jmimeType,jint jkeyType,jobject joptParams)666 static jobject android_media_MediaDrm_getKeyRequest(
667     JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
668     jstring jmimeType, jint jkeyType, jobject joptParams) {
669     sp<IDrm> drm = GetDrm(env, thiz);
670 
671     if (!CheckSession(env, drm, jsessionId)) {
672         return NULL;
673     }
674 
675     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
676 
677     Vector<uint8_t> initData;
678     if (jinitData != NULL) {
679         initData = JByteArrayToVector(env, jinitData);
680     }
681 
682     String8 mimeType;
683     if (jmimeType != NULL) {
684         mimeType = JStringToString8(env, jmimeType);
685     }
686 
687     DrmPlugin::KeyType keyType;
688     if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
689         keyType = DrmPlugin::kKeyType_Streaming;
690     } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
691         keyType = DrmPlugin::kKeyType_Offline;
692     } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
693         keyType = DrmPlugin::kKeyType_Release;
694     } else {
695         jniThrowException(env, "java/lang/IllegalArgumentException",
696                           "invalid keyType");
697         return NULL;
698     }
699 
700     KeyedVector<String8, String8> optParams;
701     if (joptParams != NULL) {
702         optParams = HashMapToKeyedVector(env, joptParams);
703     }
704 
705     Vector<uint8_t> request;
706     String8 defaultUrl;
707 
708     status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
709                                           keyType, optParams, request, defaultUrl);
710 
711     if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
712         return NULL;
713     }
714 
715     // Fill out return obj
716     jclass clazz;
717     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
718 
719     jobject keyObj = NULL;
720 
721     if (clazz) {
722         keyObj = env->AllocObject(clazz);
723         jbyteArray jrequest = VectorToJByteArray(env, request);
724         env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
725 
726         jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
727         env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
728     }
729 
730     return keyObj;
731 }
732 
android_media_MediaDrm_provideKeyResponse(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jresponse)733 static jbyteArray android_media_MediaDrm_provideKeyResponse(
734     JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
735     sp<IDrm> drm = GetDrm(env, thiz);
736 
737     if (!CheckSession(env, drm, jsessionId)) {
738         return NULL;
739     }
740 
741     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
742 
743     if (jresponse == NULL) {
744         jniThrowException(env, "java/lang/IllegalArgumentException",
745                           "key response is null");
746         return NULL;
747     }
748     Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
749     Vector<uint8_t> keySetId;
750 
751     status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
752 
753     throwExceptionAsNecessary(env, err, "Failed to handle key response");
754     return VectorToJByteArray(env, keySetId);
755 }
756 
android_media_MediaDrm_removeKeys(JNIEnv * env,jobject thiz,jbyteArray jkeysetId)757 static void android_media_MediaDrm_removeKeys(
758     JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
759     sp<IDrm> drm = GetDrm(env, thiz);
760 
761     if (jkeysetId == NULL) {
762         jniThrowException(env, "java/lang/IllegalArgumentException",
763                           "keySetId is null");
764         return;
765     }
766 
767     Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
768 
769     status_t err = drm->removeKeys(keySetId);
770 
771     throwExceptionAsNecessary(env, err, "Failed to remove keys");
772 }
773 
android_media_MediaDrm_restoreKeys(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jkeysetId)774 static void android_media_MediaDrm_restoreKeys(
775     JNIEnv *env, jobject thiz, jbyteArray jsessionId,
776     jbyteArray jkeysetId) {
777 
778     sp<IDrm> drm = GetDrm(env, thiz);
779 
780     if (!CheckSession(env, drm, jsessionId)) {
781         return;
782     }
783 
784     if (jkeysetId == NULL) {
785         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
786         return;
787     }
788 
789     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
790     Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
791 
792     status_t err = drm->restoreKeys(sessionId, keySetId);
793 
794     throwExceptionAsNecessary(env, err, "Failed to restore keys");
795 }
796 
android_media_MediaDrm_queryKeyStatus(JNIEnv * env,jobject thiz,jbyteArray jsessionId)797 static jobject android_media_MediaDrm_queryKeyStatus(
798     JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
799     sp<IDrm> drm = GetDrm(env, thiz);
800 
801     if (!CheckSession(env, drm, jsessionId)) {
802         return NULL;
803     }
804     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
805 
806     KeyedVector<String8, String8> infoMap;
807 
808     status_t err = drm->queryKeyStatus(sessionId, infoMap);
809 
810     if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
811         return NULL;
812     }
813 
814     return KeyedVectorToHashMap(env, infoMap);
815 }
816 
android_media_MediaDrm_getProvisionRequest(JNIEnv * env,jobject thiz)817 static jobject android_media_MediaDrm_getProvisionRequest(
818     JNIEnv *env, jobject thiz) {
819     sp<IDrm> drm = GetDrm(env, thiz);
820 
821     if (drm == NULL) {
822         jniThrowException(env, "java/lang/IllegalStateException",
823                           "MediaDrm obj is null");
824         return NULL;
825     }
826 
827     Vector<uint8_t> request;
828     String8 defaultUrl;
829 
830     status_t err = drm->getProvisionRequest(request, defaultUrl);
831 
832     if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
833         return NULL;
834     }
835 
836     // Fill out return obj
837     jclass clazz;
838     FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
839 
840     jobject provisionObj = NULL;
841 
842     if (clazz) {
843         provisionObj = env->AllocObject(clazz);
844         jbyteArray jrequest = VectorToJByteArray(env, request);
845         env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
846 
847         jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
848         env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
849     }
850 
851     return provisionObj;
852 }
853 
android_media_MediaDrm_provideProvisionResponse(JNIEnv * env,jobject thiz,jbyteArray jresponse)854 static void android_media_MediaDrm_provideProvisionResponse(
855     JNIEnv *env, jobject thiz, jbyteArray jresponse) {
856     sp<IDrm> drm = GetDrm(env, thiz);
857 
858     if (drm == NULL) {
859         jniThrowException(env, "java/lang/IllegalStateException",
860                           "MediaDrm obj is null");
861         return;
862     }
863 
864     if (jresponse == NULL) {
865         jniThrowException(env, "java/lang/IllegalArgumentException",
866                           "provision response is null");
867         return;
868     }
869 
870     Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
871 
872     status_t err = drm->provideProvisionResponse(response);
873 
874     throwExceptionAsNecessary(env, err, "Failed to handle provision response");
875 }
876 
android_media_MediaDrm_getSecureStops(JNIEnv * env,jobject thiz)877 static jobject android_media_MediaDrm_getSecureStops(
878     JNIEnv *env, jobject thiz) {
879     sp<IDrm> drm = GetDrm(env, thiz);
880 
881     if (drm == NULL) {
882         jniThrowException(env, "java/lang/IllegalStateException",
883                           "MediaDrm obj is null");
884         return NULL;
885     }
886 
887     List<Vector<uint8_t> > secureStops;
888 
889     status_t err = drm->getSecureStops(secureStops);
890 
891     if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
892         return NULL;
893     }
894 
895     return ListOfVectorsToArrayListOfByteArray(env, secureStops);
896 }
897 
android_media_MediaDrm_releaseSecureStops(JNIEnv * env,jobject thiz,jbyteArray jssRelease)898 static void android_media_MediaDrm_releaseSecureStops(
899     JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
900     sp<IDrm> drm = GetDrm(env, thiz);
901 
902     if (drm == NULL) {
903         jniThrowException(env, "java/lang/IllegalStateException",
904                           "MediaDrm obj is null");
905         return;
906     }
907 
908     Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
909 
910     status_t err = drm->releaseSecureStops(ssRelease);
911 
912     throwExceptionAsNecessary(env, err, "Failed to release secure stops");
913 }
914 
android_media_MediaDrm_getPropertyString(JNIEnv * env,jobject thiz,jstring jname)915 static jstring android_media_MediaDrm_getPropertyString(
916     JNIEnv *env, jobject thiz, jstring jname) {
917     sp<IDrm> drm = GetDrm(env, thiz);
918 
919     if (drm == NULL) {
920         jniThrowException(env, "java/lang/IllegalStateException",
921                           "MediaDrm obj is null");
922         return NULL;
923     }
924 
925     if (jname == NULL) {
926         jniThrowException(env, "java/lang/IllegalArgumentException",
927                           "property name String is null");
928         return NULL;
929     }
930 
931     String8 name = JStringToString8(env, jname);
932     String8 value;
933 
934     status_t err = drm->getPropertyString(name, value);
935 
936     if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
937         return NULL;
938     }
939 
940     return env->NewStringUTF(value.string());
941 }
942 
android_media_MediaDrm_getPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname)943 static jbyteArray android_media_MediaDrm_getPropertyByteArray(
944     JNIEnv *env, jobject thiz, jstring jname) {
945     sp<IDrm> drm = GetDrm(env, thiz);
946 
947     if (drm == NULL) {
948         jniThrowException(env, "java/lang/IllegalStateException",
949                           "MediaDrm obj is null");
950         return NULL;
951     }
952 
953     if (jname == NULL) {
954         jniThrowException(env, "java/lang/IllegalArgumentException",
955                           "property name String is null");
956         return NULL;
957     }
958 
959     String8 name = JStringToString8(env, jname);
960     Vector<uint8_t> value;
961 
962     status_t err = drm->getPropertyByteArray(name, value);
963 
964     if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
965         return NULL;
966     }
967 
968     return VectorToJByteArray(env, value);
969 }
970 
android_media_MediaDrm_setPropertyString(JNIEnv * env,jobject thiz,jstring jname,jstring jvalue)971 static void android_media_MediaDrm_setPropertyString(
972     JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
973     sp<IDrm> drm = GetDrm(env, thiz);
974 
975     if (drm == NULL) {
976         jniThrowException(env, "java/lang/IllegalStateException",
977                           "MediaDrm obj is null");
978         return;
979     }
980 
981     if (jname == NULL) {
982         jniThrowException(env, "java/lang/IllegalArgumentException",
983                           "property name String is null");
984         return;
985     }
986 
987     if (jvalue == NULL) {
988         jniThrowException(env, "java/lang/IllegalArgumentException",
989                           "property value String is null");
990         return;
991     }
992 
993     String8 name = JStringToString8(env, jname);
994     String8 value = JStringToString8(env, jvalue);
995 
996     status_t err = drm->setPropertyString(name, value);
997 
998     throwExceptionAsNecessary(env, err, "Failed to set property");
999 }
1000 
android_media_MediaDrm_setPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname,jbyteArray jvalue)1001 static void android_media_MediaDrm_setPropertyByteArray(
1002     JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1003     sp<IDrm> drm = GetDrm(env, thiz);
1004 
1005     if (drm == NULL) {
1006         jniThrowException(env, "java/lang/IllegalStateException",
1007                           "MediaDrm obj is null");
1008         return;
1009     }
1010 
1011     if (jname == NULL) {
1012         jniThrowException(env, "java/lang/IllegalArgumentException",
1013                           "property name String is null");
1014         return;
1015     }
1016 
1017     if (jvalue == NULL) {
1018         jniThrowException(env, "java/lang/IllegalArgumentException",
1019                           "property value byte array is null");
1020         return;
1021     }
1022 
1023     String8 name = JStringToString8(env, jname);
1024     Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1025 
1026     status_t err = drm->setPropertyByteArray(name, value);
1027 
1028     throwExceptionAsNecessary(env, err, "Failed to set property");
1029 }
1030 
android_media_MediaDrm_setCipherAlgorithmNative(JNIEnv * env,jobject thiz,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1031 static void android_media_MediaDrm_setCipherAlgorithmNative(
1032     JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1033     jstring jalgorithm) {
1034 
1035     sp<IDrm> drm = GetDrm(env, jdrm);
1036 
1037     if (!CheckSession(env, drm, jsessionId)) {
1038         return;
1039     }
1040 
1041     if (jalgorithm == NULL) {
1042         jniThrowException(env, "java/lang/IllegalArgumentException",
1043                           "algorithm String is null");
1044         return;
1045     }
1046 
1047     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1048     String8 algorithm = JStringToString8(env, jalgorithm);
1049 
1050     status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1051 
1052     throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1053 }
1054 
android_media_MediaDrm_setMacAlgorithmNative(JNIEnv * env,jobject thiz,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1055 static void android_media_MediaDrm_setMacAlgorithmNative(
1056     JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1057     jstring jalgorithm) {
1058 
1059     sp<IDrm> drm = GetDrm(env, jdrm);
1060 
1061     if (!CheckSession(env, drm, jsessionId)) {
1062         return;
1063     }
1064 
1065     if (jalgorithm == NULL) {
1066         jniThrowException(env, "java/lang/IllegalArgumentException",
1067                           "algorithm String is null");
1068         return;
1069     }
1070 
1071     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1072     String8 algorithm = JStringToString8(env, jalgorithm);
1073 
1074     status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1075 
1076     throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1077 }
1078 
1079 
android_media_MediaDrm_encryptNative(JNIEnv * env,jobject thiz,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1080 static jbyteArray android_media_MediaDrm_encryptNative(
1081     JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1082     jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1083 
1084     sp<IDrm> drm = GetDrm(env, jdrm);
1085 
1086     if (!CheckSession(env, drm, jsessionId)) {
1087         return NULL;
1088     }
1089 
1090     if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1091         jniThrowException(env, "java/lang/IllegalArgumentException",
1092                           "required argument is null");
1093         return NULL;
1094     }
1095 
1096     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1097     Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1098     Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1099     Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1100     Vector<uint8_t> output;
1101 
1102     status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1103 
1104     throwExceptionAsNecessary(env, err, "Failed to encrypt");
1105 
1106     return VectorToJByteArray(env, output);
1107 }
1108 
android_media_MediaDrm_decryptNative(JNIEnv * env,jobject thiz,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1109 static jbyteArray android_media_MediaDrm_decryptNative(
1110     JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1111     jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1112 
1113     sp<IDrm> drm = GetDrm(env, jdrm);
1114 
1115     if (!CheckSession(env, drm, jsessionId)) {
1116         return NULL;
1117     }
1118 
1119     if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1120         jniThrowException(env, "java/lang/IllegalArgumentException",
1121                           "required argument is null");
1122         return NULL;
1123     }
1124 
1125     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1126     Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1127     Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1128     Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1129     Vector<uint8_t> output;
1130 
1131     status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1132     throwExceptionAsNecessary(env, err, "Failed to decrypt");
1133 
1134     return VectorToJByteArray(env, output);
1135 }
1136 
android_media_MediaDrm_signNative(JNIEnv * env,jobject thiz,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage)1137 static jbyteArray android_media_MediaDrm_signNative(
1138     JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1139     jbyteArray jkeyId, jbyteArray jmessage) {
1140 
1141     sp<IDrm> drm = GetDrm(env, jdrm);
1142 
1143     if (!CheckSession(env, drm, jsessionId)) {
1144         return NULL;
1145     }
1146 
1147     if (jkeyId == NULL || jmessage == NULL) {
1148         jniThrowException(env, "java/lang/IllegalArgumentException",
1149                           "required argument is null");
1150         return NULL;
1151     }
1152 
1153     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1154     Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1155     Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1156     Vector<uint8_t> signature;
1157 
1158     status_t err = drm->sign(sessionId, keyId, message, signature);
1159 
1160     throwExceptionAsNecessary(env, err, "Failed to sign");
1161 
1162     return VectorToJByteArray(env, signature);
1163 }
1164 
android_media_MediaDrm_verifyNative(JNIEnv * env,jobject thiz,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage,jbyteArray jsignature)1165 static jboolean android_media_MediaDrm_verifyNative(
1166     JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1167     jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1168 
1169     sp<IDrm> drm = GetDrm(env, jdrm);
1170 
1171     if (!CheckSession(env, drm, jsessionId)) {
1172         return false;
1173     }
1174 
1175     if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
1176         jniThrowException(env, "java/lang/IllegalArgumentException",
1177                           "required argument is null");
1178         return false;
1179     }
1180 
1181     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1182     Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1183     Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1184     Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1185     bool match;
1186 
1187     status_t err = drm->verify(sessionId, keyId, message, signature, match);
1188 
1189     throwExceptionAsNecessary(env, err, "Failed to verify");
1190     return match;
1191 }
1192 
1193 
1194 static JNINativeMethod gMethods[] = {
1195     { "release", "()V", (void *)android_media_MediaDrm_release },
1196     { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1197 
1198     { "native_setup", "(Ljava/lang/Object;[B)V",
1199       (void *)android_media_MediaDrm_native_setup },
1200 
1201     { "native_finalize", "()V",
1202       (void *)android_media_MediaDrm_native_finalize },
1203 
1204     { "isCryptoSchemeSupportedNative", "([B)Z",
1205       (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1206 
1207     { "openSession", "()[B",
1208       (void *)android_media_MediaDrm_openSession },
1209 
1210     { "closeSession", "([B)V",
1211       (void *)android_media_MediaDrm_closeSession },
1212 
1213     { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1214       "Landroid/media/MediaDrm$KeyRequest;",
1215       (void *)android_media_MediaDrm_getKeyRequest },
1216 
1217     { "provideKeyResponse", "([B[B)[B",
1218       (void *)android_media_MediaDrm_provideKeyResponse },
1219 
1220     { "removeKeys", "([B)V",
1221       (void *)android_media_MediaDrm_removeKeys },
1222 
1223     { "restoreKeys", "([B[B)V",
1224       (void *)android_media_MediaDrm_restoreKeys },
1225 
1226     { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1227       (void *)android_media_MediaDrm_queryKeyStatus },
1228 
1229     { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
1230       (void *)android_media_MediaDrm_getProvisionRequest },
1231 
1232     { "provideProvisionResponse", "([B)V",
1233       (void *)android_media_MediaDrm_provideProvisionResponse },
1234 
1235     { "getSecureStops", "()Ljava/util/List;",
1236       (void *)android_media_MediaDrm_getSecureStops },
1237 
1238     { "releaseSecureStops", "([B)V",
1239       (void *)android_media_MediaDrm_releaseSecureStops },
1240 
1241     { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1242       (void *)android_media_MediaDrm_getPropertyString },
1243 
1244     { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1245       (void *)android_media_MediaDrm_getPropertyByteArray },
1246 
1247     { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1248       (void *)android_media_MediaDrm_setPropertyString },
1249 
1250     { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1251       (void *)android_media_MediaDrm_setPropertyByteArray },
1252 
1253     { "setCipherAlgorithmNative",
1254       "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1255       (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1256 
1257     { "setMacAlgorithmNative",
1258       "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1259       (void *)android_media_MediaDrm_setMacAlgorithmNative },
1260 
1261     { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1262       (void *)android_media_MediaDrm_encryptNative },
1263 
1264     { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1265       (void *)android_media_MediaDrm_decryptNative },
1266 
1267     { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1268       (void *)android_media_MediaDrm_signNative },
1269 
1270     { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1271       (void *)android_media_MediaDrm_verifyNative },
1272 };
1273 
register_android_media_Drm(JNIEnv * env)1274 int register_android_media_Drm(JNIEnv *env) {
1275     return AndroidRuntime::registerNativeMethods(env,
1276                 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1277 }
1278 
1279