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