blob: ca26e4a40314dd9a5257de874a426d99e2bb951c [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"
Ruben Brunk87eac992013-09-09 17:44:59 -070024#include "android_runtime/Log.h"
Jeff Tinker54cfbd62013-04-02 13:14:59 -070025#include "android_os_Parcel.h"
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080026#include "jni.h"
27#include "JNIHelp.h"
28
29#include <binder/IServiceManager.h>
Jeff Tinker54cfbd62013-04-02 13:14:59 -070030#include <binder/Parcel.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080031#include <media/IDrm.h>
32#include <media/IMediaPlayerService.h>
33#include <media/stagefright/foundation/ADebug.h>
Jeff Tinkerf7568b52013-04-17 14:24:40 -070034#include <media/stagefright/MediaErrors.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080035
36namespace android {
37
38#define FIND_CLASS(var, className) \
39 var = env->FindClass(className); \
40 LOG_FATAL_IF(! var, "Unable to find class " className);
41
42#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
43 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
44 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
45
46#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
47 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
48 LOG_FATAL_IF(! var, "Unable to find method " fieldName);
49
Jeff Tinker54cfbd62013-04-02 13:14:59 -070050#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
51 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
52 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
53
54#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
55 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
56 LOG_FATAL_IF(! var, "Unable to find static method " fieldName);
57
58
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080059struct RequestFields {
60 jfieldID data;
61 jfieldID defaultUrl;
62};
63
64struct ArrayListFields {
65 jmethodID init;
66 jmethodID add;
67};
68
69struct HashmapFields {
70 jmethodID init;
71 jmethodID get;
72 jmethodID put;
73 jmethodID entrySet;
74};
75
76struct SetFields {
77 jmethodID iterator;
78};
79
80struct IteratorFields {
81 jmethodID next;
82 jmethodID hasNext;
83};
84
85struct EntryFields {
86 jmethodID getKey;
87 jmethodID getValue;
88};
89
Jeff Tinker54cfbd62013-04-02 13:14:59 -070090struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -070091 jint kEventProvisionRequired;
92 jint kEventKeyRequired;
93 jint kEventKeyExpired;
94 jint kEventVendorDefined;
Jeff Tinker54cfbd62013-04-02 13:14:59 -070095} gEventTypes;
96
Jeff Tinker17b89222013-05-21 12:35:06 -070097struct KeyTypes {
98 jint kKeyTypeStreaming;
99 jint kKeyTypeOffline;
100 jint kKeyTypeRelease;
101} gKeyTypes;
102
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800103struct fields_t {
104 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700105 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700106 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800107 RequestFields provisionRequest;
108 ArrayListFields arraylist;
109 HashmapFields hashmap;
110 SetFields set;
111 IteratorFields iterator;
112 EntryFields entry;
113};
114
115static fields_t gFields;
116
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700117// ----------------------------------------------------------------------------
118// ref-counted object for callbacks
119class JNIDrmListener: public DrmListener
120{
121public:
122 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
123 ~JNIDrmListener();
124 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
125private:
126 JNIDrmListener();
127 jclass mClass; // Reference to MediaDrm class
128 jobject mObject; // Weak ref to MediaDrm Java object to call on
129};
130
131JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
132{
133 // Hold onto the MediaDrm class for use in calling the static method
134 // that posts events to the application thread.
135 jclass clazz = env->GetObjectClass(thiz);
136 if (clazz == NULL) {
137 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700138 jniThrowException(env, "java/lang/Exception",
139 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700140 return;
141 }
142 mClass = (jclass)env->NewGlobalRef(clazz);
143
144 // We use a weak reference so the MediaDrm object can be garbage collected.
145 // The reference is only used as a proxy for callbacks.
146 mObject = env->NewGlobalRef(weak_thiz);
147}
148
149JNIDrmListener::~JNIDrmListener()
150{
151 // remove global references
152 JNIEnv *env = AndroidRuntime::getJNIEnv();
153 env->DeleteGlobalRef(mObject);
154 env->DeleteGlobalRef(mClass);
155}
156
157void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
158 const Parcel *obj)
159{
160 jint jeventType;
161
162 // translate DrmPlugin event types into their java equivalents
163 switch(eventType) {
164 case DrmPlugin::kDrmPluginEventProvisionRequired:
165 jeventType = gEventTypes.kEventProvisionRequired;
166 break;
167 case DrmPlugin::kDrmPluginEventKeyNeeded:
168 jeventType = gEventTypes.kEventKeyRequired;
169 break;
170 case DrmPlugin::kDrmPluginEventKeyExpired:
171 jeventType = gEventTypes.kEventKeyExpired;
172 break;
173 case DrmPlugin::kDrmPluginEventVendorDefined:
174 jeventType = gEventTypes.kEventVendorDefined;
175 break;
176 default:
177 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
178 return;
179 }
180
181 JNIEnv *env = AndroidRuntime::getJNIEnv();
182 if (obj && obj->dataSize() > 0) {
183 jobject jParcel = createJavaParcelObject(env);
184 if (jParcel != NULL) {
185 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
186 nativeParcel->setData(obj->data(), obj->dataSize());
187 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
188 jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100189 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700190 }
191 }
192
193 if (env->ExceptionCheck()) {
194 ALOGW("An exception occurred while notifying an event.");
195 LOGW_EX(env);
196 env->ExceptionClear();
197 }
198}
199
200
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800201static bool throwExceptionAsNecessary(
202 JNIEnv *env, status_t err, const char *msg = NULL) {
203
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700204 const char *drmMessage = NULL;
205
206 switch(err) {
207 case ERROR_DRM_UNKNOWN:
208 drmMessage = "General DRM error";
209 break;
210 case ERROR_DRM_NO_LICENSE:
211 drmMessage = "No license";
212 break;
213 case ERROR_DRM_LICENSE_EXPIRED:
214 drmMessage = "License expired";
215 break;
216 case ERROR_DRM_SESSION_NOT_OPENED:
217 drmMessage = "Session not opened";
218 break;
219 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
220 drmMessage = "Not initialized";
221 break;
222 case ERROR_DRM_DECRYPT:
223 drmMessage = "Decrypt error";
224 break;
225 case ERROR_DRM_CANNOT_HANDLE:
226 drmMessage = "Unsupported scheme or data format";
227 break;
228 case ERROR_DRM_TAMPER_DETECTED:
229 drmMessage = "Invalid state";
230 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700231 default:
232 break;
233 }
234
235 String8 vendorMessage;
236 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
237 vendorMessage.format("DRM vendor-defined error: %d", err);
238 drmMessage = vendorMessage.string();
239 }
240
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800241 if (err == BAD_VALUE) {
242 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
243 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700244 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
245 jniThrowException(env, "android/media/NotProvisionedException", msg);
246 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700247 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
248 jniThrowException(env, "android/media/ResourceBusyException", msg);
249 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700250 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
251 jniThrowException(env, "android/media/DeniedByServerException", msg);
252 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800253 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700254 String8 errbuf;
255 if (drmMessage != NULL) {
256 if (msg == NULL) {
257 msg = drmMessage;
258 } else {
259 errbuf.format("%s: %s", msg, drmMessage);
260 msg = errbuf.string();
261 }
262 }
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700263 ALOGE("Illegal state exception: %s", msg);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800264 jniThrowException(env, "java/lang/IllegalStateException", msg);
265 return true;
266 }
267 return false;
268}
269
270static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000271 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800272 return jdrm ? jdrm->getDrm() : NULL;
273}
274
275JDrm::JDrm(
276 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
277 mObject = env->NewWeakGlobalRef(thiz);
278 mDrm = MakeDrm(uuid);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700279 if (mDrm != NULL) {
280 mDrm->setListener(this);
281 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800282}
283
284JDrm::~JDrm() {
285 mDrm.clear();
286
287 JNIEnv *env = AndroidRuntime::getJNIEnv();
288
289 env->DeleteWeakGlobalRef(mObject);
290 mObject = NULL;
291}
292
293// static
294sp<IDrm> JDrm::MakeDrm() {
295 sp<IServiceManager> sm = defaultServiceManager();
296
297 sp<IBinder> binder =
298 sm->getService(String16("media.player"));
299
300 sp<IMediaPlayerService> service =
301 interface_cast<IMediaPlayerService>(binder);
302
303 if (service == NULL) {
304 return NULL;
305 }
306
307 sp<IDrm> drm = service->makeDrm();
308
309 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
310 return NULL;
311 }
312
313 return drm;
314}
315
316// static
317sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
318 sp<IDrm> drm = MakeDrm();
319
320 if (drm == NULL) {
321 return NULL;
322 }
323
324 status_t err = drm->createPlugin(uuid);
325
326 if (err != OK) {
327 return NULL;
328 }
329
330 return drm;
331}
332
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700333status_t JDrm::setListener(const sp<DrmListener>& listener) {
334 Mutex::Autolock lock(mLock);
335 mListener = listener;
336 return OK;
337}
338
339void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
340 sp<DrmListener> listener;
341 mLock.lock();
342 listener = mListener;
343 mLock.unlock();
344
345 if (listener != NULL) {
346 Mutex::Autolock lock(mNotifyLock);
347 listener->notify(eventType, extra, obj);
348 }
349}
350
351
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800352// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700353bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800354 sp<IDrm> drm = MakeDrm();
355
356 if (drm == NULL) {
357 return false;
358 }
359
Jeff Tinker7cda4912013-08-21 11:52:34 -0700360 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800361}
362
363status_t JDrm::initCheck() const {
364 return mDrm == NULL ? NO_INIT : OK;
365}
366
367// JNI conversion utilities
368static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
369 Vector<uint8_t> vector;
370 size_t length = env->GetArrayLength(byteArray);
371 vector.insertAt((size_t)0, length);
372 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
373 return vector;
374}
375
376static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
377 size_t length = vector.size();
378 jbyteArray result = env->NewByteArray(length);
379 if (result != NULL) {
380 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
381 }
382 return result;
383}
384
385static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800386 String8 result;
387
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700388 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800389 if (s) {
390 result = s;
391 env->ReleaseStringUTFChars(jstr, s);
392 }
393 return result;
394}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700395
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800396/*
397 import java.util.HashMap;
398 import java.util.Set;
399 import java.Map.Entry;
400 import jav.util.Iterator;
401
402 HashMap<k, v> hm;
403 Set<Entry<k, v> > s = hm.entrySet();
404 Iterator i = s.iterator();
405 Entry e = s.next();
406*/
407
408static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
409 jclass clazz;
410 FIND_CLASS(clazz, "java/lang/String");
411 KeyedVector<String8, String8> keyedVector;
412
413 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
414 if (entrySet) {
415 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
416 if (iterator) {
417 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
418 while (hasNext) {
419 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
420 if (entry) {
421 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
422 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700423 jniThrowException(env, "java/lang/IllegalArgumentException",
424 "HashMap key is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800425 }
426 jstring jkey = static_cast<jstring>(obj);
427
428 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
429 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700430 jniThrowException(env, "java/lang/IllegalArgumentException",
431 "HashMap value is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800432 }
433 jstring jvalue = static_cast<jstring>(obj);
434
435 String8 key = JStringToString8(env, jkey);
436 String8 value = JStringToString8(env, jvalue);
437 keyedVector.add(key, value);
438
439 env->DeleteLocalRef(jkey);
440 env->DeleteLocalRef(jvalue);
441 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
442 }
443 env->DeleteLocalRef(entry);
444 }
445 env->DeleteLocalRef(iterator);
446 }
447 env->DeleteLocalRef(entrySet);
448 }
449 return keyedVector;
450}
451
452static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
453 jclass clazz;
454 FIND_CLASS(clazz, "java/util/HashMap");
455 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
456 for (size_t i = 0; i < map.size(); ++i) {
457 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
458 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
459 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
460 env->DeleteLocalRef(jkey);
461 env->DeleteLocalRef(jvalue);
462 }
463 return hashMap;
464}
465
466static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
467 List<Vector<uint8_t> > list) {
468 jclass clazz;
469 FIND_CLASS(clazz, "java/util/ArrayList");
470 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
471 List<Vector<uint8_t> >::iterator iter = list.begin();
472 while (iter != list.end()) {
473 jbyteArray byteArray = VectorToJByteArray(env, *iter);
474 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
475 env->DeleteLocalRef(byteArray);
476 iter++;
477 }
478
479 return arrayList;
480}
481
482} // namespace android
483
484using namespace android;
485
486static sp<JDrm> setDrm(
487 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000488 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800489 if (drm != NULL) {
490 drm->incStrong(thiz);
491 }
492 if (old != NULL) {
493 old->decStrong(thiz);
494 }
495 env->SetIntField(thiz, gFields.context, (int)drm.get());
496
497 return old;
498}
499
500static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
501{
502 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700503 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800504 return false;
505 }
506
507 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700508 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800509 return false;
510 }
511 return true;
512}
513
514static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700515 sp<JDrm> drm = setDrm(env, thiz, NULL);
516 if (drm != NULL) {
517 drm->setListener(NULL);
518 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800519}
520
521static void android_media_MediaDrm_native_init(JNIEnv *env) {
522 jclass clazz;
523 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000524 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700525 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
526 "(Ljava/lang/Object;IILjava/lang/Object;)V");
527
528 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700529 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700530 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700531 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700532 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700533 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700534 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700535 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700536 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800537
Jeff Tinker17b89222013-05-21 12:35:06 -0700538 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
539 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
540 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
541 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
542 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
543 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
544
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700545 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700546 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
547 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800548
549 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700550 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
551 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800552
553 FIND_CLASS(clazz, "java/util/ArrayList");
554 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
555 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
556
557 FIND_CLASS(clazz, "java/util/HashMap");
558 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
559 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
560 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
561 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
562 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
563
564 FIND_CLASS(clazz, "java/util/Set");
565 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
566
567 FIND_CLASS(clazz, "java/util/Iterator");
568 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
569 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
570
571 FIND_CLASS(clazz, "java/util/Map$Entry");
572 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
573 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
574}
575
576static void android_media_MediaDrm_native_setup(
577 JNIEnv *env, jobject thiz,
578 jobject weak_this, jbyteArray uuidObj) {
579
580 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700581 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800582 return;
583 }
584
585 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
586
587 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700588 jniThrowException(env, "java/lang/IllegalArgumentException",
589 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800590 return;
591 }
592
593 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
594
595 status_t err = drm->initCheck();
596
597 if (err != OK) {
598 jniThrowException(
599 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700600 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800601 "Failed to instantiate drm object.");
602 return;
603 }
604
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700605 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
606 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800607 setDrm(env, thiz, drm);
608}
609
610static void android_media_MediaDrm_native_finalize(
611 JNIEnv *env, jobject thiz) {
612 android_media_MediaDrm_release(env, thiz);
613}
614
615static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinker7cda4912013-08-21 11:52:34 -0700616 JNIEnv *env, jobject thiz, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800617
618 if (uuidObj == NULL) {
619 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
620 return false;
621 }
622
623 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
624
625 if (uuid.size() != 16) {
626 jniThrowException(
627 env,
628 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700629 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800630 return false;
631 }
632
Jeff Tinker7cda4912013-08-21 11:52:34 -0700633 String8 mimeType;
634 if (jmimeType != NULL) {
635 mimeType = JStringToString8(env, jmimeType);
636 }
637
638 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800639}
640
641static jbyteArray android_media_MediaDrm_openSession(
642 JNIEnv *env, jobject thiz) {
643 sp<IDrm> drm = GetDrm(env, thiz);
644
645 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700646 jniThrowException(env, "java/lang/IllegalStateException",
647 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800648 return NULL;
649 }
650
651 Vector<uint8_t> sessionId;
652 status_t err = drm->openSession(sessionId);
653
654 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
655 return NULL;
656 }
657
658 return VectorToJByteArray(env, sessionId);
659}
660
661static void android_media_MediaDrm_closeSession(
662 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
663 sp<IDrm> drm = GetDrm(env, thiz);
664
665 if (!CheckSession(env, drm, jsessionId)) {
666 return;
667 }
668
669 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
670
671 status_t err = drm->closeSession(sessionId);
672
673 throwExceptionAsNecessary(env, err, "Failed to close session");
674}
675
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700676static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800677 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700678 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800679 sp<IDrm> drm = GetDrm(env, thiz);
680
681 if (!CheckSession(env, drm, jsessionId)) {
682 return NULL;
683 }
684
685 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
686
687 Vector<uint8_t> initData;
688 if (jinitData != NULL) {
689 initData = JByteArrayToVector(env, jinitData);
690 }
691
692 String8 mimeType;
693 if (jmimeType != NULL) {
694 mimeType = JStringToString8(env, jmimeType);
695 }
696
Jeff Tinker17b89222013-05-21 12:35:06 -0700697 DrmPlugin::KeyType keyType;
698 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
699 keyType = DrmPlugin::kKeyType_Streaming;
700 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
701 keyType = DrmPlugin::kKeyType_Offline;
702 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
703 keyType = DrmPlugin::kKeyType_Release;
704 } else {
705 jniThrowException(env, "java/lang/IllegalArgumentException",
706 "invalid keyType");
707 return NULL;
708 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800709
710 KeyedVector<String8, String8> optParams;
711 if (joptParams != NULL) {
712 optParams = HashMapToKeyedVector(env, joptParams);
713 }
714
715 Vector<uint8_t> request;
716 String8 defaultUrl;
717
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700718 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
719 keyType, optParams, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800720
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700721 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800722 return NULL;
723 }
724
725 // Fill out return obj
726 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700727 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800728
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700729 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800730
731 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700732 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800733 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700734 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800735
736 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700737 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800738 }
739
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700740 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800741}
742
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700743static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800744 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
745 sp<IDrm> drm = GetDrm(env, thiz);
746
747 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700748 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800749 }
750
751 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
752
753 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700754 jniThrowException(env, "java/lang/IllegalArgumentException",
755 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700756 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800757 }
758 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700759 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800760
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700761 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800762
Jeff Tinker8117d8f2013-08-16 13:46:02 -0700763 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
764 return NULL;
765 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700766 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800767}
768
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700769static void android_media_MediaDrm_removeKeys(
770 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
771 sp<IDrm> drm = GetDrm(env, thiz);
772
773 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700774 jniThrowException(env, "java/lang/IllegalArgumentException",
775 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700776 return;
777 }
778
779 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
780
781 status_t err = drm->removeKeys(keySetId);
782
783 throwExceptionAsNecessary(env, err, "Failed to remove keys");
784}
785
786static void android_media_MediaDrm_restoreKeys(
787 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
788 jbyteArray jkeysetId) {
789
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800790 sp<IDrm> drm = GetDrm(env, thiz);
791
792 if (!CheckSession(env, drm, jsessionId)) {
793 return;
794 }
795
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700796 if (jkeysetId == NULL) {
797 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
798 return;
799 }
800
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800801 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700802 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800803
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700804 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800805
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700806 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800807}
808
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700809static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800810 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
811 sp<IDrm> drm = GetDrm(env, thiz);
812
813 if (!CheckSession(env, drm, jsessionId)) {
814 return NULL;
815 }
816 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
817
818 KeyedVector<String8, String8> infoMap;
819
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700820 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800821
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700822 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800823 return NULL;
824 }
825
826 return KeyedVectorToHashMap(env, infoMap);
827}
828
829static jobject android_media_MediaDrm_getProvisionRequest(
830 JNIEnv *env, jobject thiz) {
831 sp<IDrm> drm = GetDrm(env, thiz);
832
833 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700834 jniThrowException(env, "java/lang/IllegalStateException",
835 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800836 return NULL;
837 }
838
839 Vector<uint8_t> request;
840 String8 defaultUrl;
841
842 status_t err = drm->getProvisionRequest(request, defaultUrl);
843
844 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
845 return NULL;
846 }
847
848 // Fill out return obj
849 jclass clazz;
850 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
851
852 jobject provisionObj = NULL;
853
854 if (clazz) {
855 provisionObj = env->AllocObject(clazz);
856 jbyteArray jrequest = VectorToJByteArray(env, request);
857 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
858
859 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
860 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
861 }
862
863 return provisionObj;
864}
865
866static void android_media_MediaDrm_provideProvisionResponse(
867 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
868 sp<IDrm> drm = GetDrm(env, thiz);
869
870 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700871 jniThrowException(env, "java/lang/IllegalStateException",
872 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800873 return;
874 }
875
876 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700877 jniThrowException(env, "java/lang/IllegalArgumentException",
878 "provision response is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800879 return;
880 }
881
882 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
883
884 status_t err = drm->provideProvisionResponse(response);
885
886 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
887}
888
889static jobject android_media_MediaDrm_getSecureStops(
890 JNIEnv *env, jobject thiz) {
891 sp<IDrm> drm = GetDrm(env, thiz);
892
893 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700894 jniThrowException(env, "java/lang/IllegalStateException",
895 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800896 return NULL;
897 }
898
899 List<Vector<uint8_t> > secureStops;
900
901 status_t err = drm->getSecureStops(secureStops);
902
903 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
904 return NULL;
905 }
906
907 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
908}
909
910static void android_media_MediaDrm_releaseSecureStops(
911 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
912 sp<IDrm> drm = GetDrm(env, thiz);
913
914 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700915 jniThrowException(env, "java/lang/IllegalStateException",
916 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800917 return;
918 }
919
920 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
921
922 status_t err = drm->releaseSecureStops(ssRelease);
923
924 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
925}
926
927static jstring android_media_MediaDrm_getPropertyString(
928 JNIEnv *env, jobject thiz, jstring jname) {
929 sp<IDrm> drm = GetDrm(env, thiz);
930
931 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700932 jniThrowException(env, "java/lang/IllegalStateException",
933 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800934 return NULL;
935 }
936
937 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700938 jniThrowException(env, "java/lang/IllegalArgumentException",
939 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800940 return NULL;
941 }
942
943 String8 name = JStringToString8(env, jname);
944 String8 value;
945
946 status_t err = drm->getPropertyString(name, value);
947
948 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
949 return NULL;
950 }
951
952 return env->NewStringUTF(value.string());
953}
954
955static jbyteArray android_media_MediaDrm_getPropertyByteArray(
956 JNIEnv *env, jobject thiz, jstring jname) {
957 sp<IDrm> drm = GetDrm(env, thiz);
958
959 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700960 jniThrowException(env, "java/lang/IllegalStateException",
961 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800962 return NULL;
963 }
964
965 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700966 jniThrowException(env, "java/lang/IllegalArgumentException",
967 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800968 return NULL;
969 }
970
971 String8 name = JStringToString8(env, jname);
972 Vector<uint8_t> value;
973
974 status_t err = drm->getPropertyByteArray(name, value);
975
976 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
977 return NULL;
978 }
979
980 return VectorToJByteArray(env, value);
981}
982
983static void android_media_MediaDrm_setPropertyString(
984 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
985 sp<IDrm> drm = GetDrm(env, thiz);
986
987 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700988 jniThrowException(env, "java/lang/IllegalStateException",
989 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800990 return;
991 }
992
Jeff Tinkereada5372013-05-21 12:48:14 -0700993 if (jname == NULL) {
994 jniThrowException(env, "java/lang/IllegalArgumentException",
995 "property name String is null");
996 return;
997 }
998
999 if (jvalue == NULL) {
1000 jniThrowException(env, "java/lang/IllegalArgumentException",
1001 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001002 return;
1003 }
1004
1005 String8 name = JStringToString8(env, jname);
1006 String8 value = JStringToString8(env, jvalue);
1007
1008 status_t err = drm->setPropertyString(name, value);
1009
1010 throwExceptionAsNecessary(env, err, "Failed to set property");
1011}
1012
1013static void android_media_MediaDrm_setPropertyByteArray(
1014 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1015 sp<IDrm> drm = GetDrm(env, thiz);
1016
1017 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001018 jniThrowException(env, "java/lang/IllegalStateException",
1019 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001020 return;
1021 }
1022
Jeff Tinkereada5372013-05-21 12:48:14 -07001023 if (jname == NULL) {
1024 jniThrowException(env, "java/lang/IllegalArgumentException",
1025 "property name String is null");
1026 return;
1027 }
1028
1029 if (jvalue == NULL) {
1030 jniThrowException(env, "java/lang/IllegalArgumentException",
1031 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001032 return;
1033 }
1034
1035 String8 name = JStringToString8(env, jname);
1036 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1037
1038 status_t err = drm->setPropertyByteArray(name, value);
1039
1040 throwExceptionAsNecessary(env, err, "Failed to set property");
1041}
1042
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001043static void android_media_MediaDrm_setCipherAlgorithmNative(
1044 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1045 jstring jalgorithm) {
1046
1047 sp<IDrm> drm = GetDrm(env, jdrm);
1048
1049 if (!CheckSession(env, drm, jsessionId)) {
1050 return;
1051 }
1052
1053 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001054 jniThrowException(env, "java/lang/IllegalArgumentException",
1055 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001056 return;
1057 }
1058
1059 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1060 String8 algorithm = JStringToString8(env, jalgorithm);
1061
1062 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1063
1064 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1065}
1066
1067static void android_media_MediaDrm_setMacAlgorithmNative(
1068 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1069 jstring jalgorithm) {
1070
1071 sp<IDrm> drm = GetDrm(env, jdrm);
1072
1073 if (!CheckSession(env, drm, jsessionId)) {
1074 return;
1075 }
1076
1077 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001078 jniThrowException(env, "java/lang/IllegalArgumentException",
1079 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001080 return;
1081 }
1082
1083 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1084 String8 algorithm = JStringToString8(env, jalgorithm);
1085
1086 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1087
1088 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1089}
1090
1091
1092static jbyteArray android_media_MediaDrm_encryptNative(
1093 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1094 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1095
1096 sp<IDrm> drm = GetDrm(env, jdrm);
1097
1098 if (!CheckSession(env, drm, jsessionId)) {
1099 return NULL;
1100 }
1101
1102 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001103 jniThrowException(env, "java/lang/IllegalArgumentException",
1104 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001105 return NULL;
1106 }
1107
1108 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1109 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1110 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1111 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1112 Vector<uint8_t> output;
1113
1114 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1115
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001116 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1117 return NULL;
1118 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001119
1120 return VectorToJByteArray(env, output);
1121}
1122
1123static jbyteArray android_media_MediaDrm_decryptNative(
1124 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1125 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1126
1127 sp<IDrm> drm = GetDrm(env, jdrm);
1128
1129 if (!CheckSession(env, drm, jsessionId)) {
1130 return NULL;
1131 }
1132
1133 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001134 jniThrowException(env, "java/lang/IllegalArgumentException",
1135 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001136 return NULL;
1137 }
1138
1139 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1140 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1141 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1142 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1143 Vector<uint8_t> output;
1144
1145 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001146 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1147 return NULL;
1148 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001149
1150 return VectorToJByteArray(env, output);
1151}
1152
1153static jbyteArray android_media_MediaDrm_signNative(
1154 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1155 jbyteArray jkeyId, jbyteArray jmessage) {
1156
1157 sp<IDrm> drm = GetDrm(env, jdrm);
1158
1159 if (!CheckSession(env, drm, jsessionId)) {
1160 return NULL;
1161 }
1162
1163 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001164 jniThrowException(env, "java/lang/IllegalArgumentException",
1165 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001166 return NULL;
1167 }
1168
1169 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1170 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1171 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1172 Vector<uint8_t> signature;
1173
1174 status_t err = drm->sign(sessionId, keyId, message, signature);
1175
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001176 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1177 return NULL;
1178 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001179
1180 return VectorToJByteArray(env, signature);
1181}
1182
1183static jboolean android_media_MediaDrm_verifyNative(
1184 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1185 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1186
1187 sp<IDrm> drm = GetDrm(env, jdrm);
1188
1189 if (!CheckSession(env, drm, jsessionId)) {
1190 return false;
1191 }
1192
1193 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001194 jniThrowException(env, "java/lang/IllegalArgumentException",
1195 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001196 return false;
1197 }
1198
1199 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1200 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1201 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1202 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1203 bool match;
1204
1205 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1206
1207 throwExceptionAsNecessary(env, err, "Failed to verify");
1208 return match;
1209}
1210
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001211
1212static JNINativeMethod gMethods[] = {
1213 { "release", "()V", (void *)android_media_MediaDrm_release },
1214 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1215
1216 { "native_setup", "(Ljava/lang/Object;[B)V",
1217 (void *)android_media_MediaDrm_native_setup },
1218
1219 { "native_finalize", "()V",
1220 (void *)android_media_MediaDrm_native_finalize },
1221
Jeff Tinker7cda4912013-08-21 11:52:34 -07001222 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001223 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1224
1225 { "openSession", "()[B",
1226 (void *)android_media_MediaDrm_openSession },
1227
1228 { "closeSession", "([B)V",
1229 (void *)android_media_MediaDrm_closeSession },
1230
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001231 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1232 "Landroid/media/MediaDrm$KeyRequest;",
1233 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001234
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001235 { "provideKeyResponse", "([B[B)[B",
1236 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001237
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001238 { "removeKeys", "([B)V",
1239 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001240
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001241 { "restoreKeys", "([B[B)V",
1242 (void *)android_media_MediaDrm_restoreKeys },
1243
1244 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1245 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001246
1247 { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
1248 (void *)android_media_MediaDrm_getProvisionRequest },
1249
1250 { "provideProvisionResponse", "([B)V",
1251 (void *)android_media_MediaDrm_provideProvisionResponse },
1252
1253 { "getSecureStops", "()Ljava/util/List;",
1254 (void *)android_media_MediaDrm_getSecureStops },
1255
1256 { "releaseSecureStops", "([B)V",
1257 (void *)android_media_MediaDrm_releaseSecureStops },
1258
1259 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1260 (void *)android_media_MediaDrm_getPropertyString },
1261
1262 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1263 (void *)android_media_MediaDrm_getPropertyByteArray },
1264
1265 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1266 (void *)android_media_MediaDrm_setPropertyString },
1267
1268 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1269 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001270
1271 { "setCipherAlgorithmNative",
1272 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1273 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1274
1275 { "setMacAlgorithmNative",
1276 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1277 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1278
1279 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1280 (void *)android_media_MediaDrm_encryptNative },
1281
1282 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1283 (void *)android_media_MediaDrm_decryptNative },
1284
1285 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1286 (void *)android_media_MediaDrm_signNative },
1287
1288 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1289 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001290};
1291
1292int register_android_media_Drm(JNIEnv *env) {
1293 return AndroidRuntime::registerNativeMethods(env,
1294 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1295}
1296