• 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 <nativehelper/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],const String8 & appPackageName)337 JDrm::JDrm(
338         JNIEnv *env, jobject thiz, const uint8_t uuid[16],
339         const String8 &appPackageName) {
340     mObject = env->NewWeakGlobalRef(thiz);
341     mDrm = MakeDrm(uuid, appPackageName);
342     if (mDrm != NULL) {
343         mDrm->setListener(this);
344     }
345 }
346 
~JDrm()347 JDrm::~JDrm() {
348     JNIEnv *env = AndroidRuntime::getJNIEnv();
349 
350     env->DeleteWeakGlobalRef(mObject);
351     mObject = NULL;
352 }
353 
354 // static
MakeDrm()355 sp<IDrm> JDrm::MakeDrm() {
356     sp<IServiceManager> sm = defaultServiceManager();
357 
358     sp<IBinder> binder = sm->getService(String16("media.drm"));
359     sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
360     if (service == NULL) {
361         return NULL;
362     }
363 
364     sp<IDrm> drm = service->makeDrm();
365     if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
366         return NULL;
367     }
368 
369     return drm;
370 }
371 
372 // static
MakeDrm(const uint8_t uuid[16],const String8 & appPackageName)373 sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
374     sp<IDrm> drm = MakeDrm();
375 
376     if (drm == NULL) {
377         return NULL;
378     }
379 
380     status_t err = drm->createPlugin(uuid, appPackageName);
381 
382     if (err != OK) {
383         return NULL;
384     }
385 
386     return drm;
387 }
388 
setListener(const sp<DrmListener> & listener)389 status_t JDrm::setListener(const sp<DrmListener>& listener) {
390     Mutex::Autolock lock(mLock);
391     mListener = listener;
392     return OK;
393 }
394 
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)395 void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
396     sp<DrmListener> listener;
397     mLock.lock();
398     listener = mListener;
399     mLock.unlock();
400 
401     if (listener != NULL) {
402         Mutex::Autolock lock(mNotifyLock);
403         listener->notify(eventType, extra, obj);
404     }
405 }
406 
disconnect()407 void JDrm::disconnect() {
408     if (mDrm != NULL) {
409         mDrm->destroyPlugin();
410         mDrm.clear();
411     }
412 }
413 
414 
415 // static
IsCryptoSchemeSupported(const uint8_t uuid[16],const String8 & mimeType)416 bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
417     sp<IDrm> drm = MakeDrm();
418 
419     if (drm == NULL) {
420         return false;
421     }
422 
423     return drm->isCryptoSchemeSupported(uuid, mimeType);
424 }
425 
initCheck() const426 status_t JDrm::initCheck() const {
427     return mDrm == NULL ? NO_INIT : OK;
428 }
429 
430 // JNI conversion utilities
JByteArrayToVector(JNIEnv * env,jbyteArray const & byteArray)431 static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
432     Vector<uint8_t> vector;
433     size_t length = env->GetArrayLength(byteArray);
434     vector.insertAt((size_t)0, length);
435     env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
436     return vector;
437 }
438 
VectorToJByteArray(JNIEnv * env,Vector<uint8_t> const & vector)439 static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
440     size_t length = vector.size();
441     jbyteArray result = env->NewByteArray(length);
442     if (result != NULL) {
443         env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
444     }
445     return result;
446 }
447 
JStringToString8(JNIEnv * env,jstring const & jstr)448 static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
449     String8 result;
450 
451     const char *s = env->GetStringUTFChars(jstr, NULL);
452     if (s) {
453         result = s;
454         env->ReleaseStringUTFChars(jstr, s);
455     }
456     return result;
457 }
458 
459 /*
460     import java.util.HashMap;
461     import java.util.Set;
462     import java.Map.Entry;
463     import jav.util.Iterator;
464 
465     HashMap<k, v> hm;
466     Set<Entry<k, v> > s = hm.entrySet();
467     Iterator i = s.iterator();
468     Entry e = s.next();
469 */
470 
HashMapToKeyedVector(JNIEnv * env,jobject & hashMap,bool * pIsOK)471 static KeyedVector<String8, String8> HashMapToKeyedVector(
472     JNIEnv *env, jobject &hashMap, bool* pIsOK) {
473     jclass clazz = gFields.stringClassId;
474     KeyedVector<String8, String8> keyedVector;
475     *pIsOK = true;
476 
477     jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
478     if (entrySet) {
479         jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
480         if (iterator) {
481             jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
482             while (hasNext) {
483                 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
484                 if (entry) {
485                     jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
486                     if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
487                         jniThrowException(env, "java/lang/IllegalArgumentException",
488                                           "HashMap key is not a String");
489                         env->DeleteLocalRef(entry);
490                         *pIsOK = false;
491                         break;
492                     }
493                     jstring jkey = static_cast<jstring>(obj);
494 
495                     obj = env->CallObjectMethod(entry, gFields.entry.getValue);
496                     if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
497                         jniThrowException(env, "java/lang/IllegalArgumentException",
498                                           "HashMap value is not a String");
499                         env->DeleteLocalRef(entry);
500                         *pIsOK = false;
501                         break;
502                     }
503                     jstring jvalue = static_cast<jstring>(obj);
504 
505                     String8 key = JStringToString8(env, jkey);
506                     String8 value = JStringToString8(env, jvalue);
507                     keyedVector.add(key, value);
508 
509                     env->DeleteLocalRef(jkey);
510                     env->DeleteLocalRef(jvalue);
511                     hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
512                 }
513                 env->DeleteLocalRef(entry);
514             }
515             env->DeleteLocalRef(iterator);
516         }
517         env->DeleteLocalRef(entrySet);
518     }
519     return keyedVector;
520 }
521 
KeyedVectorToHashMap(JNIEnv * env,KeyedVector<String8,String8> const & map)522 static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
523     jclass clazz = gFields.hashmapClassId;
524     jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
525     for (size_t i = 0; i < map.size(); ++i) {
526         jstring jkey = env->NewStringUTF(map.keyAt(i).string());
527         jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
528         env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
529         env->DeleteLocalRef(jkey);
530         env->DeleteLocalRef(jvalue);
531     }
532     return hashMap;
533 }
534 
ListOfVectorsToArrayListOfByteArray(JNIEnv * env,List<Vector<uint8_t>> list)535 static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
536                                                    List<Vector<uint8_t> > list) {
537     jclass clazz = gFields.arraylistClassId;
538     jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
539     List<Vector<uint8_t> >::iterator iter = list.begin();
540     while (iter != list.end()) {
541         jbyteArray byteArray = VectorToJByteArray(env, *iter);
542         env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
543         env->DeleteLocalRef(byteArray);
544         iter++;
545     }
546 
547     return arrayList;
548 }
549 
550 }  // namespace android
551 
552 using namespace android;
553 
setDrm(JNIEnv * env,jobject thiz,const sp<JDrm> & drm)554 static sp<JDrm> setDrm(
555         JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
556     sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
557     if (drm != NULL) {
558         drm->incStrong(thiz);
559     }
560     if (old != NULL) {
561         old->decStrong(thiz);
562     }
563     env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
564 
565     return old;
566 }
567 
CheckSession(JNIEnv * env,const sp<IDrm> & drm,jbyteArray const & jsessionId)568 static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
569 {
570     if (drm == NULL) {
571         jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
572         return false;
573     }
574 
575     if (jsessionId == NULL) {
576         jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
577         return false;
578     }
579     return true;
580 }
581 
android_media_MediaDrm_release(JNIEnv * env,jobject thiz)582 static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
583     sp<JDrm> drm = setDrm(env, thiz, NULL);
584     if (drm != NULL) {
585         drm->setListener(NULL);
586         drm->disconnect();
587     }
588 }
589 
android_media_MediaDrm_native_init(JNIEnv * env)590 static void android_media_MediaDrm_native_init(JNIEnv *env) {
591     jclass clazz;
592     FIND_CLASS(clazz, "android/media/MediaDrm");
593     GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
594     GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
595                          "(Ljava/lang/Object;IIILjava/lang/Object;)V");
596 
597     jfieldID field;
598     GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
599     gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
600     GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
601     gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
602     GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
603     gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
604     GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
605     gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
606     GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
607     gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
608 
609     GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
610     gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
611     GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
612     gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
613     GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
614     gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
615 
616     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
617     gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
618     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
619     gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
620     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
621     gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
622 
623     GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
624     gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
625     GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
626     gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
627 
628     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
629     GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
630     GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
631     GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
632 
633     GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
634     gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
635     GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
636     gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
637     GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
638     gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
639 
640     FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
641     GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
642     GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
643 
644     FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
645     GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
646     GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
647     gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
648 
649     FIND_CLASS(clazz, "java/util/ArrayList");
650     GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
651     GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
652 
653     FIND_CLASS(clazz, "java/util/HashMap");
654     GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
655     GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
656     GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
657                   "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
658     GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
659 
660     FIND_CLASS(clazz, "java/util/Set");
661     GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
662 
663     FIND_CLASS(clazz, "java/util/Iterator");
664     GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
665     GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
666 
667     FIND_CLASS(clazz, "java/util/Map$Entry");
668     GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
669     GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
670 
671     FIND_CLASS(clazz, "java/util/HashMap");
672     gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
673 
674     FIND_CLASS(clazz, "java/lang/String");
675     gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
676 
677     FIND_CLASS(clazz, "java/util/ArrayList");
678     gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
679 
680     FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
681     GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
682     gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
683 }
684 
android_media_MediaDrm_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jbyteArray uuidObj,jstring jappPackageName)685 static void android_media_MediaDrm_native_setup(
686         JNIEnv *env, jobject thiz,
687         jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
688 
689     if (uuidObj == NULL) {
690         jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
691         return;
692     }
693 
694     Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
695 
696     if (uuid.size() != 16) {
697         jniThrowException(env, "java/lang/IllegalArgumentException",
698                           "invalid UUID size, expected 16 bytes");
699         return;
700     }
701 
702     String8 packageName;
703     if (jappPackageName == NULL) {
704         jniThrowException(env, "java/lang/IllegalArgumentException",
705                           "application package name cannot be null");
706         return;
707     }
708 
709     packageName = JStringToString8(env, jappPackageName);
710     sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
711 
712     status_t err = drm->initCheck();
713 
714     if (err != OK) {
715         jniThrowException(
716                 env,
717                 "android/media/UnsupportedSchemeException",
718                 "Failed to instantiate drm object.");
719         return;
720     }
721 
722     sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
723     drm->setListener(listener);
724     setDrm(env, thiz, drm);
725 }
726 
android_media_MediaDrm_native_finalize(JNIEnv * env,jobject thiz)727 static void android_media_MediaDrm_native_finalize(
728         JNIEnv *env, jobject thiz) {
729     android_media_MediaDrm_release(env, thiz);
730 }
731 
android_media_MediaDrm_isCryptoSchemeSupportedNative(JNIEnv * env,jobject,jbyteArray uuidObj,jstring jmimeType)732 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
733     JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
734 
735     if (uuidObj == NULL) {
736         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
737         return false;
738     }
739 
740     Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
741 
742     if (uuid.size() != 16) {
743         jniThrowException(
744                 env,
745                 "java/lang/IllegalArgumentException",
746                 "invalid UUID size, expected 16 bytes");
747         return false;
748     }
749 
750     String8 mimeType;
751     if (jmimeType != NULL) {
752         mimeType = JStringToString8(env, jmimeType);
753     }
754 
755     return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
756 }
757 
android_media_MediaDrm_openSession(JNIEnv * env,jobject thiz)758 static jbyteArray android_media_MediaDrm_openSession(
759     JNIEnv *env, jobject thiz) {
760     sp<IDrm> drm = GetDrm(env, thiz);
761 
762     if (drm == NULL) {
763         jniThrowException(env, "java/lang/IllegalStateException",
764                           "MediaDrm obj is null");
765         return NULL;
766     }
767 
768     Vector<uint8_t> sessionId;
769     status_t err = drm->openSession(sessionId);
770 
771     if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
772         return NULL;
773     }
774 
775     return VectorToJByteArray(env, sessionId);
776 }
777 
android_media_MediaDrm_closeSession(JNIEnv * env,jobject thiz,jbyteArray jsessionId)778 static void android_media_MediaDrm_closeSession(
779     JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
780     sp<IDrm> drm = GetDrm(env, thiz);
781 
782     if (!CheckSession(env, drm, jsessionId)) {
783         return;
784     }
785 
786     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
787 
788     status_t err = drm->closeSession(sessionId);
789 
790     throwExceptionAsNecessary(env, err, "Failed to close session");
791 }
792 
android_media_MediaDrm_getKeyRequest(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jinitData,jstring jmimeType,jint jkeyType,jobject joptParams)793 static jobject android_media_MediaDrm_getKeyRequest(
794     JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
795     jstring jmimeType, jint jkeyType, jobject joptParams) {
796     sp<IDrm> drm = GetDrm(env, thiz);
797 
798     if (!CheckSession(env, drm, jsessionId)) {
799         return NULL;
800     }
801 
802     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
803 
804     Vector<uint8_t> initData;
805     if (jinitData != NULL) {
806         initData = JByteArrayToVector(env, jinitData);
807     }
808 
809     String8 mimeType;
810     if (jmimeType != NULL) {
811         mimeType = JStringToString8(env, jmimeType);
812     }
813 
814     DrmPlugin::KeyType keyType;
815     if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
816         keyType = DrmPlugin::kKeyType_Streaming;
817     } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
818         keyType = DrmPlugin::kKeyType_Offline;
819     } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
820         keyType = DrmPlugin::kKeyType_Release;
821     } else {
822         jniThrowException(env, "java/lang/IllegalArgumentException",
823                           "invalid keyType");
824         return NULL;
825     }
826 
827     KeyedVector<String8, String8> optParams;
828     if (joptParams != NULL) {
829         bool isOK;
830         optParams = HashMapToKeyedVector(env, joptParams, &isOK);
831         if (!isOK) {
832             return NULL;
833         }
834     }
835 
836     Vector<uint8_t> request;
837     String8 defaultUrl;
838     DrmPlugin::KeyRequestType keyRequestType;
839 
840     status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
841             keyType, optParams, request, defaultUrl, &keyRequestType);
842 
843     if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
844         return NULL;
845     }
846 
847     // Fill out return obj
848     jclass clazz;
849     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
850 
851     jobject keyObj = NULL;
852 
853     if (clazz) {
854         keyObj = env->AllocObject(clazz);
855         jbyteArray jrequest = VectorToJByteArray(env, request);
856         env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
857 
858         jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
859         env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
860 
861         switch (keyRequestType) {
862             case DrmPlugin::kKeyRequestType_Initial:
863                 env->SetIntField(keyObj, gFields.keyRequest.requestType,
864                         gKeyRequestTypes.kKeyRequestTypeInitial);
865                 break;
866             case DrmPlugin::kKeyRequestType_Renewal:
867                 env->SetIntField(keyObj, gFields.keyRequest.requestType,
868                         gKeyRequestTypes.kKeyRequestTypeRenewal);
869                 break;
870             case DrmPlugin::kKeyRequestType_Release:
871                 env->SetIntField(keyObj, gFields.keyRequest.requestType,
872                         gKeyRequestTypes.kKeyRequestTypeRelease);
873                 break;
874             default:
875                 throwStateException(env, "DRM plugin failure: unknown key request type",
876                         ERROR_DRM_UNKNOWN);
877                 break;
878         }
879     }
880 
881     return keyObj;
882 }
883 
android_media_MediaDrm_provideKeyResponse(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jresponse)884 static jbyteArray android_media_MediaDrm_provideKeyResponse(
885     JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
886     sp<IDrm> drm = GetDrm(env, thiz);
887 
888     if (!CheckSession(env, drm, jsessionId)) {
889         return NULL;
890     }
891 
892     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
893 
894     if (jresponse == NULL) {
895         jniThrowException(env, "java/lang/IllegalArgumentException",
896                           "key response is null");
897         return NULL;
898     }
899     Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
900     Vector<uint8_t> keySetId;
901 
902     status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
903 
904     if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
905         return NULL;
906     }
907     return VectorToJByteArray(env, keySetId);
908 }
909 
android_media_MediaDrm_removeKeys(JNIEnv * env,jobject thiz,jbyteArray jkeysetId)910 static void android_media_MediaDrm_removeKeys(
911     JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
912     sp<IDrm> drm = GetDrm(env, thiz);
913 
914     if (jkeysetId == NULL) {
915         jniThrowException(env, "java/lang/IllegalArgumentException",
916                           "keySetId is null");
917         return;
918     }
919 
920     Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
921 
922     status_t err = drm->removeKeys(keySetId);
923 
924     throwExceptionAsNecessary(env, err, "Failed to remove keys");
925 }
926 
android_media_MediaDrm_restoreKeys(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jkeysetId)927 static void android_media_MediaDrm_restoreKeys(
928     JNIEnv *env, jobject thiz, jbyteArray jsessionId,
929     jbyteArray jkeysetId) {
930 
931     sp<IDrm> drm = GetDrm(env, thiz);
932 
933     if (!CheckSession(env, drm, jsessionId)) {
934         return;
935     }
936 
937     if (jkeysetId == NULL) {
938         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
939         return;
940     }
941 
942     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
943     Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
944 
945     status_t err = drm->restoreKeys(sessionId, keySetId);
946 
947     throwExceptionAsNecessary(env, err, "Failed to restore keys");
948 }
949 
android_media_MediaDrm_queryKeyStatus(JNIEnv * env,jobject thiz,jbyteArray jsessionId)950 static jobject android_media_MediaDrm_queryKeyStatus(
951     JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
952     sp<IDrm> drm = GetDrm(env, thiz);
953 
954     if (!CheckSession(env, drm, jsessionId)) {
955         return NULL;
956     }
957     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
958 
959     KeyedVector<String8, String8> infoMap;
960 
961     status_t err = drm->queryKeyStatus(sessionId, infoMap);
962 
963     if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
964         return NULL;
965     }
966 
967     return KeyedVectorToHashMap(env, infoMap);
968 }
969 
android_media_MediaDrm_getProvisionRequestNative(JNIEnv * env,jobject thiz,jint jcertType,jstring jcertAuthority)970 static jobject android_media_MediaDrm_getProvisionRequestNative(
971     JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
972     sp<IDrm> drm = GetDrm(env, thiz);
973 
974     if (drm == NULL) {
975         jniThrowException(env, "java/lang/IllegalStateException",
976                           "MediaDrm obj is null");
977         return NULL;
978     }
979 
980     Vector<uint8_t> request;
981     String8 defaultUrl;
982 
983     String8 certType;
984     if (jcertType == gCertificateTypes.kCertificateTypeX509) {
985         certType = "X.509";
986     } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
987         certType = "none";
988     } else {
989         certType = "invalid";
990     }
991 
992     String8 certAuthority = JStringToString8(env, jcertAuthority);
993     status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
994 
995     if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
996         return NULL;
997     }
998 
999     // Fill out return obj
1000     jclass clazz;
1001     FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1002 
1003     jobject provisionObj = NULL;
1004 
1005     if (clazz) {
1006         provisionObj = env->AllocObject(clazz);
1007         jbyteArray jrequest = VectorToJByteArray(env, request);
1008         env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1009 
1010         jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1011         env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1012     }
1013 
1014     return provisionObj;
1015 }
1016 
android_media_MediaDrm_provideProvisionResponseNative(JNIEnv * env,jobject thiz,jbyteArray jresponse)1017 static jobject android_media_MediaDrm_provideProvisionResponseNative(
1018     JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1019     sp<IDrm> drm = GetDrm(env, thiz);
1020 
1021     if (drm == NULL) {
1022         jniThrowException(env, "java/lang/IllegalStateException",
1023                           "MediaDrm obj is null");
1024         return NULL;
1025     }
1026 
1027     if (jresponse == NULL) {
1028         jniThrowException(env, "java/lang/IllegalArgumentException",
1029                           "provision response is null");
1030         return NULL;
1031     }
1032 
1033     Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
1034     Vector<uint8_t> certificate, wrappedKey;
1035 
1036     status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1037 
1038     // Fill out return obj
1039     jclass clazz = gFields.certificateClassId;
1040 
1041     jobject certificateObj = NULL;
1042 
1043     if (clazz && certificate.size() && wrappedKey.size()) {
1044         certificateObj = env->AllocObject(clazz);
1045         jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1046         env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1047 
1048         jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1049         env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1050     }
1051 
1052     throwExceptionAsNecessary(env, err, "Failed to handle provision response");
1053     return certificateObj;
1054 }
1055 
android_media_MediaDrm_getSecureStops(JNIEnv * env,jobject thiz)1056 static jobject android_media_MediaDrm_getSecureStops(
1057     JNIEnv *env, jobject thiz) {
1058     sp<IDrm> drm = GetDrm(env, thiz);
1059 
1060     if (drm == NULL) {
1061         jniThrowException(env, "java/lang/IllegalStateException",
1062                           "MediaDrm obj is null");
1063         return NULL;
1064     }
1065 
1066     List<Vector<uint8_t> > secureStops;
1067 
1068     status_t err = drm->getSecureStops(secureStops);
1069 
1070     if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1071         return NULL;
1072     }
1073 
1074     return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1075 }
1076 
android_media_MediaDrm_getSecureStop(JNIEnv * env,jobject thiz,jbyteArray ssid)1077 static jbyteArray android_media_MediaDrm_getSecureStop(
1078     JNIEnv *env, jobject thiz, jbyteArray ssid) {
1079     sp<IDrm> drm = GetDrm(env, thiz);
1080 
1081     if (drm == NULL) {
1082         jniThrowException(env, "java/lang/IllegalStateException",
1083                           "MediaDrm obj is null");
1084         return NULL;
1085     }
1086 
1087     Vector<uint8_t> secureStop;
1088 
1089     status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1090 
1091     if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1092         return NULL;
1093     }
1094 
1095     return VectorToJByteArray(env, secureStop);
1096 }
1097 
android_media_MediaDrm_releaseSecureStops(JNIEnv * env,jobject thiz,jbyteArray jssRelease)1098 static void android_media_MediaDrm_releaseSecureStops(
1099     JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1100     sp<IDrm> drm = GetDrm(env, thiz);
1101 
1102     if (drm == NULL) {
1103         jniThrowException(env, "java/lang/IllegalStateException",
1104                           "MediaDrm obj is null");
1105         return;
1106     }
1107 
1108     Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1109 
1110     status_t err = drm->releaseSecureStops(ssRelease);
1111 
1112     throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1113 }
1114 
android_media_MediaDrm_releaseAllSecureStops(JNIEnv * env,jobject thiz)1115 static void android_media_MediaDrm_releaseAllSecureStops(
1116     JNIEnv *env, jobject thiz) {
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     status_t err = drm->releaseAllSecureStops();
1126 
1127     throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
1128 }
1129 
android_media_MediaDrm_getPropertyString(JNIEnv * env,jobject thiz,jstring jname)1130 static jstring android_media_MediaDrm_getPropertyString(
1131     JNIEnv *env, jobject thiz, jstring jname) {
1132     sp<IDrm> drm = GetDrm(env, thiz);
1133 
1134     if (drm == NULL) {
1135         jniThrowException(env, "java/lang/IllegalStateException",
1136                           "MediaDrm obj is null");
1137         return NULL;
1138     }
1139 
1140     if (jname == NULL) {
1141         jniThrowException(env, "java/lang/IllegalArgumentException",
1142                           "property name String is null");
1143         return NULL;
1144     }
1145 
1146     String8 name = JStringToString8(env, jname);
1147     String8 value;
1148 
1149     status_t err = drm->getPropertyString(name, value);
1150 
1151     if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1152         return NULL;
1153     }
1154 
1155     return env->NewStringUTF(value.string());
1156 }
1157 
android_media_MediaDrm_getPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname)1158 static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1159     JNIEnv *env, jobject thiz, jstring jname) {
1160     sp<IDrm> drm = GetDrm(env, thiz);
1161 
1162     if (drm == NULL) {
1163         jniThrowException(env, "java/lang/IllegalStateException",
1164                           "MediaDrm obj is null");
1165         return NULL;
1166     }
1167 
1168     if (jname == NULL) {
1169         jniThrowException(env, "java/lang/IllegalArgumentException",
1170                           "property name String is null");
1171         return NULL;
1172     }
1173 
1174     String8 name = JStringToString8(env, jname);
1175     Vector<uint8_t> value;
1176 
1177     status_t err = drm->getPropertyByteArray(name, value);
1178 
1179     if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1180         return NULL;
1181     }
1182 
1183     return VectorToJByteArray(env, value);
1184 }
1185 
android_media_MediaDrm_setPropertyString(JNIEnv * env,jobject thiz,jstring jname,jstring jvalue)1186 static void android_media_MediaDrm_setPropertyString(
1187     JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1188     sp<IDrm> drm = GetDrm(env, thiz);
1189 
1190     if (drm == NULL) {
1191         jniThrowException(env, "java/lang/IllegalStateException",
1192                           "MediaDrm obj is null");
1193         return;
1194     }
1195 
1196     if (jname == NULL) {
1197         jniThrowException(env, "java/lang/IllegalArgumentException",
1198                           "property name String is null");
1199         return;
1200     }
1201 
1202     if (jvalue == NULL) {
1203         jniThrowException(env, "java/lang/IllegalArgumentException",
1204                           "property value String is null");
1205         return;
1206     }
1207 
1208     String8 name = JStringToString8(env, jname);
1209     String8 value = JStringToString8(env, jvalue);
1210 
1211     status_t err = drm->setPropertyString(name, value);
1212 
1213     throwExceptionAsNecessary(env, err, "Failed to set property");
1214 }
1215 
android_media_MediaDrm_setPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname,jbyteArray jvalue)1216 static void android_media_MediaDrm_setPropertyByteArray(
1217     JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1218     sp<IDrm> drm = GetDrm(env, thiz);
1219 
1220     if (drm == NULL) {
1221         jniThrowException(env, "java/lang/IllegalStateException",
1222                           "MediaDrm obj is null");
1223         return;
1224     }
1225 
1226     if (jname == NULL) {
1227         jniThrowException(env, "java/lang/IllegalArgumentException",
1228                           "property name String is null");
1229         return;
1230     }
1231 
1232     if (jvalue == NULL) {
1233         jniThrowException(env, "java/lang/IllegalArgumentException",
1234                           "property value byte array is null");
1235         return;
1236     }
1237 
1238     String8 name = JStringToString8(env, jname);
1239     Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1240 
1241     status_t err = drm->setPropertyByteArray(name, value);
1242 
1243     throwExceptionAsNecessary(env, err, "Failed to set property");
1244 }
1245 
android_media_MediaDrm_setCipherAlgorithmNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1246 static void android_media_MediaDrm_setCipherAlgorithmNative(
1247     JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1248     jstring jalgorithm) {
1249 
1250     sp<IDrm> drm = GetDrm(env, jdrm);
1251 
1252     if (!CheckSession(env, drm, jsessionId)) {
1253         return;
1254     }
1255 
1256     if (jalgorithm == NULL) {
1257         jniThrowException(env, "java/lang/IllegalArgumentException",
1258                           "algorithm String is null");
1259         return;
1260     }
1261 
1262     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1263     String8 algorithm = JStringToString8(env, jalgorithm);
1264 
1265     status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1266 
1267     throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1268 }
1269 
android_media_MediaDrm_setMacAlgorithmNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1270 static void android_media_MediaDrm_setMacAlgorithmNative(
1271     JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1272     jstring jalgorithm) {
1273 
1274     sp<IDrm> drm = GetDrm(env, jdrm);
1275 
1276     if (!CheckSession(env, drm, jsessionId)) {
1277         return;
1278     }
1279 
1280     if (jalgorithm == NULL) {
1281         jniThrowException(env, "java/lang/IllegalArgumentException",
1282                           "algorithm String is null");
1283         return;
1284     }
1285 
1286     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1287     String8 algorithm = JStringToString8(env, jalgorithm);
1288 
1289     status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1290 
1291     throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1292 }
1293 
1294 
android_media_MediaDrm_encryptNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1295 static jbyteArray android_media_MediaDrm_encryptNative(
1296     JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1297     jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1298 
1299     sp<IDrm> drm = GetDrm(env, jdrm);
1300 
1301     if (!CheckSession(env, drm, jsessionId)) {
1302         return NULL;
1303     }
1304 
1305     if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1306         jniThrowException(env, "java/lang/IllegalArgumentException",
1307                           "required argument is null");
1308         return NULL;
1309     }
1310 
1311     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1312     Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1313     Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1314     Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1315     Vector<uint8_t> output;
1316 
1317     status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1318 
1319     if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1320         return NULL;
1321     }
1322 
1323     return VectorToJByteArray(env, output);
1324 }
1325 
android_media_MediaDrm_decryptNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1326 static jbyteArray android_media_MediaDrm_decryptNative(
1327     JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1328     jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1329 
1330     sp<IDrm> drm = GetDrm(env, jdrm);
1331 
1332     if (!CheckSession(env, drm, jsessionId)) {
1333         return NULL;
1334     }
1335 
1336     if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1337         jniThrowException(env, "java/lang/IllegalArgumentException",
1338                           "required argument is null");
1339         return NULL;
1340     }
1341 
1342     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1343     Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1344     Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1345     Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1346     Vector<uint8_t> output;
1347 
1348     status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1349     if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1350         return NULL;
1351     }
1352 
1353     return VectorToJByteArray(env, output);
1354 }
1355 
android_media_MediaDrm_signNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage)1356 static jbyteArray android_media_MediaDrm_signNative(
1357     JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1358     jbyteArray jkeyId, jbyteArray jmessage) {
1359 
1360     sp<IDrm> drm = GetDrm(env, jdrm);
1361 
1362     if (!CheckSession(env, drm, jsessionId)) {
1363         return NULL;
1364     }
1365 
1366     if (jkeyId == NULL || jmessage == NULL) {
1367         jniThrowException(env, "java/lang/IllegalArgumentException",
1368                           "required argument is null");
1369         return NULL;
1370     }
1371 
1372     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1373     Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1374     Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1375     Vector<uint8_t> signature;
1376 
1377     status_t err = drm->sign(sessionId, keyId, message, signature);
1378 
1379     if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1380         return NULL;
1381     }
1382 
1383     return VectorToJByteArray(env, signature);
1384 }
1385 
android_media_MediaDrm_verifyNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage,jbyteArray jsignature)1386 static jboolean android_media_MediaDrm_verifyNative(
1387     JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1388     jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1389 
1390     sp<IDrm> drm = GetDrm(env, jdrm);
1391 
1392     if (!CheckSession(env, drm, jsessionId)) {
1393         return false;
1394     }
1395 
1396     if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
1397         jniThrowException(env, "java/lang/IllegalArgumentException",
1398                           "required argument is null");
1399         return false;
1400     }
1401 
1402     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1403     Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1404     Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1405     Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1406     bool match;
1407 
1408     status_t err = drm->verify(sessionId, keyId, message, signature, match);
1409 
1410     throwExceptionAsNecessary(env, err, "Failed to verify");
1411     return match;
1412 }
1413 
1414 
android_media_MediaDrm_signRSANative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm,jbyteArray jwrappedKey,jbyteArray jmessage)1415 static jbyteArray android_media_MediaDrm_signRSANative(
1416     JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1417     jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1418 
1419     sp<IDrm> drm = GetDrm(env, jdrm);
1420 
1421     if (!CheckSession(env, drm, jsessionId)) {
1422         return NULL;
1423     }
1424 
1425     if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1426         jniThrowException(env, "java/lang/IllegalArgumentException",
1427                           "required argument is null");
1428         return NULL;
1429     }
1430 
1431     Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1432     String8 algorithm = JStringToString8(env, jalgorithm);
1433     Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1434     Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1435     Vector<uint8_t> signature;
1436 
1437     status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1438 
1439     if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1440         return NULL;
1441     }
1442 
1443     return VectorToJByteArray(env, signature);
1444 }
1445 
1446 
1447 static const JNINativeMethod gMethods[] = {
1448     { "release", "()V", (void *)android_media_MediaDrm_release },
1449     { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1450 
1451     { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
1452       (void *)android_media_MediaDrm_native_setup },
1453 
1454     { "native_finalize", "()V",
1455       (void *)android_media_MediaDrm_native_finalize },
1456 
1457     { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
1458       (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1459 
1460     { "openSession", "()[B",
1461       (void *)android_media_MediaDrm_openSession },
1462 
1463     { "closeSession", "([B)V",
1464       (void *)android_media_MediaDrm_closeSession },
1465 
1466     { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1467       "Landroid/media/MediaDrm$KeyRequest;",
1468       (void *)android_media_MediaDrm_getKeyRequest },
1469 
1470     { "provideKeyResponse", "([B[B)[B",
1471       (void *)android_media_MediaDrm_provideKeyResponse },
1472 
1473     { "removeKeys", "([B)V",
1474       (void *)android_media_MediaDrm_removeKeys },
1475 
1476     { "restoreKeys", "([B[B)V",
1477       (void *)android_media_MediaDrm_restoreKeys },
1478 
1479     { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1480       (void *)android_media_MediaDrm_queryKeyStatus },
1481 
1482     { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1483       (void *)android_media_MediaDrm_getProvisionRequestNative },
1484 
1485     { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1486       (void *)android_media_MediaDrm_provideProvisionResponseNative },
1487 
1488     { "getSecureStops", "()Ljava/util/List;",
1489       (void *)android_media_MediaDrm_getSecureStops },
1490 
1491     { "getSecureStop", "([B)[B",
1492       (void *)android_media_MediaDrm_getSecureStop },
1493 
1494     { "releaseSecureStops", "([B)V",
1495       (void *)android_media_MediaDrm_releaseSecureStops },
1496 
1497     { "releaseAllSecureStops", "()V",
1498       (void *)android_media_MediaDrm_releaseAllSecureStops },
1499 
1500     { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1501       (void *)android_media_MediaDrm_getPropertyString },
1502 
1503     { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1504       (void *)android_media_MediaDrm_getPropertyByteArray },
1505 
1506     { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1507       (void *)android_media_MediaDrm_setPropertyString },
1508 
1509     { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1510       (void *)android_media_MediaDrm_setPropertyByteArray },
1511 
1512     { "setCipherAlgorithmNative",
1513       "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1514       (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1515 
1516     { "setMacAlgorithmNative",
1517       "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1518       (void *)android_media_MediaDrm_setMacAlgorithmNative },
1519 
1520     { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1521       (void *)android_media_MediaDrm_encryptNative },
1522 
1523     { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1524       (void *)android_media_MediaDrm_decryptNative },
1525 
1526     { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1527       (void *)android_media_MediaDrm_signNative },
1528 
1529     { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1530       (void *)android_media_MediaDrm_verifyNative },
1531 
1532     { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1533       (void *)android_media_MediaDrm_signRSANative },
1534 };
1535 
register_android_media_Drm(JNIEnv * env)1536 int register_android_media_Drm(JNIEnv *env) {
1537     return AndroidRuntime::registerNativeMethods(env,
1538                 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1539 }
1540