blob: 666d111621c3e3d5d221c1cf10c09e8e8ca87121 [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
Jeff Tinker7cda4912013-08-21 11:52:34 -0700351bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800352 sp<IDrm> drm = MakeDrm();
353
354 if (drm == NULL) {
355 return false;
356 }
357
Jeff Tinker7cda4912013-08-21 11:52:34 -0700358 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800359}
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(
Jeff Tinker7cda4912013-08-21 11:52:34 -0700614 JNIEnv *env, jobject thiz, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800615
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
Jeff Tinker7cda4912013-08-21 11:52:34 -0700631 String8 mimeType;
632 if (jmimeType != NULL) {
633 mimeType = JStringToString8(env, jmimeType);
634 }
635
636 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800637}
638
639static jbyteArray android_media_MediaDrm_openSession(
640 JNIEnv *env, jobject thiz) {
641 sp<IDrm> drm = GetDrm(env, thiz);
642
643 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700644 jniThrowException(env, "java/lang/IllegalStateException",
645 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800646 return NULL;
647 }
648
649 Vector<uint8_t> sessionId;
650 status_t err = drm->openSession(sessionId);
651
652 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
653 return NULL;
654 }
655
656 return VectorToJByteArray(env, sessionId);
657}
658
659static void android_media_MediaDrm_closeSession(
660 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
661 sp<IDrm> drm = GetDrm(env, thiz);
662
663 if (!CheckSession(env, drm, jsessionId)) {
664 return;
665 }
666
667 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
668
669 status_t err = drm->closeSession(sessionId);
670
671 throwExceptionAsNecessary(env, err, "Failed to close session");
672}
673
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700674static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800675 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700676 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800677 sp<IDrm> drm = GetDrm(env, thiz);
678
679 if (!CheckSession(env, drm, jsessionId)) {
680 return NULL;
681 }
682
683 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
684
685 Vector<uint8_t> initData;
686 if (jinitData != NULL) {
687 initData = JByteArrayToVector(env, jinitData);
688 }
689
690 String8 mimeType;
691 if (jmimeType != NULL) {
692 mimeType = JStringToString8(env, jmimeType);
693 }
694
Jeff Tinker17b89222013-05-21 12:35:06 -0700695 DrmPlugin::KeyType keyType;
696 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
697 keyType = DrmPlugin::kKeyType_Streaming;
698 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
699 keyType = DrmPlugin::kKeyType_Offline;
700 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
701 keyType = DrmPlugin::kKeyType_Release;
702 } else {
703 jniThrowException(env, "java/lang/IllegalArgumentException",
704 "invalid keyType");
705 return NULL;
706 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800707
708 KeyedVector<String8, String8> optParams;
709 if (joptParams != NULL) {
710 optParams = HashMapToKeyedVector(env, joptParams);
711 }
712
713 Vector<uint8_t> request;
714 String8 defaultUrl;
715
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700716 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
717 keyType, optParams, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800718
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700719 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800720 return NULL;
721 }
722
723 // Fill out return obj
724 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700725 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800726
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700727 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800728
729 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700730 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800731 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700732 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800733
734 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700735 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800736 }
737
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700738 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800739}
740
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700741static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800742 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
743 sp<IDrm> drm = GetDrm(env, thiz);
744
745 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700746 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800747 }
748
749 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
750
751 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700752 jniThrowException(env, "java/lang/IllegalArgumentException",
753 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700754 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800755 }
756 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700757 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800758
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700759 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800760
Jeff Tinker8117d8f2013-08-16 13:46:02 -0700761 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
762 return NULL;
763 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700764 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800765}
766
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700767static void android_media_MediaDrm_removeKeys(
768 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
769 sp<IDrm> drm = GetDrm(env, thiz);
770
771 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700772 jniThrowException(env, "java/lang/IllegalArgumentException",
773 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700774 return;
775 }
776
777 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
778
779 status_t err = drm->removeKeys(keySetId);
780
781 throwExceptionAsNecessary(env, err, "Failed to remove keys");
782}
783
784static void android_media_MediaDrm_restoreKeys(
785 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
786 jbyteArray jkeysetId) {
787
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800788 sp<IDrm> drm = GetDrm(env, thiz);
789
790 if (!CheckSession(env, drm, jsessionId)) {
791 return;
792 }
793
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700794 if (jkeysetId == NULL) {
795 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
796 return;
797 }
798
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800799 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700800 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800801
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700802 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800803
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700804 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800805}
806
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700807static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800808 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
809 sp<IDrm> drm = GetDrm(env, thiz);
810
811 if (!CheckSession(env, drm, jsessionId)) {
812 return NULL;
813 }
814 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
815
816 KeyedVector<String8, String8> infoMap;
817
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700818 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800819
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700820 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800821 return NULL;
822 }
823
824 return KeyedVectorToHashMap(env, infoMap);
825}
826
827static jobject android_media_MediaDrm_getProvisionRequest(
828 JNIEnv *env, jobject thiz) {
829 sp<IDrm> drm = GetDrm(env, thiz);
830
831 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700832 jniThrowException(env, "java/lang/IllegalStateException",
833 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800834 return NULL;
835 }
836
837 Vector<uint8_t> request;
838 String8 defaultUrl;
839
840 status_t err = drm->getProvisionRequest(request, defaultUrl);
841
842 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
843 return NULL;
844 }
845
846 // Fill out return obj
847 jclass clazz;
848 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
849
850 jobject provisionObj = NULL;
851
852 if (clazz) {
853 provisionObj = env->AllocObject(clazz);
854 jbyteArray jrequest = VectorToJByteArray(env, request);
855 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
856
857 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
858 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
859 }
860
861 return provisionObj;
862}
863
864static void android_media_MediaDrm_provideProvisionResponse(
865 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
866 sp<IDrm> drm = GetDrm(env, thiz);
867
868 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700869 jniThrowException(env, "java/lang/IllegalStateException",
870 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800871 return;
872 }
873
874 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700875 jniThrowException(env, "java/lang/IllegalArgumentException",
876 "provision response is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800877 return;
878 }
879
880 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
881
882 status_t err = drm->provideProvisionResponse(response);
883
884 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
885}
886
887static jobject android_media_MediaDrm_getSecureStops(
888 JNIEnv *env, jobject thiz) {
889 sp<IDrm> drm = GetDrm(env, thiz);
890
891 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700892 jniThrowException(env, "java/lang/IllegalStateException",
893 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800894 return NULL;
895 }
896
897 List<Vector<uint8_t> > secureStops;
898
899 status_t err = drm->getSecureStops(secureStops);
900
901 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
902 return NULL;
903 }
904
905 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
906}
907
908static void android_media_MediaDrm_releaseSecureStops(
909 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
910 sp<IDrm> drm = GetDrm(env, thiz);
911
912 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700913 jniThrowException(env, "java/lang/IllegalStateException",
914 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800915 return;
916 }
917
918 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
919
920 status_t err = drm->releaseSecureStops(ssRelease);
921
922 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
923}
924
925static jstring android_media_MediaDrm_getPropertyString(
926 JNIEnv *env, jobject thiz, jstring jname) {
927 sp<IDrm> drm = GetDrm(env, thiz);
928
929 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700930 jniThrowException(env, "java/lang/IllegalStateException",
931 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800932 return NULL;
933 }
934
935 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700936 jniThrowException(env, "java/lang/IllegalArgumentException",
937 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800938 return NULL;
939 }
940
941 String8 name = JStringToString8(env, jname);
942 String8 value;
943
944 status_t err = drm->getPropertyString(name, value);
945
946 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
947 return NULL;
948 }
949
950 return env->NewStringUTF(value.string());
951}
952
953static jbyteArray android_media_MediaDrm_getPropertyByteArray(
954 JNIEnv *env, jobject thiz, jstring jname) {
955 sp<IDrm> drm = GetDrm(env, thiz);
956
957 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700958 jniThrowException(env, "java/lang/IllegalStateException",
959 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800960 return NULL;
961 }
962
963 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700964 jniThrowException(env, "java/lang/IllegalArgumentException",
965 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800966 return NULL;
967 }
968
969 String8 name = JStringToString8(env, jname);
970 Vector<uint8_t> value;
971
972 status_t err = drm->getPropertyByteArray(name, value);
973
974 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
975 return NULL;
976 }
977
978 return VectorToJByteArray(env, value);
979}
980
981static void android_media_MediaDrm_setPropertyString(
982 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
983 sp<IDrm> drm = GetDrm(env, thiz);
984
985 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700986 jniThrowException(env, "java/lang/IllegalStateException",
987 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800988 return;
989 }
990
Jeff Tinkereada5372013-05-21 12:48:14 -0700991 if (jname == NULL) {
992 jniThrowException(env, "java/lang/IllegalArgumentException",
993 "property name String is null");
994 return;
995 }
996
997 if (jvalue == NULL) {
998 jniThrowException(env, "java/lang/IllegalArgumentException",
999 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001000 return;
1001 }
1002
1003 String8 name = JStringToString8(env, jname);
1004 String8 value = JStringToString8(env, jvalue);
1005
1006 status_t err = drm->setPropertyString(name, value);
1007
1008 throwExceptionAsNecessary(env, err, "Failed to set property");
1009}
1010
1011static void android_media_MediaDrm_setPropertyByteArray(
1012 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1013 sp<IDrm> drm = GetDrm(env, thiz);
1014
1015 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001016 jniThrowException(env, "java/lang/IllegalStateException",
1017 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001018 return;
1019 }
1020
Jeff Tinkereada5372013-05-21 12:48:14 -07001021 if (jname == NULL) {
1022 jniThrowException(env, "java/lang/IllegalArgumentException",
1023 "property name String is null");
1024 return;
1025 }
1026
1027 if (jvalue == NULL) {
1028 jniThrowException(env, "java/lang/IllegalArgumentException",
1029 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001030 return;
1031 }
1032
1033 String8 name = JStringToString8(env, jname);
1034 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1035
1036 status_t err = drm->setPropertyByteArray(name, value);
1037
1038 throwExceptionAsNecessary(env, err, "Failed to set property");
1039}
1040
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001041static void android_media_MediaDrm_setCipherAlgorithmNative(
1042 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1043 jstring jalgorithm) {
1044
1045 sp<IDrm> drm = GetDrm(env, jdrm);
1046
1047 if (!CheckSession(env, drm, jsessionId)) {
1048 return;
1049 }
1050
1051 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001052 jniThrowException(env, "java/lang/IllegalArgumentException",
1053 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001054 return;
1055 }
1056
1057 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1058 String8 algorithm = JStringToString8(env, jalgorithm);
1059
1060 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1061
1062 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1063}
1064
1065static void android_media_MediaDrm_setMacAlgorithmNative(
1066 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1067 jstring jalgorithm) {
1068
1069 sp<IDrm> drm = GetDrm(env, jdrm);
1070
1071 if (!CheckSession(env, drm, jsessionId)) {
1072 return;
1073 }
1074
1075 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001076 jniThrowException(env, "java/lang/IllegalArgumentException",
1077 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001078 return;
1079 }
1080
1081 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1082 String8 algorithm = JStringToString8(env, jalgorithm);
1083
1084 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1085
1086 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1087}
1088
1089
1090static jbyteArray android_media_MediaDrm_encryptNative(
1091 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1092 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1093
1094 sp<IDrm> drm = GetDrm(env, jdrm);
1095
1096 if (!CheckSession(env, drm, jsessionId)) {
1097 return NULL;
1098 }
1099
1100 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001101 jniThrowException(env, "java/lang/IllegalArgumentException",
1102 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001103 return NULL;
1104 }
1105
1106 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1107 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1108 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1109 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1110 Vector<uint8_t> output;
1111
1112 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1113
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001114 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1115 return NULL;
1116 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001117
1118 return VectorToJByteArray(env, output);
1119}
1120
1121static jbyteArray android_media_MediaDrm_decryptNative(
1122 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1123 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1124
1125 sp<IDrm> drm = GetDrm(env, jdrm);
1126
1127 if (!CheckSession(env, drm, jsessionId)) {
1128 return NULL;
1129 }
1130
1131 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001132 jniThrowException(env, "java/lang/IllegalArgumentException",
1133 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001134 return NULL;
1135 }
1136
1137 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1138 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1139 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1140 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1141 Vector<uint8_t> output;
1142
1143 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001144 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1145 return NULL;
1146 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001147
1148 return VectorToJByteArray(env, output);
1149}
1150
1151static jbyteArray android_media_MediaDrm_signNative(
1152 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1153 jbyteArray jkeyId, jbyteArray jmessage) {
1154
1155 sp<IDrm> drm = GetDrm(env, jdrm);
1156
1157 if (!CheckSession(env, drm, jsessionId)) {
1158 return NULL;
1159 }
1160
1161 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001162 jniThrowException(env, "java/lang/IllegalArgumentException",
1163 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001164 return NULL;
1165 }
1166
1167 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1168 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1169 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1170 Vector<uint8_t> signature;
1171
1172 status_t err = drm->sign(sessionId, keyId, message, signature);
1173
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001174 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1175 return NULL;
1176 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001177
1178 return VectorToJByteArray(env, signature);
1179}
1180
1181static jboolean android_media_MediaDrm_verifyNative(
1182 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1183 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1184
1185 sp<IDrm> drm = GetDrm(env, jdrm);
1186
1187 if (!CheckSession(env, drm, jsessionId)) {
1188 return false;
1189 }
1190
1191 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001192 jniThrowException(env, "java/lang/IllegalArgumentException",
1193 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001194 return false;
1195 }
1196
1197 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1198 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1199 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1200 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1201 bool match;
1202
1203 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1204
1205 throwExceptionAsNecessary(env, err, "Failed to verify");
1206 return match;
1207}
1208
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001209
1210static JNINativeMethod gMethods[] = {
1211 { "release", "()V", (void *)android_media_MediaDrm_release },
1212 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1213
1214 { "native_setup", "(Ljava/lang/Object;[B)V",
1215 (void *)android_media_MediaDrm_native_setup },
1216
1217 { "native_finalize", "()V",
1218 (void *)android_media_MediaDrm_native_finalize },
1219
Jeff Tinker7cda4912013-08-21 11:52:34 -07001220 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001221 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1222
1223 { "openSession", "()[B",
1224 (void *)android_media_MediaDrm_openSession },
1225
1226 { "closeSession", "([B)V",
1227 (void *)android_media_MediaDrm_closeSession },
1228
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001229 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1230 "Landroid/media/MediaDrm$KeyRequest;",
1231 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001232
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001233 { "provideKeyResponse", "([B[B)[B",
1234 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001235
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001236 { "removeKeys", "([B)V",
1237 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001238
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001239 { "restoreKeys", "([B[B)V",
1240 (void *)android_media_MediaDrm_restoreKeys },
1241
1242 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1243 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001244
1245 { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
1246 (void *)android_media_MediaDrm_getProvisionRequest },
1247
1248 { "provideProvisionResponse", "([B)V",
1249 (void *)android_media_MediaDrm_provideProvisionResponse },
1250
1251 { "getSecureStops", "()Ljava/util/List;",
1252 (void *)android_media_MediaDrm_getSecureStops },
1253
1254 { "releaseSecureStops", "([B)V",
1255 (void *)android_media_MediaDrm_releaseSecureStops },
1256
1257 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1258 (void *)android_media_MediaDrm_getPropertyString },
1259
1260 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1261 (void *)android_media_MediaDrm_getPropertyByteArray },
1262
1263 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1264 (void *)android_media_MediaDrm_setPropertyString },
1265
1266 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1267 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001268
1269 { "setCipherAlgorithmNative",
1270 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1271 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1272
1273 { "setMacAlgorithmNative",
1274 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1275 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1276
1277 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1278 (void *)android_media_MediaDrm_encryptNative },
1279
1280 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1281 (void *)android_media_MediaDrm_decryptNative },
1282
1283 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1284 (void *)android_media_MediaDrm_signNative },
1285
1286 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1287 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001288};
1289
1290int register_android_media_Drm(JNIEnv *env) {
1291 return AndroidRuntime::registerNativeMethods(env,
1292 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1293}
1294