blob: 3d7784d6303d4a342bbceeb4be0e323dc99f203b [file] [log] [blame]
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001/*
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"
Jeff Tinker54cfbd62013-04-02 13:14:59 -070024#include "android_os_Parcel.h"
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080025#include "jni.h"
26#include "JNIHelp.h"
27
28#include <binder/IServiceManager.h>
Jeff Tinker54cfbd62013-04-02 13:14:59 -070029#include <binder/Parcel.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080030#include <media/IDrm.h>
31#include <media/IMediaPlayerService.h>
32#include <media/stagefright/foundation/ADebug.h>
Jeff Tinkerf7568b52013-04-17 14:24:40 -070033#include <media/stagefright/MediaErrors.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080034
35namespace android {
36
37#define FIND_CLASS(var, className) \
38 var = env->FindClass(className); \
39 LOG_FATAL_IF(! var, "Unable to find class " className);
40
41#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
42 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
43 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
44
45#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
46 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
47 LOG_FATAL_IF(! var, "Unable to find method " fieldName);
48
Jeff Tinker54cfbd62013-04-02 13:14:59 -070049#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
50 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
51 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
52
53#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
54 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
55 LOG_FATAL_IF(! var, "Unable to find static method " fieldName);
56
57
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080058struct RequestFields {
59 jfieldID data;
60 jfieldID defaultUrl;
61};
62
63struct ArrayListFields {
64 jmethodID init;
65 jmethodID add;
66};
67
68struct HashmapFields {
69 jmethodID init;
70 jmethodID get;
71 jmethodID put;
72 jmethodID entrySet;
73};
74
75struct SetFields {
76 jmethodID iterator;
77};
78
79struct IteratorFields {
80 jmethodID next;
81 jmethodID hasNext;
82};
83
84struct EntryFields {
85 jmethodID getKey;
86 jmethodID getValue;
87};
88
Jeff Tinker54cfbd62013-04-02 13:14:59 -070089struct EventTypes {
90 int kEventProvisionRequired;
91 int kEventKeyRequired;
92 int kEventKeyExpired;
93 int kEventVendorDefined;
94} gEventTypes;
95
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080096struct fields_t {
97 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -070098 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -070099 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800100 RequestFields provisionRequest;
101 ArrayListFields arraylist;
102 HashmapFields hashmap;
103 SetFields set;
104 IteratorFields iterator;
105 EntryFields entry;
106};
107
108static fields_t gFields;
109
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700110// ----------------------------------------------------------------------------
111// ref-counted object for callbacks
112class JNIDrmListener: public DrmListener
113{
114public:
115 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
116 ~JNIDrmListener();
117 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
118private:
119 JNIDrmListener();
120 jclass mClass; // Reference to MediaDrm class
121 jobject mObject; // Weak ref to MediaDrm Java object to call on
122};
123
124JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
125{
126 // Hold onto the MediaDrm class for use in calling the static method
127 // that posts events to the application thread.
128 jclass clazz = env->GetObjectClass(thiz);
129 if (clazz == NULL) {
130 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700131 jniThrowException(env, "java/lang/Exception",
132 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700133 return;
134 }
135 mClass = (jclass)env->NewGlobalRef(clazz);
136
137 // We use a weak reference so the MediaDrm object can be garbage collected.
138 // The reference is only used as a proxy for callbacks.
139 mObject = env->NewGlobalRef(weak_thiz);
140}
141
142JNIDrmListener::~JNIDrmListener()
143{
144 // remove global references
145 JNIEnv *env = AndroidRuntime::getJNIEnv();
146 env->DeleteGlobalRef(mObject);
147 env->DeleteGlobalRef(mClass);
148}
149
150void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
151 const Parcel *obj)
152{
153 jint jeventType;
154
155 // translate DrmPlugin event types into their java equivalents
156 switch(eventType) {
157 case DrmPlugin::kDrmPluginEventProvisionRequired:
158 jeventType = gEventTypes.kEventProvisionRequired;
159 break;
160 case DrmPlugin::kDrmPluginEventKeyNeeded:
161 jeventType = gEventTypes.kEventKeyRequired;
162 break;
163 case DrmPlugin::kDrmPluginEventKeyExpired:
164 jeventType = gEventTypes.kEventKeyExpired;
165 break;
166 case DrmPlugin::kDrmPluginEventVendorDefined:
167 jeventType = gEventTypes.kEventVendorDefined;
168 break;
169 default:
170 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
171 return;
172 }
173
174 JNIEnv *env = AndroidRuntime::getJNIEnv();
175 if (obj && obj->dataSize() > 0) {
176 jobject jParcel = createJavaParcelObject(env);
177 if (jParcel != NULL) {
178 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
179 nativeParcel->setData(obj->data(), obj->dataSize());
180 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
181 jeventType, extra, jParcel);
182 }
183 }
184
185 if (env->ExceptionCheck()) {
186 ALOGW("An exception occurred while notifying an event.");
187 LOGW_EX(env);
188 env->ExceptionClear();
189 }
190}
191
192
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800193static bool throwExceptionAsNecessary(
194 JNIEnv *env, status_t err, const char *msg = NULL) {
195
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700196 const char *drmMessage = NULL;
197
198 switch(err) {
199 case ERROR_DRM_UNKNOWN:
200 drmMessage = "General DRM error";
201 break;
202 case ERROR_DRM_NO_LICENSE:
203 drmMessage = "No license";
204 break;
205 case ERROR_DRM_LICENSE_EXPIRED:
206 drmMessage = "License expired";
207 break;
208 case ERROR_DRM_SESSION_NOT_OPENED:
209 drmMessage = "Session not opened";
210 break;
211 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
212 drmMessage = "Not initialized";
213 break;
214 case ERROR_DRM_DECRYPT:
215 drmMessage = "Decrypt error";
216 break;
217 case ERROR_DRM_CANNOT_HANDLE:
218 drmMessage = "Unsupported scheme or data format";
219 break;
220 case ERROR_DRM_TAMPER_DETECTED:
221 drmMessage = "Invalid state";
222 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700223 default:
224 break;
225 }
226
227 String8 vendorMessage;
228 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
229 vendorMessage.format("DRM vendor-defined error: %d", err);
230 drmMessage = vendorMessage.string();
231 }
232
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800233 if (err == BAD_VALUE) {
234 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
235 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700236 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
237 jniThrowException(env, "android/media/NotProvisionedException", msg);
238 return true;
239 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
240 jniThrowException(env, "android/media/DeniedByServerException", msg);
241 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800242 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700243 String8 errbuf;
244 if (drmMessage != NULL) {
245 if (msg == NULL) {
246 msg = drmMessage;
247 } else {
248 errbuf.format("%s: %s", msg, drmMessage);
249 msg = errbuf.string();
250 }
251 }
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700252 ALOGE("Illegal state exception: %s", msg);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800253 jniThrowException(env, "java/lang/IllegalStateException", msg);
254 return true;
255 }
256 return false;
257}
258
259static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
260 JDrm *jdrm = (JDrm *)env->GetIntField(thiz, gFields.context);
261 return jdrm ? jdrm->getDrm() : NULL;
262}
263
264JDrm::JDrm(
265 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
266 mObject = env->NewWeakGlobalRef(thiz);
267 mDrm = MakeDrm(uuid);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700268 if (mDrm != NULL) {
269 mDrm->setListener(this);
270 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800271}
272
273JDrm::~JDrm() {
274 mDrm.clear();
275
276 JNIEnv *env = AndroidRuntime::getJNIEnv();
277
278 env->DeleteWeakGlobalRef(mObject);
279 mObject = NULL;
280}
281
282// static
283sp<IDrm> JDrm::MakeDrm() {
284 sp<IServiceManager> sm = defaultServiceManager();
285
286 sp<IBinder> binder =
287 sm->getService(String16("media.player"));
288
289 sp<IMediaPlayerService> service =
290 interface_cast<IMediaPlayerService>(binder);
291
292 if (service == NULL) {
293 return NULL;
294 }
295
296 sp<IDrm> drm = service->makeDrm();
297
298 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
299 return NULL;
300 }
301
302 return drm;
303}
304
305// static
306sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
307 sp<IDrm> drm = MakeDrm();
308
309 if (drm == NULL) {
310 return NULL;
311 }
312
313 status_t err = drm->createPlugin(uuid);
314
315 if (err != OK) {
316 return NULL;
317 }
318
319 return drm;
320}
321
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700322status_t JDrm::setListener(const sp<DrmListener>& listener) {
323 Mutex::Autolock lock(mLock);
324 mListener = listener;
325 return OK;
326}
327
328void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
329 sp<DrmListener> listener;
330 mLock.lock();
331 listener = mListener;
332 mLock.unlock();
333
334 if (listener != NULL) {
335 Mutex::Autolock lock(mNotifyLock);
336 listener->notify(eventType, extra, obj);
337 }
338}
339
340
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800341// static
342bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
343 sp<IDrm> drm = MakeDrm();
344
345 if (drm == NULL) {
346 return false;
347 }
348
349 return drm->isCryptoSchemeSupported(uuid);
350}
351
352status_t JDrm::initCheck() const {
353 return mDrm == NULL ? NO_INIT : OK;
354}
355
356// JNI conversion utilities
357static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
358 Vector<uint8_t> vector;
359 size_t length = env->GetArrayLength(byteArray);
360 vector.insertAt((size_t)0, length);
361 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
362 return vector;
363}
364
365static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
366 size_t length = vector.size();
367 jbyteArray result = env->NewByteArray(length);
368 if (result != NULL) {
369 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
370 }
371 return result;
372}
373
374static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800375 String8 result;
376
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700377 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800378 if (s) {
379 result = s;
380 env->ReleaseStringUTFChars(jstr, s);
381 }
382 return result;
383}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700384
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800385/*
386 import java.util.HashMap;
387 import java.util.Set;
388 import java.Map.Entry;
389 import jav.util.Iterator;
390
391 HashMap<k, v> hm;
392 Set<Entry<k, v> > s = hm.entrySet();
393 Iterator i = s.iterator();
394 Entry e = s.next();
395*/
396
397static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
398 jclass clazz;
399 FIND_CLASS(clazz, "java/lang/String");
400 KeyedVector<String8, String8> keyedVector;
401
402 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
403 if (entrySet) {
404 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
405 if (iterator) {
406 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
407 while (hasNext) {
408 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
409 if (entry) {
410 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
411 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700412 jniThrowException(env, "java/lang/IllegalArgumentException",
413 "HashMap key is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800414 }
415 jstring jkey = static_cast<jstring>(obj);
416
417 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
418 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700419 jniThrowException(env, "java/lang/IllegalArgumentException",
420 "HashMap value is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800421 }
422 jstring jvalue = static_cast<jstring>(obj);
423
424 String8 key = JStringToString8(env, jkey);
425 String8 value = JStringToString8(env, jvalue);
426 keyedVector.add(key, value);
427
428 env->DeleteLocalRef(jkey);
429 env->DeleteLocalRef(jvalue);
430 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
431 }
432 env->DeleteLocalRef(entry);
433 }
434 env->DeleteLocalRef(iterator);
435 }
436 env->DeleteLocalRef(entrySet);
437 }
438 return keyedVector;
439}
440
441static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
442 jclass clazz;
443 FIND_CLASS(clazz, "java/util/HashMap");
444 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
445 for (size_t i = 0; i < map.size(); ++i) {
446 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
447 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
448 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
449 env->DeleteLocalRef(jkey);
450 env->DeleteLocalRef(jvalue);
451 }
452 return hashMap;
453}
454
455static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
456 List<Vector<uint8_t> > list) {
457 jclass clazz;
458 FIND_CLASS(clazz, "java/util/ArrayList");
459 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
460 List<Vector<uint8_t> >::iterator iter = list.begin();
461 while (iter != list.end()) {
462 jbyteArray byteArray = VectorToJByteArray(env, *iter);
463 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
464 env->DeleteLocalRef(byteArray);
465 iter++;
466 }
467
468 return arrayList;
469}
470
471} // namespace android
472
473using namespace android;
474
475static sp<JDrm> setDrm(
476 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
477 sp<JDrm> old = (JDrm *)env->GetIntField(thiz, gFields.context);
478 if (drm != NULL) {
479 drm->incStrong(thiz);
480 }
481 if (old != NULL) {
482 old->decStrong(thiz);
483 }
484 env->SetIntField(thiz, gFields.context, (int)drm.get());
485
486 return old;
487}
488
489static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
490{
491 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700492 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800493 return false;
494 }
495
496 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700497 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800498 return false;
499 }
500 return true;
501}
502
503static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700504 sp<JDrm> drm = setDrm(env, thiz, NULL);
505 if (drm != NULL) {
506 drm->setListener(NULL);
507 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800508}
509
510static void android_media_MediaDrm_native_init(JNIEnv *env) {
511 jclass clazz;
512 FIND_CLASS(clazz, "android/media/MediaDrm");
513 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700514 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
515 "(Ljava/lang/Object;IILjava/lang/Object;)V");
516
517 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700518 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700519 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700520 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700521 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700522 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700523 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700524 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700525 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800526
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700527 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700528 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
529 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800530
531 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700532 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
533 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800534
535 FIND_CLASS(clazz, "java/util/ArrayList");
536 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
537 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
538
539 FIND_CLASS(clazz, "java/util/HashMap");
540 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
541 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
542 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
543 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
544 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
545
546 FIND_CLASS(clazz, "java/util/Set");
547 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
548
549 FIND_CLASS(clazz, "java/util/Iterator");
550 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
551 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
552
553 FIND_CLASS(clazz, "java/util/Map$Entry");
554 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
555 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
556}
557
558static void android_media_MediaDrm_native_setup(
559 JNIEnv *env, jobject thiz,
560 jobject weak_this, jbyteArray uuidObj) {
561
562 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700563 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800564 return;
565 }
566
567 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
568
569 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700570 jniThrowException(env, "java/lang/IllegalArgumentException",
571 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800572 return;
573 }
574
575 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
576
577 status_t err = drm->initCheck();
578
579 if (err != OK) {
580 jniThrowException(
581 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700582 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800583 "Failed to instantiate drm object.");
584 return;
585 }
586
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700587 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
588 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800589 setDrm(env, thiz, drm);
590}
591
592static void android_media_MediaDrm_native_finalize(
593 JNIEnv *env, jobject thiz) {
594 android_media_MediaDrm_release(env, thiz);
595}
596
597static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
598 JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
599
600 if (uuidObj == NULL) {
601 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
602 return false;
603 }
604
605 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
606
607 if (uuid.size() != 16) {
608 jniThrowException(
609 env,
610 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700611 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800612 return false;
613 }
614
615 return JDrm::IsCryptoSchemeSupported(uuid.array());
616}
617
618static jbyteArray android_media_MediaDrm_openSession(
619 JNIEnv *env, jobject thiz) {
620 sp<IDrm> drm = GetDrm(env, thiz);
621
622 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700623 jniThrowException(env, "java/lang/IllegalStateException",
624 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800625 return NULL;
626 }
627
628 Vector<uint8_t> sessionId;
629 status_t err = drm->openSession(sessionId);
630
631 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
632 return NULL;
633 }
634
635 return VectorToJByteArray(env, sessionId);
636}
637
638static void android_media_MediaDrm_closeSession(
639 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
640 sp<IDrm> drm = GetDrm(env, thiz);
641
642 if (!CheckSession(env, drm, jsessionId)) {
643 return;
644 }
645
646 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
647
648 status_t err = drm->closeSession(sessionId);
649
650 throwExceptionAsNecessary(env, err, "Failed to close session");
651}
652
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700653static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800654 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700655 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800656 sp<IDrm> drm = GetDrm(env, thiz);
657
658 if (!CheckSession(env, drm, jsessionId)) {
659 return NULL;
660 }
661
662 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
663
664 Vector<uint8_t> initData;
665 if (jinitData != NULL) {
666 initData = JByteArrayToVector(env, jinitData);
667 }
668
669 String8 mimeType;
670 if (jmimeType != NULL) {
671 mimeType = JStringToString8(env, jmimeType);
672 }
673
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700674 DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)jkeyType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800675
676 KeyedVector<String8, String8> optParams;
677 if (joptParams != NULL) {
678 optParams = HashMapToKeyedVector(env, joptParams);
679 }
680
681 Vector<uint8_t> request;
682 String8 defaultUrl;
683
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700684 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
685 keyType, optParams, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800686
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700687 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800688 return NULL;
689 }
690
691 // Fill out return obj
692 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700693 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800694
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700695 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800696
697 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700698 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800699 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700700 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800701
702 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700703 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800704 }
705
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700706 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800707}
708
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700709static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800710 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
711 sp<IDrm> drm = GetDrm(env, thiz);
712
713 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700714 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800715 }
716
717 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
718
719 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700720 jniThrowException(env, "java/lang/IllegalArgumentException",
721 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700722 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800723 }
724 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700725 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800726
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700727 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800728
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700729 throwExceptionAsNecessary(env, err, "Failed to handle key response");
730 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800731}
732
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700733static void android_media_MediaDrm_removeKeys(
734 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
735 sp<IDrm> drm = GetDrm(env, thiz);
736
737 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700738 jniThrowException(env, "java/lang/IllegalArgumentException",
739 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700740 return;
741 }
742
743 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
744
745 status_t err = drm->removeKeys(keySetId);
746
747 throwExceptionAsNecessary(env, err, "Failed to remove keys");
748}
749
750static void android_media_MediaDrm_restoreKeys(
751 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
752 jbyteArray jkeysetId) {
753
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800754 sp<IDrm> drm = GetDrm(env, thiz);
755
756 if (!CheckSession(env, drm, jsessionId)) {
757 return;
758 }
759
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700760 if (jkeysetId == NULL) {
761 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
762 return;
763 }
764
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800765 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700766 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800767
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700768 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800769
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700770 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800771}
772
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700773static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800774 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
775 sp<IDrm> drm = GetDrm(env, thiz);
776
777 if (!CheckSession(env, drm, jsessionId)) {
778 return NULL;
779 }
780 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
781
782 KeyedVector<String8, String8> infoMap;
783
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700784 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800785
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700786 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800787 return NULL;
788 }
789
790 return KeyedVectorToHashMap(env, infoMap);
791}
792
793static jobject android_media_MediaDrm_getProvisionRequest(
794 JNIEnv *env, jobject thiz) {
795 sp<IDrm> drm = GetDrm(env, thiz);
796
797 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700798 jniThrowException(env, "java/lang/IllegalStateException",
799 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800800 return NULL;
801 }
802
803 Vector<uint8_t> request;
804 String8 defaultUrl;
805
806 status_t err = drm->getProvisionRequest(request, defaultUrl);
807
808 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
809 return NULL;
810 }
811
812 // Fill out return obj
813 jclass clazz;
814 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
815
816 jobject provisionObj = NULL;
817
818 if (clazz) {
819 provisionObj = env->AllocObject(clazz);
820 jbyteArray jrequest = VectorToJByteArray(env, request);
821 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
822
823 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
824 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
825 }
826
827 return provisionObj;
828}
829
830static void android_media_MediaDrm_provideProvisionResponse(
831 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
832 sp<IDrm> drm = GetDrm(env, thiz);
833
834 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700835 jniThrowException(env, "java/lang/IllegalStateException",
836 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800837 return;
838 }
839
840 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700841 jniThrowException(env, "java/lang/IllegalArgumentException",
842 "provision response is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800843 return;
844 }
845
846 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
847
848 status_t err = drm->provideProvisionResponse(response);
849
850 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
851}
852
853static jobject android_media_MediaDrm_getSecureStops(
854 JNIEnv *env, jobject thiz) {
855 sp<IDrm> drm = GetDrm(env, thiz);
856
857 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700858 jniThrowException(env, "java/lang/IllegalStateException",
859 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800860 return NULL;
861 }
862
863 List<Vector<uint8_t> > secureStops;
864
865 status_t err = drm->getSecureStops(secureStops);
866
867 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
868 return NULL;
869 }
870
871 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
872}
873
874static void android_media_MediaDrm_releaseSecureStops(
875 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
876 sp<IDrm> drm = GetDrm(env, thiz);
877
878 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700879 jniThrowException(env, "java/lang/IllegalStateException",
880 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800881 return;
882 }
883
884 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
885
886 status_t err = drm->releaseSecureStops(ssRelease);
887
888 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
889}
890
891static jstring android_media_MediaDrm_getPropertyString(
892 JNIEnv *env, jobject thiz, jstring jname) {
893 sp<IDrm> drm = GetDrm(env, thiz);
894
895 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700896 jniThrowException(env, "java/lang/IllegalStateException",
897 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800898 return NULL;
899 }
900
901 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700902 jniThrowException(env, "java/lang/IllegalArgumentException",
903 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800904 return NULL;
905 }
906
907 String8 name = JStringToString8(env, jname);
908 String8 value;
909
910 status_t err = drm->getPropertyString(name, value);
911
912 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
913 return NULL;
914 }
915
916 return env->NewStringUTF(value.string());
917}
918
919static jbyteArray android_media_MediaDrm_getPropertyByteArray(
920 JNIEnv *env, jobject thiz, jstring jname) {
921 sp<IDrm> drm = GetDrm(env, thiz);
922
923 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700924 jniThrowException(env, "java/lang/IllegalStateException",
925 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800926 return NULL;
927 }
928
929 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700930 jniThrowException(env, "java/lang/IllegalArgumentException",
931 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800932 return NULL;
933 }
934
935 String8 name = JStringToString8(env, jname);
936 Vector<uint8_t> value;
937
938 status_t err = drm->getPropertyByteArray(name, value);
939
940 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
941 return NULL;
942 }
943
944 return VectorToJByteArray(env, value);
945}
946
947static void android_media_MediaDrm_setPropertyString(
948 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
949 sp<IDrm> drm = GetDrm(env, thiz);
950
951 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700952 jniThrowException(env, "java/lang/IllegalStateException",
953 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800954 return;
955 }
956
Jeff Tinkereada5372013-05-21 12:48:14 -0700957 if (jname == NULL) {
958 jniThrowException(env, "java/lang/IllegalArgumentException",
959 "property name String is null");
960 return;
961 }
962
963 if (jvalue == NULL) {
964 jniThrowException(env, "java/lang/IllegalArgumentException",
965 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800966 return;
967 }
968
969 String8 name = JStringToString8(env, jname);
970 String8 value = JStringToString8(env, jvalue);
971
972 status_t err = drm->setPropertyString(name, value);
973
974 throwExceptionAsNecessary(env, err, "Failed to set property");
975}
976
977static void android_media_MediaDrm_setPropertyByteArray(
978 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
979 sp<IDrm> drm = GetDrm(env, thiz);
980
981 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700982 jniThrowException(env, "java/lang/IllegalStateException",
983 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800984 return;
985 }
986
Jeff Tinkereada5372013-05-21 12:48:14 -0700987 if (jname == NULL) {
988 jniThrowException(env, "java/lang/IllegalArgumentException",
989 "property name String is null");
990 return;
991 }
992
993 if (jvalue == NULL) {
994 jniThrowException(env, "java/lang/IllegalArgumentException",
995 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800996 return;
997 }
998
999 String8 name = JStringToString8(env, jname);
1000 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1001
1002 status_t err = drm->setPropertyByteArray(name, value);
1003
1004 throwExceptionAsNecessary(env, err, "Failed to set property");
1005}
1006
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001007static void android_media_MediaDrm_setCipherAlgorithmNative(
1008 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1009 jstring jalgorithm) {
1010
1011 sp<IDrm> drm = GetDrm(env, jdrm);
1012
1013 if (!CheckSession(env, drm, jsessionId)) {
1014 return;
1015 }
1016
1017 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001018 jniThrowException(env, "java/lang/IllegalArgumentException",
1019 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001020 return;
1021 }
1022
1023 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1024 String8 algorithm = JStringToString8(env, jalgorithm);
1025
1026 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1027
1028 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1029}
1030
1031static void android_media_MediaDrm_setMacAlgorithmNative(
1032 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1033 jstring jalgorithm) {
1034
1035 sp<IDrm> drm = GetDrm(env, jdrm);
1036
1037 if (!CheckSession(env, drm, jsessionId)) {
1038 return;
1039 }
1040
1041 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001042 jniThrowException(env, "java/lang/IllegalArgumentException",
1043 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001044 return;
1045 }
1046
1047 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1048 String8 algorithm = JStringToString8(env, jalgorithm);
1049
1050 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1051
1052 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1053}
1054
1055
1056static jbyteArray android_media_MediaDrm_encryptNative(
1057 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1058 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1059
1060 sp<IDrm> drm = GetDrm(env, jdrm);
1061
1062 if (!CheckSession(env, drm, jsessionId)) {
1063 return NULL;
1064 }
1065
1066 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001067 jniThrowException(env, "java/lang/IllegalArgumentException",
1068 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001069 return NULL;
1070 }
1071
1072 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1073 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1074 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1075 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1076 Vector<uint8_t> output;
1077
1078 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1079
1080 throwExceptionAsNecessary(env, err, "Failed to encrypt");
1081
1082 return VectorToJByteArray(env, output);
1083}
1084
1085static jbyteArray android_media_MediaDrm_decryptNative(
1086 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1087 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1088
1089 sp<IDrm> drm = GetDrm(env, jdrm);
1090
1091 if (!CheckSession(env, drm, jsessionId)) {
1092 return NULL;
1093 }
1094
1095 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001096 jniThrowException(env, "java/lang/IllegalArgumentException",
1097 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001098 return NULL;
1099 }
1100
1101 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1102 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1103 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1104 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1105 Vector<uint8_t> output;
1106
1107 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1108 throwExceptionAsNecessary(env, err, "Failed to decrypt");
1109
1110 return VectorToJByteArray(env, output);
1111}
1112
1113static jbyteArray android_media_MediaDrm_signNative(
1114 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1115 jbyteArray jkeyId, jbyteArray jmessage) {
1116
1117 sp<IDrm> drm = GetDrm(env, jdrm);
1118
1119 if (!CheckSession(env, drm, jsessionId)) {
1120 return NULL;
1121 }
1122
1123 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001124 jniThrowException(env, "java/lang/IllegalArgumentException",
1125 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001126 return NULL;
1127 }
1128
1129 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1130 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1131 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1132 Vector<uint8_t> signature;
1133
1134 status_t err = drm->sign(sessionId, keyId, message, signature);
1135
1136 throwExceptionAsNecessary(env, err, "Failed to sign");
1137
1138 return VectorToJByteArray(env, signature);
1139}
1140
1141static jboolean android_media_MediaDrm_verifyNative(
1142 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1143 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1144
1145 sp<IDrm> drm = GetDrm(env, jdrm);
1146
1147 if (!CheckSession(env, drm, jsessionId)) {
1148 return false;
1149 }
1150
1151 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001152 jniThrowException(env, "java/lang/IllegalArgumentException",
1153 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001154 return false;
1155 }
1156
1157 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1158 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1159 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1160 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1161 bool match;
1162
1163 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1164
1165 throwExceptionAsNecessary(env, err, "Failed to verify");
1166 return match;
1167}
1168
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001169
1170static JNINativeMethod gMethods[] = {
1171 { "release", "()V", (void *)android_media_MediaDrm_release },
1172 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1173
1174 { "native_setup", "(Ljava/lang/Object;[B)V",
1175 (void *)android_media_MediaDrm_native_setup },
1176
1177 { "native_finalize", "()V",
1178 (void *)android_media_MediaDrm_native_finalize },
1179
1180 { "isCryptoSchemeSupportedNative", "([B)Z",
1181 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1182
1183 { "openSession", "()[B",
1184 (void *)android_media_MediaDrm_openSession },
1185
1186 { "closeSession", "([B)V",
1187 (void *)android_media_MediaDrm_closeSession },
1188
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001189 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1190 "Landroid/media/MediaDrm$KeyRequest;",
1191 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001192
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001193 { "provideKeyResponse", "([B[B)[B",
1194 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001195
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001196 { "removeKeys", "([B)V",
1197 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001198
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001199 { "restoreKeys", "([B[B)V",
1200 (void *)android_media_MediaDrm_restoreKeys },
1201
1202 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1203 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001204
1205 { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
1206 (void *)android_media_MediaDrm_getProvisionRequest },
1207
1208 { "provideProvisionResponse", "([B)V",
1209 (void *)android_media_MediaDrm_provideProvisionResponse },
1210
1211 { "getSecureStops", "()Ljava/util/List;",
1212 (void *)android_media_MediaDrm_getSecureStops },
1213
1214 { "releaseSecureStops", "([B)V",
1215 (void *)android_media_MediaDrm_releaseSecureStops },
1216
1217 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1218 (void *)android_media_MediaDrm_getPropertyString },
1219
1220 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1221 (void *)android_media_MediaDrm_getPropertyByteArray },
1222
1223 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1224 (void *)android_media_MediaDrm_setPropertyString },
1225
1226 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1227 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001228
1229 { "setCipherAlgorithmNative",
1230 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1231 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1232
1233 { "setMacAlgorithmNative",
1234 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1235 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1236
1237 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1238 (void *)android_media_MediaDrm_encryptNative },
1239
1240 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1241 (void *)android_media_MediaDrm_decryptNative },
1242
1243 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1244 (void *)android_media_MediaDrm_signNative },
1245
1246 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1247 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001248};
1249
1250int register_android_media_Drm(JNIEnv *env) {
1251 return AndroidRuntime::registerNativeMethods(env,
1252 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1253}
1254