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