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