blob: 6d90ccb213b09fe863543b30ed08f93e1302cc0b [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);
189 }
190 }
191
192 if (env->ExceptionCheck()) {
193 ALOGW("An exception occurred while notifying an event.");
194 LOGW_EX(env);
195 env->ExceptionClear();
196 }
197}
198
199
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800200static bool throwExceptionAsNecessary(
201 JNIEnv *env, status_t err, const char *msg = NULL) {
202
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700203 const char *drmMessage = NULL;
204
205 switch(err) {
206 case ERROR_DRM_UNKNOWN:
207 drmMessage = "General DRM error";
208 break;
209 case ERROR_DRM_NO_LICENSE:
210 drmMessage = "No license";
211 break;
212 case ERROR_DRM_LICENSE_EXPIRED:
213 drmMessage = "License expired";
214 break;
215 case ERROR_DRM_SESSION_NOT_OPENED:
216 drmMessage = "Session not opened";
217 break;
218 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
219 drmMessage = "Not initialized";
220 break;
221 case ERROR_DRM_DECRYPT:
222 drmMessage = "Decrypt error";
223 break;
224 case ERROR_DRM_CANNOT_HANDLE:
225 drmMessage = "Unsupported scheme or data format";
226 break;
227 case ERROR_DRM_TAMPER_DETECTED:
228 drmMessage = "Invalid state";
229 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700230 default:
231 break;
232 }
233
234 String8 vendorMessage;
235 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
236 vendorMessage.format("DRM vendor-defined error: %d", err);
237 drmMessage = vendorMessage.string();
238 }
239
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800240 if (err == BAD_VALUE) {
241 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
242 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700243 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
244 jniThrowException(env, "android/media/NotProvisionedException", msg);
245 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700246 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
247 jniThrowException(env, "android/media/ResourceBusyException", msg);
248 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700249 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
250 jniThrowException(env, "android/media/DeniedByServerException", msg);
251 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800252 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700253 String8 errbuf;
254 if (drmMessage != NULL) {
255 if (msg == NULL) {
256 msg = drmMessage;
257 } else {
258 errbuf.format("%s: %s", msg, drmMessage);
259 msg = errbuf.string();
260 }
261 }
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700262 ALOGE("Illegal state exception: %s", msg);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800263 jniThrowException(env, "java/lang/IllegalStateException", msg);
264 return true;
265 }
266 return false;
267}
268
269static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000270 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800271 return jdrm ? jdrm->getDrm() : NULL;
272}
273
274JDrm::JDrm(
275 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
276 mObject = env->NewWeakGlobalRef(thiz);
277 mDrm = MakeDrm(uuid);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700278 if (mDrm != NULL) {
279 mDrm->setListener(this);
280 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800281}
282
283JDrm::~JDrm() {
284 mDrm.clear();
285
286 JNIEnv *env = AndroidRuntime::getJNIEnv();
287
288 env->DeleteWeakGlobalRef(mObject);
289 mObject = NULL;
290}
291
292// static
293sp<IDrm> JDrm::MakeDrm() {
294 sp<IServiceManager> sm = defaultServiceManager();
295
296 sp<IBinder> binder =
297 sm->getService(String16("media.player"));
298
299 sp<IMediaPlayerService> service =
300 interface_cast<IMediaPlayerService>(binder);
301
302 if (service == NULL) {
303 return NULL;
304 }
305
306 sp<IDrm> drm = service->makeDrm();
307
308 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
309 return NULL;
310 }
311
312 return drm;
313}
314
315// static
316sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
317 sp<IDrm> drm = MakeDrm();
318
319 if (drm == NULL) {
320 return NULL;
321 }
322
323 status_t err = drm->createPlugin(uuid);
324
325 if (err != OK) {
326 return NULL;
327 }
328
329 return drm;
330}
331
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700332status_t JDrm::setListener(const sp<DrmListener>& listener) {
333 Mutex::Autolock lock(mLock);
334 mListener = listener;
335 return OK;
336}
337
338void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
339 sp<DrmListener> listener;
340 mLock.lock();
341 listener = mListener;
342 mLock.unlock();
343
344 if (listener != NULL) {
345 Mutex::Autolock lock(mNotifyLock);
346 listener->notify(eventType, extra, obj);
347 }
348}
349
350
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800351// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700352bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800353 sp<IDrm> drm = MakeDrm();
354
355 if (drm == NULL) {
356 return false;
357 }
358
Jeff Tinker7cda4912013-08-21 11:52:34 -0700359 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800360}
361
362status_t JDrm::initCheck() const {
363 return mDrm == NULL ? NO_INIT : OK;
364}
365
366// JNI conversion utilities
367static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
368 Vector<uint8_t> vector;
369 size_t length = env->GetArrayLength(byteArray);
370 vector.insertAt((size_t)0, length);
371 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
372 return vector;
373}
374
375static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
376 size_t length = vector.size();
377 jbyteArray result = env->NewByteArray(length);
378 if (result != NULL) {
379 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
380 }
381 return result;
382}
383
384static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800385 String8 result;
386
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700387 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800388 if (s) {
389 result = s;
390 env->ReleaseStringUTFChars(jstr, s);
391 }
392 return result;
393}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700394
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800395/*
396 import java.util.HashMap;
397 import java.util.Set;
398 import java.Map.Entry;
399 import jav.util.Iterator;
400
401 HashMap<k, v> hm;
402 Set<Entry<k, v> > s = hm.entrySet();
403 Iterator i = s.iterator();
404 Entry e = s.next();
405*/
406
407static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
408 jclass clazz;
409 FIND_CLASS(clazz, "java/lang/String");
410 KeyedVector<String8, String8> keyedVector;
411
412 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
413 if (entrySet) {
414 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
415 if (iterator) {
416 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
417 while (hasNext) {
418 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
419 if (entry) {
420 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
421 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700422 jniThrowException(env, "java/lang/IllegalArgumentException",
423 "HashMap key is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800424 }
425 jstring jkey = static_cast<jstring>(obj);
426
427 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
428 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700429 jniThrowException(env, "java/lang/IllegalArgumentException",
430 "HashMap value is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800431 }
432 jstring jvalue = static_cast<jstring>(obj);
433
434 String8 key = JStringToString8(env, jkey);
435 String8 value = JStringToString8(env, jvalue);
436 keyedVector.add(key, value);
437
438 env->DeleteLocalRef(jkey);
439 env->DeleteLocalRef(jvalue);
440 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
441 }
442 env->DeleteLocalRef(entry);
443 }
444 env->DeleteLocalRef(iterator);
445 }
446 env->DeleteLocalRef(entrySet);
447 }
448 return keyedVector;
449}
450
451static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
452 jclass clazz;
453 FIND_CLASS(clazz, "java/util/HashMap");
454 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
455 for (size_t i = 0; i < map.size(); ++i) {
456 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
457 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
458 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
459 env->DeleteLocalRef(jkey);
460 env->DeleteLocalRef(jvalue);
461 }
462 return hashMap;
463}
464
465static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
466 List<Vector<uint8_t> > list) {
467 jclass clazz;
468 FIND_CLASS(clazz, "java/util/ArrayList");
469 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
470 List<Vector<uint8_t> >::iterator iter = list.begin();
471 while (iter != list.end()) {
472 jbyteArray byteArray = VectorToJByteArray(env, *iter);
473 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
474 env->DeleteLocalRef(byteArray);
475 iter++;
476 }
477
478 return arrayList;
479}
480
481} // namespace android
482
483using namespace android;
484
485static sp<JDrm> setDrm(
486 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000487 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800488 if (drm != NULL) {
489 drm->incStrong(thiz);
490 }
491 if (old != NULL) {
492 old->decStrong(thiz);
493 }
494 env->SetIntField(thiz, gFields.context, (int)drm.get());
495
496 return old;
497}
498
499static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
500{
501 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700502 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800503 return false;
504 }
505
506 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700507 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800508 return false;
509 }
510 return true;
511}
512
513static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700514 sp<JDrm> drm = setDrm(env, thiz, NULL);
515 if (drm != NULL) {
516 drm->setListener(NULL);
517 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800518}
519
520static void android_media_MediaDrm_native_init(JNIEnv *env) {
521 jclass clazz;
522 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000523 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700524 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
525 "(Ljava/lang/Object;IILjava/lang/Object;)V");
526
527 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700528 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700529 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700530 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700531 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700532 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700533 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700534 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700535 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800536
Jeff Tinker17b89222013-05-21 12:35:06 -0700537 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
538 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
539 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
540 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
541 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
542 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
543
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700544 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700545 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
546 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800547
548 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700549 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
550 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800551
552 FIND_CLASS(clazz, "java/util/ArrayList");
553 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
554 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
555
556 FIND_CLASS(clazz, "java/util/HashMap");
557 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
558 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
559 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
560 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
561 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
562
563 FIND_CLASS(clazz, "java/util/Set");
564 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
565
566 FIND_CLASS(clazz, "java/util/Iterator");
567 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
568 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
569
570 FIND_CLASS(clazz, "java/util/Map$Entry");
571 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
572 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
573}
574
575static void android_media_MediaDrm_native_setup(
576 JNIEnv *env, jobject thiz,
577 jobject weak_this, jbyteArray uuidObj) {
578
579 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700580 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800581 return;
582 }
583
584 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
585
586 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700587 jniThrowException(env, "java/lang/IllegalArgumentException",
588 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800589 return;
590 }
591
592 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
593
594 status_t err = drm->initCheck();
595
596 if (err != OK) {
597 jniThrowException(
598 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700599 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800600 "Failed to instantiate drm object.");
601 return;
602 }
603
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700604 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
605 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800606 setDrm(env, thiz, drm);
607}
608
609static void android_media_MediaDrm_native_finalize(
610 JNIEnv *env, jobject thiz) {
611 android_media_MediaDrm_release(env, thiz);
612}
613
614static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinker7cda4912013-08-21 11:52:34 -0700615 JNIEnv *env, jobject thiz, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800616
617 if (uuidObj == NULL) {
618 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
619 return false;
620 }
621
622 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
623
624 if (uuid.size() != 16) {
625 jniThrowException(
626 env,
627 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700628 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800629 return false;
630 }
631
Jeff Tinker7cda4912013-08-21 11:52:34 -0700632 String8 mimeType;
633 if (jmimeType != NULL) {
634 mimeType = JStringToString8(env, jmimeType);
635 }
636
637 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800638}
639
640static jbyteArray android_media_MediaDrm_openSession(
641 JNIEnv *env, jobject thiz) {
642 sp<IDrm> drm = GetDrm(env, thiz);
643
644 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700645 jniThrowException(env, "java/lang/IllegalStateException",
646 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800647 return NULL;
648 }
649
650 Vector<uint8_t> sessionId;
651 status_t err = drm->openSession(sessionId);
652
653 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
654 return NULL;
655 }
656
657 return VectorToJByteArray(env, sessionId);
658}
659
660static void android_media_MediaDrm_closeSession(
661 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
662 sp<IDrm> drm = GetDrm(env, thiz);
663
664 if (!CheckSession(env, drm, jsessionId)) {
665 return;
666 }
667
668 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
669
670 status_t err = drm->closeSession(sessionId);
671
672 throwExceptionAsNecessary(env, err, "Failed to close session");
673}
674
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700675static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800676 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700677 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800678 sp<IDrm> drm = GetDrm(env, thiz);
679
680 if (!CheckSession(env, drm, jsessionId)) {
681 return NULL;
682 }
683
684 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
685
686 Vector<uint8_t> initData;
687 if (jinitData != NULL) {
688 initData = JByteArrayToVector(env, jinitData);
689 }
690
691 String8 mimeType;
692 if (jmimeType != NULL) {
693 mimeType = JStringToString8(env, jmimeType);
694 }
695
Jeff Tinker17b89222013-05-21 12:35:06 -0700696 DrmPlugin::KeyType keyType;
697 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
698 keyType = DrmPlugin::kKeyType_Streaming;
699 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
700 keyType = DrmPlugin::kKeyType_Offline;
701 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
702 keyType = DrmPlugin::kKeyType_Release;
703 } else {
704 jniThrowException(env, "java/lang/IllegalArgumentException",
705 "invalid keyType");
706 return NULL;
707 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800708
709 KeyedVector<String8, String8> optParams;
710 if (joptParams != NULL) {
711 optParams = HashMapToKeyedVector(env, joptParams);
712 }
713
714 Vector<uint8_t> request;
715 String8 defaultUrl;
716
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700717 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
718 keyType, optParams, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800719
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700720 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800721 return NULL;
722 }
723
724 // Fill out return obj
725 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700726 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800727
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700728 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800729
730 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700731 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800732 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700733 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800734
735 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700736 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800737 }
738
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700739 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800740}
741
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700742static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800743 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
744 sp<IDrm> drm = GetDrm(env, thiz);
745
746 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700747 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800748 }
749
750 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
751
752 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700753 jniThrowException(env, "java/lang/IllegalArgumentException",
754 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700755 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800756 }
757 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700758 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800759
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700760 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800761
Jeff Tinker8117d8f2013-08-16 13:46:02 -0700762 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
763 return NULL;
764 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700765 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800766}
767
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700768static void android_media_MediaDrm_removeKeys(
769 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
770 sp<IDrm> drm = GetDrm(env, thiz);
771
772 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700773 jniThrowException(env, "java/lang/IllegalArgumentException",
774 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700775 return;
776 }
777
778 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
779
780 status_t err = drm->removeKeys(keySetId);
781
782 throwExceptionAsNecessary(env, err, "Failed to remove keys");
783}
784
785static void android_media_MediaDrm_restoreKeys(
786 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
787 jbyteArray jkeysetId) {
788
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800789 sp<IDrm> drm = GetDrm(env, thiz);
790
791 if (!CheckSession(env, drm, jsessionId)) {
792 return;
793 }
794
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700795 if (jkeysetId == NULL) {
796 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
797 return;
798 }
799
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800800 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700801 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800802
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700803 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800804
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700805 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800806}
807
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700808static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800809 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
810 sp<IDrm> drm = GetDrm(env, thiz);
811
812 if (!CheckSession(env, drm, jsessionId)) {
813 return NULL;
814 }
815 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
816
817 KeyedVector<String8, String8> infoMap;
818
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700819 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800820
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700821 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800822 return NULL;
823 }
824
825 return KeyedVectorToHashMap(env, infoMap);
826}
827
828static jobject android_media_MediaDrm_getProvisionRequest(
829 JNIEnv *env, jobject thiz) {
830 sp<IDrm> drm = GetDrm(env, thiz);
831
832 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700833 jniThrowException(env, "java/lang/IllegalStateException",
834 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800835 return NULL;
836 }
837
838 Vector<uint8_t> request;
839 String8 defaultUrl;
840
841 status_t err = drm->getProvisionRequest(request, defaultUrl);
842
843 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
844 return NULL;
845 }
846
847 // Fill out return obj
848 jclass clazz;
849 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
850
851 jobject provisionObj = NULL;
852
853 if (clazz) {
854 provisionObj = env->AllocObject(clazz);
855 jbyteArray jrequest = VectorToJByteArray(env, request);
856 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
857
858 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
859 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
860 }
861
862 return provisionObj;
863}
864
865static void android_media_MediaDrm_provideProvisionResponse(
866 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
867 sp<IDrm> drm = GetDrm(env, thiz);
868
869 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700870 jniThrowException(env, "java/lang/IllegalStateException",
871 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800872 return;
873 }
874
875 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700876 jniThrowException(env, "java/lang/IllegalArgumentException",
877 "provision response is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800878 return;
879 }
880
881 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
882
883 status_t err = drm->provideProvisionResponse(response);
884
885 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
886}
887
888static jobject android_media_MediaDrm_getSecureStops(
889 JNIEnv *env, jobject thiz) {
890 sp<IDrm> drm = GetDrm(env, thiz);
891
892 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700893 jniThrowException(env, "java/lang/IllegalStateException",
894 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800895 return NULL;
896 }
897
898 List<Vector<uint8_t> > secureStops;
899
900 status_t err = drm->getSecureStops(secureStops);
901
902 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
903 return NULL;
904 }
905
906 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
907}
908
909static void android_media_MediaDrm_releaseSecureStops(
910 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
911 sp<IDrm> drm = GetDrm(env, thiz);
912
913 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700914 jniThrowException(env, "java/lang/IllegalStateException",
915 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800916 return;
917 }
918
919 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
920
921 status_t err = drm->releaseSecureStops(ssRelease);
922
923 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
924}
925
926static jstring android_media_MediaDrm_getPropertyString(
927 JNIEnv *env, jobject thiz, jstring jname) {
928 sp<IDrm> drm = GetDrm(env, thiz);
929
930 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700931 jniThrowException(env, "java/lang/IllegalStateException",
932 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800933 return NULL;
934 }
935
936 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700937 jniThrowException(env, "java/lang/IllegalArgumentException",
938 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800939 return NULL;
940 }
941
942 String8 name = JStringToString8(env, jname);
943 String8 value;
944
945 status_t err = drm->getPropertyString(name, value);
946
947 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
948 return NULL;
949 }
950
951 return env->NewStringUTF(value.string());
952}
953
954static jbyteArray android_media_MediaDrm_getPropertyByteArray(
955 JNIEnv *env, jobject thiz, jstring jname) {
956 sp<IDrm> drm = GetDrm(env, thiz);
957
958 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700959 jniThrowException(env, "java/lang/IllegalStateException",
960 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800961 return NULL;
962 }
963
964 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700965 jniThrowException(env, "java/lang/IllegalArgumentException",
966 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800967 return NULL;
968 }
969
970 String8 name = JStringToString8(env, jname);
971 Vector<uint8_t> value;
972
973 status_t err = drm->getPropertyByteArray(name, value);
974
975 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
976 return NULL;
977 }
978
979 return VectorToJByteArray(env, value);
980}
981
982static void android_media_MediaDrm_setPropertyString(
983 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
984 sp<IDrm> drm = GetDrm(env, thiz);
985
986 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700987 jniThrowException(env, "java/lang/IllegalStateException",
988 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800989 return;
990 }
991
Jeff Tinkereada5372013-05-21 12:48:14 -0700992 if (jname == NULL) {
993 jniThrowException(env, "java/lang/IllegalArgumentException",
994 "property name String is null");
995 return;
996 }
997
998 if (jvalue == NULL) {
999 jniThrowException(env, "java/lang/IllegalArgumentException",
1000 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001001 return;
1002 }
1003
1004 String8 name = JStringToString8(env, jname);
1005 String8 value = JStringToString8(env, jvalue);
1006
1007 status_t err = drm->setPropertyString(name, value);
1008
1009 throwExceptionAsNecessary(env, err, "Failed to set property");
1010}
1011
1012static void android_media_MediaDrm_setPropertyByteArray(
1013 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1014 sp<IDrm> drm = GetDrm(env, thiz);
1015
1016 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001017 jniThrowException(env, "java/lang/IllegalStateException",
1018 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001019 return;
1020 }
1021
Jeff Tinkereada5372013-05-21 12:48:14 -07001022 if (jname == NULL) {
1023 jniThrowException(env, "java/lang/IllegalArgumentException",
1024 "property name String is null");
1025 return;
1026 }
1027
1028 if (jvalue == NULL) {
1029 jniThrowException(env, "java/lang/IllegalArgumentException",
1030 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001031 return;
1032 }
1033
1034 String8 name = JStringToString8(env, jname);
1035 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1036
1037 status_t err = drm->setPropertyByteArray(name, value);
1038
1039 throwExceptionAsNecessary(env, err, "Failed to set property");
1040}
1041
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001042static void android_media_MediaDrm_setCipherAlgorithmNative(
1043 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1044 jstring jalgorithm) {
1045
1046 sp<IDrm> drm = GetDrm(env, jdrm);
1047
1048 if (!CheckSession(env, drm, jsessionId)) {
1049 return;
1050 }
1051
1052 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001053 jniThrowException(env, "java/lang/IllegalArgumentException",
1054 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001055 return;
1056 }
1057
1058 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1059 String8 algorithm = JStringToString8(env, jalgorithm);
1060
1061 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1062
1063 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1064}
1065
1066static void android_media_MediaDrm_setMacAlgorithmNative(
1067 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1068 jstring jalgorithm) {
1069
1070 sp<IDrm> drm = GetDrm(env, jdrm);
1071
1072 if (!CheckSession(env, drm, jsessionId)) {
1073 return;
1074 }
1075
1076 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001077 jniThrowException(env, "java/lang/IllegalArgumentException",
1078 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001079 return;
1080 }
1081
1082 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1083 String8 algorithm = JStringToString8(env, jalgorithm);
1084
1085 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1086
1087 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1088}
1089
1090
1091static jbyteArray android_media_MediaDrm_encryptNative(
1092 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1093 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1094
1095 sp<IDrm> drm = GetDrm(env, jdrm);
1096
1097 if (!CheckSession(env, drm, jsessionId)) {
1098 return NULL;
1099 }
1100
1101 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001102 jniThrowException(env, "java/lang/IllegalArgumentException",
1103 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001104 return NULL;
1105 }
1106
1107 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1108 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1109 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1110 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1111 Vector<uint8_t> output;
1112
1113 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1114
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001115 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1116 return NULL;
1117 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001118
1119 return VectorToJByteArray(env, output);
1120}
1121
1122static jbyteArray android_media_MediaDrm_decryptNative(
1123 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1124 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1125
1126 sp<IDrm> drm = GetDrm(env, jdrm);
1127
1128 if (!CheckSession(env, drm, jsessionId)) {
1129 return NULL;
1130 }
1131
1132 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001133 jniThrowException(env, "java/lang/IllegalArgumentException",
1134 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001135 return NULL;
1136 }
1137
1138 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1139 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1140 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1141 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1142 Vector<uint8_t> output;
1143
1144 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001145 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1146 return NULL;
1147 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001148
1149 return VectorToJByteArray(env, output);
1150}
1151
1152static jbyteArray android_media_MediaDrm_signNative(
1153 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1154 jbyteArray jkeyId, jbyteArray jmessage) {
1155
1156 sp<IDrm> drm = GetDrm(env, jdrm);
1157
1158 if (!CheckSession(env, drm, jsessionId)) {
1159 return NULL;
1160 }
1161
1162 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001163 jniThrowException(env, "java/lang/IllegalArgumentException",
1164 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001165 return NULL;
1166 }
1167
1168 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1169 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1170 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1171 Vector<uint8_t> signature;
1172
1173 status_t err = drm->sign(sessionId, keyId, message, signature);
1174
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001175 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1176 return NULL;
1177 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001178
1179 return VectorToJByteArray(env, signature);
1180}
1181
1182static jboolean android_media_MediaDrm_verifyNative(
1183 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1184 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1185
1186 sp<IDrm> drm = GetDrm(env, jdrm);
1187
1188 if (!CheckSession(env, drm, jsessionId)) {
1189 return false;
1190 }
1191
1192 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001193 jniThrowException(env, "java/lang/IllegalArgumentException",
1194 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001195 return false;
1196 }
1197
1198 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1199 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1200 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1201 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1202 bool match;
1203
1204 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1205
1206 throwExceptionAsNecessary(env, err, "Failed to verify");
1207 return match;
1208}
1209
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001210
1211static JNINativeMethod gMethods[] = {
1212 { "release", "()V", (void *)android_media_MediaDrm_release },
1213 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1214
1215 { "native_setup", "(Ljava/lang/Object;[B)V",
1216 (void *)android_media_MediaDrm_native_setup },
1217
1218 { "native_finalize", "()V",
1219 (void *)android_media_MediaDrm_native_finalize },
1220
Jeff Tinker7cda4912013-08-21 11:52:34 -07001221 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001222 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1223
1224 { "openSession", "()[B",
1225 (void *)android_media_MediaDrm_openSession },
1226
1227 { "closeSession", "([B)V",
1228 (void *)android_media_MediaDrm_closeSession },
1229
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001230 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1231 "Landroid/media/MediaDrm$KeyRequest;",
1232 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001233
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001234 { "provideKeyResponse", "([B[B)[B",
1235 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001236
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001237 { "removeKeys", "([B)V",
1238 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001239
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001240 { "restoreKeys", "([B[B)V",
1241 (void *)android_media_MediaDrm_restoreKeys },
1242
1243 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1244 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001245
1246 { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
1247 (void *)android_media_MediaDrm_getProvisionRequest },
1248
1249 { "provideProvisionResponse", "([B)V",
1250 (void *)android_media_MediaDrm_provideProvisionResponse },
1251
1252 { "getSecureStops", "()Ljava/util/List;",
1253 (void *)android_media_MediaDrm_getSecureStops },
1254
1255 { "releaseSecureStops", "([B)V",
1256 (void *)android_media_MediaDrm_releaseSecureStops },
1257
1258 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1259 (void *)android_media_MediaDrm_getPropertyString },
1260
1261 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1262 (void *)android_media_MediaDrm_getPropertyByteArray },
1263
1264 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1265 (void *)android_media_MediaDrm_setPropertyString },
1266
1267 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1268 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001269
1270 { "setCipherAlgorithmNative",
1271 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1272 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1273
1274 { "setMacAlgorithmNative",
1275 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1276 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1277
1278 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1279 (void *)android_media_MediaDrm_encryptNative },
1280
1281 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1282 (void *)android_media_MediaDrm_decryptNative },
1283
1284 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1285 (void *)android_media_MediaDrm_signNative },
1286
1287 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1288 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001289};
1290
1291int register_android_media_Drm(JNIEnv *env) {
1292 return AndroidRuntime::registerNativeMethods(env,
1293 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1294}
1295