blob: 16a1e48a8da2c4164b678ab148e5b5195b7bd6dd [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 {
Jeff Tinker17b89222013-05-21 12:35:06 -070090 jint kEventProvisionRequired;
91 jint kEventKeyRequired;
92 jint kEventKeyExpired;
93 jint kEventVendorDefined;
Jeff Tinker54cfbd62013-04-02 13:14:59 -070094} gEventTypes;
95
Jeff Tinker17b89222013-05-21 12:35:06 -070096struct KeyTypes {
97 jint kKeyTypeStreaming;
98 jint kKeyTypeOffline;
99 jint kKeyTypeRelease;
100} gKeyTypes;
101
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800102struct fields_t {
103 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700104 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700105 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800106 RequestFields provisionRequest;
107 ArrayListFields arraylist;
108 HashmapFields hashmap;
109 SetFields set;
110 IteratorFields iterator;
111 EntryFields entry;
112};
113
114static fields_t gFields;
115
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700116// ----------------------------------------------------------------------------
117// ref-counted object for callbacks
118class JNIDrmListener: public DrmListener
119{
120public:
121 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
122 ~JNIDrmListener();
123 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
124private:
125 JNIDrmListener();
126 jclass mClass; // Reference to MediaDrm class
127 jobject mObject; // Weak ref to MediaDrm Java object to call on
128};
129
130JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
131{
132 // Hold onto the MediaDrm class for use in calling the static method
133 // that posts events to the application thread.
134 jclass clazz = env->GetObjectClass(thiz);
135 if (clazz == NULL) {
136 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700137 jniThrowException(env, "java/lang/Exception",
138 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700139 return;
140 }
141 mClass = (jclass)env->NewGlobalRef(clazz);
142
143 // We use a weak reference so the MediaDrm object can be garbage collected.
144 // The reference is only used as a proxy for callbacks.
145 mObject = env->NewGlobalRef(weak_thiz);
146}
147
148JNIDrmListener::~JNIDrmListener()
149{
150 // remove global references
151 JNIEnv *env = AndroidRuntime::getJNIEnv();
152 env->DeleteGlobalRef(mObject);
153 env->DeleteGlobalRef(mClass);
154}
155
156void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
157 const Parcel *obj)
158{
159 jint jeventType;
160
161 // translate DrmPlugin event types into their java equivalents
162 switch(eventType) {
163 case DrmPlugin::kDrmPluginEventProvisionRequired:
164 jeventType = gEventTypes.kEventProvisionRequired;
165 break;
166 case DrmPlugin::kDrmPluginEventKeyNeeded:
167 jeventType = gEventTypes.kEventKeyRequired;
168 break;
169 case DrmPlugin::kDrmPluginEventKeyExpired:
170 jeventType = gEventTypes.kEventKeyExpired;
171 break;
172 case DrmPlugin::kDrmPluginEventVendorDefined:
173 jeventType = gEventTypes.kEventVendorDefined;
174 break;
175 default:
176 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
177 return;
178 }
179
180 JNIEnv *env = AndroidRuntime::getJNIEnv();
181 if (obj && obj->dataSize() > 0) {
182 jobject jParcel = createJavaParcelObject(env);
183 if (jParcel != NULL) {
184 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
185 nativeParcel->setData(obj->data(), obj->dataSize());
186 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
187 jeventType, extra, jParcel);
188 }
189 }
190
191 if (env->ExceptionCheck()) {
192 ALOGW("An exception occurred while notifying an event.");
193 LOGW_EX(env);
194 env->ExceptionClear();
195 }
196}
197
198
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800199static bool throwExceptionAsNecessary(
200 JNIEnv *env, status_t err, const char *msg = NULL) {
201
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700202 const char *drmMessage = NULL;
203
204 switch(err) {
205 case ERROR_DRM_UNKNOWN:
206 drmMessage = "General DRM error";
207 break;
208 case ERROR_DRM_NO_LICENSE:
209 drmMessage = "No license";
210 break;
211 case ERROR_DRM_LICENSE_EXPIRED:
212 drmMessage = "License expired";
213 break;
214 case ERROR_DRM_SESSION_NOT_OPENED:
215 drmMessage = "Session not opened";
216 break;
217 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
218 drmMessage = "Not initialized";
219 break;
220 case ERROR_DRM_DECRYPT:
221 drmMessage = "Decrypt error";
222 break;
223 case ERROR_DRM_CANNOT_HANDLE:
224 drmMessage = "Unsupported scheme or data format";
225 break;
226 case ERROR_DRM_TAMPER_DETECTED:
227 drmMessage = "Invalid state";
228 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700229 default:
230 break;
231 }
232
233 String8 vendorMessage;
234 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
235 vendorMessage.format("DRM vendor-defined error: %d", err);
236 drmMessage = vendorMessage.string();
237 }
238
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800239 if (err == BAD_VALUE) {
240 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
241 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700242 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
243 jniThrowException(env, "android/media/NotProvisionedException", msg);
244 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700245 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
246 jniThrowException(env, "android/media/ResourceBusyException", msg);
247 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700248 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
249 jniThrowException(env, "android/media/DeniedByServerException", msg);
250 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800251 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700252 String8 errbuf;
253 if (drmMessage != NULL) {
254 if (msg == NULL) {
255 msg = drmMessage;
256 } else {
257 errbuf.format("%s: %s", msg, drmMessage);
258 msg = errbuf.string();
259 }
260 }
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700261 ALOGE("Illegal state exception: %s", msg);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800262 jniThrowException(env, "java/lang/IllegalStateException", msg);
263 return true;
264 }
265 return false;
266}
267
268static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
269 JDrm *jdrm = (JDrm *)env->GetIntField(thiz, gFields.context);
270 return jdrm ? jdrm->getDrm() : NULL;
271}
272
273JDrm::JDrm(
274 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
275 mObject = env->NewWeakGlobalRef(thiz);
276 mDrm = MakeDrm(uuid);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700277 if (mDrm != NULL) {
278 mDrm->setListener(this);
279 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800280}
281
282JDrm::~JDrm() {
283 mDrm.clear();
284
285 JNIEnv *env = AndroidRuntime::getJNIEnv();
286
287 env->DeleteWeakGlobalRef(mObject);
288 mObject = NULL;
289}
290
291// static
292sp<IDrm> JDrm::MakeDrm() {
293 sp<IServiceManager> sm = defaultServiceManager();
294
295 sp<IBinder> binder =
296 sm->getService(String16("media.player"));
297
298 sp<IMediaPlayerService> service =
299 interface_cast<IMediaPlayerService>(binder);
300
301 if (service == NULL) {
302 return NULL;
303 }
304
305 sp<IDrm> drm = service->makeDrm();
306
307 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
308 return NULL;
309 }
310
311 return drm;
312}
313
314// static
315sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
316 sp<IDrm> drm = MakeDrm();
317
318 if (drm == NULL) {
319 return NULL;
320 }
321
322 status_t err = drm->createPlugin(uuid);
323
324 if (err != OK) {
325 return NULL;
326 }
327
328 return drm;
329}
330
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700331status_t JDrm::setListener(const sp<DrmListener>& listener) {
332 Mutex::Autolock lock(mLock);
333 mListener = listener;
334 return OK;
335}
336
337void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
338 sp<DrmListener> listener;
339 mLock.lock();
340 listener = mListener;
341 mLock.unlock();
342
343 if (listener != NULL) {
344 Mutex::Autolock lock(mNotifyLock);
345 listener->notify(eventType, extra, obj);
346 }
347}
348
349
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800350// static
351bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
352 sp<IDrm> drm = MakeDrm();
353
354 if (drm == NULL) {
355 return false;
356 }
357
358 return drm->isCryptoSchemeSupported(uuid);
359}
360
361status_t JDrm::initCheck() const {
362 return mDrm == NULL ? NO_INIT : OK;
363}
364
365// JNI conversion utilities
366static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
367 Vector<uint8_t> vector;
368 size_t length = env->GetArrayLength(byteArray);
369 vector.insertAt((size_t)0, length);
370 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
371 return vector;
372}
373
374static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
375 size_t length = vector.size();
376 jbyteArray result = env->NewByteArray(length);
377 if (result != NULL) {
378 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
379 }
380 return result;
381}
382
383static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800384 String8 result;
385
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700386 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800387 if (s) {
388 result = s;
389 env->ReleaseStringUTFChars(jstr, s);
390 }
391 return result;
392}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700393
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800394/*
395 import java.util.HashMap;
396 import java.util.Set;
397 import java.Map.Entry;
398 import jav.util.Iterator;
399
400 HashMap<k, v> hm;
401 Set<Entry<k, v> > s = hm.entrySet();
402 Iterator i = s.iterator();
403 Entry e = s.next();
404*/
405
406static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
407 jclass clazz;
408 FIND_CLASS(clazz, "java/lang/String");
409 KeyedVector<String8, String8> keyedVector;
410
411 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
412 if (entrySet) {
413 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
414 if (iterator) {
415 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
416 while (hasNext) {
417 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
418 if (entry) {
419 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
420 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700421 jniThrowException(env, "java/lang/IllegalArgumentException",
422 "HashMap key is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800423 }
424 jstring jkey = static_cast<jstring>(obj);
425
426 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
427 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700428 jniThrowException(env, "java/lang/IllegalArgumentException",
429 "HashMap value is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800430 }
431 jstring jvalue = static_cast<jstring>(obj);
432
433 String8 key = JStringToString8(env, jkey);
434 String8 value = JStringToString8(env, jvalue);
435 keyedVector.add(key, value);
436
437 env->DeleteLocalRef(jkey);
438 env->DeleteLocalRef(jvalue);
439 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
440 }
441 env->DeleteLocalRef(entry);
442 }
443 env->DeleteLocalRef(iterator);
444 }
445 env->DeleteLocalRef(entrySet);
446 }
447 return keyedVector;
448}
449
450static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
451 jclass clazz;
452 FIND_CLASS(clazz, "java/util/HashMap");
453 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
454 for (size_t i = 0; i < map.size(); ++i) {
455 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
456 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
457 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
458 env->DeleteLocalRef(jkey);
459 env->DeleteLocalRef(jvalue);
460 }
461 return hashMap;
462}
463
464static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
465 List<Vector<uint8_t> > list) {
466 jclass clazz;
467 FIND_CLASS(clazz, "java/util/ArrayList");
468 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
469 List<Vector<uint8_t> >::iterator iter = list.begin();
470 while (iter != list.end()) {
471 jbyteArray byteArray = VectorToJByteArray(env, *iter);
472 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
473 env->DeleteLocalRef(byteArray);
474 iter++;
475 }
476
477 return arrayList;
478}
479
480} // namespace android
481
482using namespace android;
483
484static sp<JDrm> setDrm(
485 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
486 sp<JDrm> old = (JDrm *)env->GetIntField(thiz, gFields.context);
487 if (drm != NULL) {
488 drm->incStrong(thiz);
489 }
490 if (old != NULL) {
491 old->decStrong(thiz);
492 }
493 env->SetIntField(thiz, gFields.context, (int)drm.get());
494
495 return old;
496}
497
498static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
499{
500 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700501 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800502 return false;
503 }
504
505 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700506 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800507 return false;
508 }
509 return true;
510}
511
512static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700513 sp<JDrm> drm = setDrm(env, thiz, NULL);
514 if (drm != NULL) {
515 drm->setListener(NULL);
516 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800517}
518
519static void android_media_MediaDrm_native_init(JNIEnv *env) {
520 jclass clazz;
521 FIND_CLASS(clazz, "android/media/MediaDrm");
522 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700523 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
524 "(Ljava/lang/Object;IILjava/lang/Object;)V");
525
526 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700527 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700528 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700529 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700530 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700531 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700532 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700533 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700534 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800535
Jeff Tinker17b89222013-05-21 12:35:06 -0700536 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
537 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
538 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
539 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
540 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
541 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
542
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700543 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700544 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
545 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800546
547 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700548 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
549 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800550
551 FIND_CLASS(clazz, "java/util/ArrayList");
552 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
553 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
554
555 FIND_CLASS(clazz, "java/util/HashMap");
556 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
557 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
558 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
559 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
560 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
561
562 FIND_CLASS(clazz, "java/util/Set");
563 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
564
565 FIND_CLASS(clazz, "java/util/Iterator");
566 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
567 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
568
569 FIND_CLASS(clazz, "java/util/Map$Entry");
570 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
571 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
572}
573
574static void android_media_MediaDrm_native_setup(
575 JNIEnv *env, jobject thiz,
576 jobject weak_this, jbyteArray uuidObj) {
577
578 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700579 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800580 return;
581 }
582
583 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
584
585 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700586 jniThrowException(env, "java/lang/IllegalArgumentException",
587 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800588 return;
589 }
590
591 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
592
593 status_t err = drm->initCheck();
594
595 if (err != OK) {
596 jniThrowException(
597 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700598 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800599 "Failed to instantiate drm object.");
600 return;
601 }
602
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700603 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
604 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800605 setDrm(env, thiz, drm);
606}
607
608static void android_media_MediaDrm_native_finalize(
609 JNIEnv *env, jobject thiz) {
610 android_media_MediaDrm_release(env, thiz);
611}
612
613static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
614 JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
615
616 if (uuidObj == NULL) {
617 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
618 return false;
619 }
620
621 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
622
623 if (uuid.size() != 16) {
624 jniThrowException(
625 env,
626 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700627 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800628 return false;
629 }
630
631 return JDrm::IsCryptoSchemeSupported(uuid.array());
632}
633
634static jbyteArray android_media_MediaDrm_openSession(
635 JNIEnv *env, jobject thiz) {
636 sp<IDrm> drm = GetDrm(env, thiz);
637
638 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700639 jniThrowException(env, "java/lang/IllegalStateException",
640 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800641 return NULL;
642 }
643
644 Vector<uint8_t> sessionId;
645 status_t err = drm->openSession(sessionId);
646
647 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
648 return NULL;
649 }
650
651 return VectorToJByteArray(env, sessionId);
652}
653
654static void android_media_MediaDrm_closeSession(
655 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
656 sp<IDrm> drm = GetDrm(env, thiz);
657
658 if (!CheckSession(env, drm, jsessionId)) {
659 return;
660 }
661
662 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
663
664 status_t err = drm->closeSession(sessionId);
665
666 throwExceptionAsNecessary(env, err, "Failed to close session");
667}
668
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700669static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800670 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700671 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800672 sp<IDrm> drm = GetDrm(env, thiz);
673
674 if (!CheckSession(env, drm, jsessionId)) {
675 return NULL;
676 }
677
678 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
679
680 Vector<uint8_t> initData;
681 if (jinitData != NULL) {
682 initData = JByteArrayToVector(env, jinitData);
683 }
684
685 String8 mimeType;
686 if (jmimeType != NULL) {
687 mimeType = JStringToString8(env, jmimeType);
688 }
689
Jeff Tinker17b89222013-05-21 12:35:06 -0700690 DrmPlugin::KeyType keyType;
691 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
692 keyType = DrmPlugin::kKeyType_Streaming;
693 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
694 keyType = DrmPlugin::kKeyType_Offline;
695 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
696 keyType = DrmPlugin::kKeyType_Release;
697 } else {
698 jniThrowException(env, "java/lang/IllegalArgumentException",
699 "invalid keyType");
700 return NULL;
701 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800702
703 KeyedVector<String8, String8> optParams;
704 if (joptParams != NULL) {
705 optParams = HashMapToKeyedVector(env, joptParams);
706 }
707
708 Vector<uint8_t> request;
709 String8 defaultUrl;
710
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700711 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
712 keyType, optParams, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800713
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700714 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800715 return NULL;
716 }
717
718 // Fill out return obj
719 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700720 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800721
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700722 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800723
724 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700725 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800726 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700727 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800728
729 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700730 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800731 }
732
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700733 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800734}
735
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700736static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800737 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
738 sp<IDrm> drm = GetDrm(env, thiz);
739
740 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700741 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800742 }
743
744 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
745
746 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700747 jniThrowException(env, "java/lang/IllegalArgumentException",
748 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700749 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800750 }
751 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700752 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800753
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700754 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800755
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700756 throwExceptionAsNecessary(env, err, "Failed to handle key response");
757 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800758}
759
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700760static void android_media_MediaDrm_removeKeys(
761 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
762 sp<IDrm> drm = GetDrm(env, thiz);
763
764 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700765 jniThrowException(env, "java/lang/IllegalArgumentException",
766 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700767 return;
768 }
769
770 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
771
772 status_t err = drm->removeKeys(keySetId);
773
774 throwExceptionAsNecessary(env, err, "Failed to remove keys");
775}
776
777static void android_media_MediaDrm_restoreKeys(
778 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
779 jbyteArray jkeysetId) {
780
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800781 sp<IDrm> drm = GetDrm(env, thiz);
782
783 if (!CheckSession(env, drm, jsessionId)) {
784 return;
785 }
786
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700787 if (jkeysetId == NULL) {
788 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
789 return;
790 }
791
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800792 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700793 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800794
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700795 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800796
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700797 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800798}
799
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700800static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800801 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
802 sp<IDrm> drm = GetDrm(env, thiz);
803
804 if (!CheckSession(env, drm, jsessionId)) {
805 return NULL;
806 }
807 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
808
809 KeyedVector<String8, String8> infoMap;
810
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700811 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800812
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700813 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800814 return NULL;
815 }
816
817 return KeyedVectorToHashMap(env, infoMap);
818}
819
820static jobject android_media_MediaDrm_getProvisionRequest(
821 JNIEnv *env, jobject thiz) {
822 sp<IDrm> drm = GetDrm(env, thiz);
823
824 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700825 jniThrowException(env, "java/lang/IllegalStateException",
826 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800827 return NULL;
828 }
829
830 Vector<uint8_t> request;
831 String8 defaultUrl;
832
833 status_t err = drm->getProvisionRequest(request, defaultUrl);
834
835 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
836 return NULL;
837 }
838
839 // Fill out return obj
840 jclass clazz;
841 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
842
843 jobject provisionObj = NULL;
844
845 if (clazz) {
846 provisionObj = env->AllocObject(clazz);
847 jbyteArray jrequest = VectorToJByteArray(env, request);
848 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
849
850 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
851 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
852 }
853
854 return provisionObj;
855}
856
857static void android_media_MediaDrm_provideProvisionResponse(
858 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
859 sp<IDrm> drm = GetDrm(env, thiz);
860
861 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700862 jniThrowException(env, "java/lang/IllegalStateException",
863 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800864 return;
865 }
866
867 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700868 jniThrowException(env, "java/lang/IllegalArgumentException",
869 "provision response is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800870 return;
871 }
872
873 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
874
875 status_t err = drm->provideProvisionResponse(response);
876
877 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
878}
879
880static jobject android_media_MediaDrm_getSecureStops(
881 JNIEnv *env, jobject thiz) {
882 sp<IDrm> drm = GetDrm(env, thiz);
883
884 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700885 jniThrowException(env, "java/lang/IllegalStateException",
886 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800887 return NULL;
888 }
889
890 List<Vector<uint8_t> > secureStops;
891
892 status_t err = drm->getSecureStops(secureStops);
893
894 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
895 return NULL;
896 }
897
898 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
899}
900
901static void android_media_MediaDrm_releaseSecureStops(
902 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
903 sp<IDrm> drm = GetDrm(env, thiz);
904
905 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700906 jniThrowException(env, "java/lang/IllegalStateException",
907 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800908 return;
909 }
910
911 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
912
913 status_t err = drm->releaseSecureStops(ssRelease);
914
915 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
916}
917
918static jstring android_media_MediaDrm_getPropertyString(
919 JNIEnv *env, jobject thiz, jstring jname) {
920 sp<IDrm> drm = GetDrm(env, thiz);
921
922 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700923 jniThrowException(env, "java/lang/IllegalStateException",
924 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800925 return NULL;
926 }
927
928 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700929 jniThrowException(env, "java/lang/IllegalArgumentException",
930 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800931 return NULL;
932 }
933
934 String8 name = JStringToString8(env, jname);
935 String8 value;
936
937 status_t err = drm->getPropertyString(name, value);
938
939 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
940 return NULL;
941 }
942
943 return env->NewStringUTF(value.string());
944}
945
946static jbyteArray android_media_MediaDrm_getPropertyByteArray(
947 JNIEnv *env, jobject thiz, jstring jname) {
948 sp<IDrm> drm = GetDrm(env, thiz);
949
950 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700951 jniThrowException(env, "java/lang/IllegalStateException",
952 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800953 return NULL;
954 }
955
956 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700957 jniThrowException(env, "java/lang/IllegalArgumentException",
958 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800959 return NULL;
960 }
961
962 String8 name = JStringToString8(env, jname);
963 Vector<uint8_t> value;
964
965 status_t err = drm->getPropertyByteArray(name, value);
966
967 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
968 return NULL;
969 }
970
971 return VectorToJByteArray(env, value);
972}
973
974static void android_media_MediaDrm_setPropertyString(
975 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
976 sp<IDrm> drm = GetDrm(env, thiz);
977
978 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700979 jniThrowException(env, "java/lang/IllegalStateException",
980 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800981 return;
982 }
983
Jeff Tinkereada5372013-05-21 12:48:14 -0700984 if (jname == NULL) {
985 jniThrowException(env, "java/lang/IllegalArgumentException",
986 "property name String is null");
987 return;
988 }
989
990 if (jvalue == NULL) {
991 jniThrowException(env, "java/lang/IllegalArgumentException",
992 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800993 return;
994 }
995
996 String8 name = JStringToString8(env, jname);
997 String8 value = JStringToString8(env, jvalue);
998
999 status_t err = drm->setPropertyString(name, value);
1000
1001 throwExceptionAsNecessary(env, err, "Failed to set property");
1002}
1003
1004static void android_media_MediaDrm_setPropertyByteArray(
1005 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1006 sp<IDrm> drm = GetDrm(env, thiz);
1007
1008 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001009 jniThrowException(env, "java/lang/IllegalStateException",
1010 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001011 return;
1012 }
1013
Jeff Tinkereada5372013-05-21 12:48:14 -07001014 if (jname == NULL) {
1015 jniThrowException(env, "java/lang/IllegalArgumentException",
1016 "property name String is null");
1017 return;
1018 }
1019
1020 if (jvalue == NULL) {
1021 jniThrowException(env, "java/lang/IllegalArgumentException",
1022 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001023 return;
1024 }
1025
1026 String8 name = JStringToString8(env, jname);
1027 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1028
1029 status_t err = drm->setPropertyByteArray(name, value);
1030
1031 throwExceptionAsNecessary(env, err, "Failed to set property");
1032}
1033
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001034static void android_media_MediaDrm_setCipherAlgorithmNative(
1035 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1036 jstring jalgorithm) {
1037
1038 sp<IDrm> drm = GetDrm(env, jdrm);
1039
1040 if (!CheckSession(env, drm, jsessionId)) {
1041 return;
1042 }
1043
1044 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001045 jniThrowException(env, "java/lang/IllegalArgumentException",
1046 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001047 return;
1048 }
1049
1050 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1051 String8 algorithm = JStringToString8(env, jalgorithm);
1052
1053 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1054
1055 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1056}
1057
1058static void android_media_MediaDrm_setMacAlgorithmNative(
1059 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1060 jstring jalgorithm) {
1061
1062 sp<IDrm> drm = GetDrm(env, jdrm);
1063
1064 if (!CheckSession(env, drm, jsessionId)) {
1065 return;
1066 }
1067
1068 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001069 jniThrowException(env, "java/lang/IllegalArgumentException",
1070 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001071 return;
1072 }
1073
1074 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1075 String8 algorithm = JStringToString8(env, jalgorithm);
1076
1077 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1078
1079 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1080}
1081
1082
1083static jbyteArray android_media_MediaDrm_encryptNative(
1084 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1085 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1086
1087 sp<IDrm> drm = GetDrm(env, jdrm);
1088
1089 if (!CheckSession(env, drm, jsessionId)) {
1090 return NULL;
1091 }
1092
1093 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001094 jniThrowException(env, "java/lang/IllegalArgumentException",
1095 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001096 return NULL;
1097 }
1098
1099 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1100 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1101 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1102 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1103 Vector<uint8_t> output;
1104
1105 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1106
1107 throwExceptionAsNecessary(env, err, "Failed to encrypt");
1108
1109 return VectorToJByteArray(env, output);
1110}
1111
1112static jbyteArray android_media_MediaDrm_decryptNative(
1113 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1114 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1115
1116 sp<IDrm> drm = GetDrm(env, jdrm);
1117
1118 if (!CheckSession(env, drm, jsessionId)) {
1119 return NULL;
1120 }
1121
1122 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001123 jniThrowException(env, "java/lang/IllegalArgumentException",
1124 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001125 return NULL;
1126 }
1127
1128 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1129 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1130 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1131 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1132 Vector<uint8_t> output;
1133
1134 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1135 throwExceptionAsNecessary(env, err, "Failed to decrypt");
1136
1137 return VectorToJByteArray(env, output);
1138}
1139
1140static jbyteArray android_media_MediaDrm_signNative(
1141 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1142 jbyteArray jkeyId, jbyteArray jmessage) {
1143
1144 sp<IDrm> drm = GetDrm(env, jdrm);
1145
1146 if (!CheckSession(env, drm, jsessionId)) {
1147 return NULL;
1148 }
1149
1150 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001151 jniThrowException(env, "java/lang/IllegalArgumentException",
1152 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001153 return NULL;
1154 }
1155
1156 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1157 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1158 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1159 Vector<uint8_t> signature;
1160
1161 status_t err = drm->sign(sessionId, keyId, message, signature);
1162
1163 throwExceptionAsNecessary(env, err, "Failed to sign");
1164
1165 return VectorToJByteArray(env, signature);
1166}
1167
1168static jboolean android_media_MediaDrm_verifyNative(
1169 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1170 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1171
1172 sp<IDrm> drm = GetDrm(env, jdrm);
1173
1174 if (!CheckSession(env, drm, jsessionId)) {
1175 return false;
1176 }
1177
1178 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001179 jniThrowException(env, "java/lang/IllegalArgumentException",
1180 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001181 return false;
1182 }
1183
1184 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1185 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1186 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1187 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1188 bool match;
1189
1190 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1191
1192 throwExceptionAsNecessary(env, err, "Failed to verify");
1193 return match;
1194}
1195
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001196
1197static JNINativeMethod gMethods[] = {
1198 { "release", "()V", (void *)android_media_MediaDrm_release },
1199 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1200
1201 { "native_setup", "(Ljava/lang/Object;[B)V",
1202 (void *)android_media_MediaDrm_native_setup },
1203
1204 { "native_finalize", "()V",
1205 (void *)android_media_MediaDrm_native_finalize },
1206
1207 { "isCryptoSchemeSupportedNative", "([B)Z",
1208 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1209
1210 { "openSession", "()[B",
1211 (void *)android_media_MediaDrm_openSession },
1212
1213 { "closeSession", "([B)V",
1214 (void *)android_media_MediaDrm_closeSession },
1215
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001216 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1217 "Landroid/media/MediaDrm$KeyRequest;",
1218 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001219
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001220 { "provideKeyResponse", "([B[B)[B",
1221 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001222
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001223 { "removeKeys", "([B)V",
1224 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001225
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001226 { "restoreKeys", "([B[B)V",
1227 (void *)android_media_MediaDrm_restoreKeys },
1228
1229 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1230 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001231
1232 { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
1233 (void *)android_media_MediaDrm_getProvisionRequest },
1234
1235 { "provideProvisionResponse", "([B)V",
1236 (void *)android_media_MediaDrm_provideProvisionResponse },
1237
1238 { "getSecureStops", "()Ljava/util/List;",
1239 (void *)android_media_MediaDrm_getSecureStops },
1240
1241 { "releaseSecureStops", "([B)V",
1242 (void *)android_media_MediaDrm_releaseSecureStops },
1243
1244 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1245 (void *)android_media_MediaDrm_getPropertyString },
1246
1247 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1248 (void *)android_media_MediaDrm_getPropertyByteArray },
1249
1250 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1251 (void *)android_media_MediaDrm_setPropertyString },
1252
1253 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1254 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001255
1256 { "setCipherAlgorithmNative",
1257 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1258 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1259
1260 { "setMacAlgorithmNative",
1261 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1262 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1263
1264 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1265 (void *)android_media_MediaDrm_encryptNative },
1266
1267 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1268 (void *)android_media_MediaDrm_decryptNative },
1269
1270 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1271 (void *)android_media_MediaDrm_signNative },
1272
1273 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1274 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001275};
1276
1277int register_android_media_Drm(JNIEnv *env) {
1278 return AndroidRuntime::registerNativeMethods(env,
1279 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1280}
1281