blob: 1618edf2b34cbb4652e5cedf7d0a9e75dfb39a78 [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"
24#include "jni.h"
25#include "JNIHelp.h"
26
27#include <binder/IServiceManager.h>
28#include <media/IDrm.h>
29#include <media/IMediaPlayerService.h>
30#include <media/stagefright/foundation/ADebug.h>
31
32namespace android {
33
34#define FIND_CLASS(var, className) \
35 var = env->FindClass(className); \
36 LOG_FATAL_IF(! var, "Unable to find class " className);
37
38#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
39 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
40 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
41
42#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
43 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
44 LOG_FATAL_IF(! var, "Unable to find method " fieldName);
45
46struct RequestFields {
47 jfieldID data;
48 jfieldID defaultUrl;
49};
50
51struct ArrayListFields {
52 jmethodID init;
53 jmethodID add;
54};
55
56struct HashmapFields {
57 jmethodID init;
58 jmethodID get;
59 jmethodID put;
60 jmethodID entrySet;
61};
62
63struct SetFields {
64 jmethodID iterator;
65};
66
67struct IteratorFields {
68 jmethodID next;
69 jmethodID hasNext;
70};
71
72struct EntryFields {
73 jmethodID getKey;
74 jmethodID getValue;
75};
76
77struct fields_t {
78 jfieldID context;
Jeff Tinker16b8cff2013-03-30 16:26:13 -070079 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080080 RequestFields provisionRequest;
81 ArrayListFields arraylist;
82 HashmapFields hashmap;
83 SetFields set;
84 IteratorFields iterator;
85 EntryFields entry;
86};
87
88static fields_t gFields;
89
90static bool throwExceptionAsNecessary(
91 JNIEnv *env, status_t err, const char *msg = NULL) {
92
93 if (err == BAD_VALUE) {
94 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
95 return true;
96 } else if (err != OK) {
97 jniThrowException(env, "java/lang/IllegalStateException", msg);
98 return true;
99 }
100 return false;
101}
102
103static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
104 JDrm *jdrm = (JDrm *)env->GetIntField(thiz, gFields.context);
105 return jdrm ? jdrm->getDrm() : NULL;
106}
107
108JDrm::JDrm(
109 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
110 mObject = env->NewWeakGlobalRef(thiz);
111 mDrm = MakeDrm(uuid);
112}
113
114JDrm::~JDrm() {
115 mDrm.clear();
116
117 JNIEnv *env = AndroidRuntime::getJNIEnv();
118
119 env->DeleteWeakGlobalRef(mObject);
120 mObject = NULL;
121}
122
123// static
124sp<IDrm> JDrm::MakeDrm() {
125 sp<IServiceManager> sm = defaultServiceManager();
126
127 sp<IBinder> binder =
128 sm->getService(String16("media.player"));
129
130 sp<IMediaPlayerService> service =
131 interface_cast<IMediaPlayerService>(binder);
132
133 if (service == NULL) {
134 return NULL;
135 }
136
137 sp<IDrm> drm = service->makeDrm();
138
139 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
140 return NULL;
141 }
142
143 return drm;
144}
145
146// static
147sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
148 sp<IDrm> drm = MakeDrm();
149
150 if (drm == NULL) {
151 return NULL;
152 }
153
154 status_t err = drm->createPlugin(uuid);
155
156 if (err != OK) {
157 return NULL;
158 }
159
160 return drm;
161}
162
163// static
164bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
165 sp<IDrm> drm = MakeDrm();
166
167 if (drm == NULL) {
168 return false;
169 }
170
171 return drm->isCryptoSchemeSupported(uuid);
172}
173
174status_t JDrm::initCheck() const {
175 return mDrm == NULL ? NO_INIT : OK;
176}
177
178// JNI conversion utilities
179static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
180 Vector<uint8_t> vector;
181 size_t length = env->GetArrayLength(byteArray);
182 vector.insertAt((size_t)0, length);
183 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
184 return vector;
185}
186
187static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
188 size_t length = vector.size();
189 jbyteArray result = env->NewByteArray(length);
190 if (result != NULL) {
191 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
192 }
193 return result;
194}
195
196static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
197 jboolean isCopy;
198 String8 result;
199
200 const char *s = env->GetStringUTFChars(jstr, &isCopy);
201 if (s) {
202 result = s;
203 env->ReleaseStringUTFChars(jstr, s);
204 }
205 return result;
206}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700207
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800208/*
209 import java.util.HashMap;
210 import java.util.Set;
211 import java.Map.Entry;
212 import jav.util.Iterator;
213
214 HashMap<k, v> hm;
215 Set<Entry<k, v> > s = hm.entrySet();
216 Iterator i = s.iterator();
217 Entry e = s.next();
218*/
219
220static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
221 jclass clazz;
222 FIND_CLASS(clazz, "java/lang/String");
223 KeyedVector<String8, String8> keyedVector;
224
225 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
226 if (entrySet) {
227 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
228 if (iterator) {
229 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
230 while (hasNext) {
231 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
232 if (entry) {
233 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
234 if (!env->IsInstanceOf(obj, clazz)) {
235 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
236 }
237 jstring jkey = static_cast<jstring>(obj);
238
239 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
240 if (!env->IsInstanceOf(obj, clazz)) {
241 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
242 }
243 jstring jvalue = static_cast<jstring>(obj);
244
245 String8 key = JStringToString8(env, jkey);
246 String8 value = JStringToString8(env, jvalue);
247 keyedVector.add(key, value);
248
249 env->DeleteLocalRef(jkey);
250 env->DeleteLocalRef(jvalue);
251 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
252 }
253 env->DeleteLocalRef(entry);
254 }
255 env->DeleteLocalRef(iterator);
256 }
257 env->DeleteLocalRef(entrySet);
258 }
259 return keyedVector;
260}
261
262static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
263 jclass clazz;
264 FIND_CLASS(clazz, "java/util/HashMap");
265 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
266 for (size_t i = 0; i < map.size(); ++i) {
267 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
268 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
269 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
270 env->DeleteLocalRef(jkey);
271 env->DeleteLocalRef(jvalue);
272 }
273 return hashMap;
274}
275
276static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
277 List<Vector<uint8_t> > list) {
278 jclass clazz;
279 FIND_CLASS(clazz, "java/util/ArrayList");
280 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
281 List<Vector<uint8_t> >::iterator iter = list.begin();
282 while (iter != list.end()) {
283 jbyteArray byteArray = VectorToJByteArray(env, *iter);
284 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
285 env->DeleteLocalRef(byteArray);
286 iter++;
287 }
288
289 return arrayList;
290}
291
292} // namespace android
293
294using namespace android;
295
296static sp<JDrm> setDrm(
297 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
298 sp<JDrm> old = (JDrm *)env->GetIntField(thiz, gFields.context);
299 if (drm != NULL) {
300 drm->incStrong(thiz);
301 }
302 if (old != NULL) {
303 old->decStrong(thiz);
304 }
305 env->SetIntField(thiz, gFields.context, (int)drm.get());
306
307 return old;
308}
309
310static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
311{
312 if (drm == NULL) {
313 jniThrowException(env, "java/lang/IllegalStateException", NULL);
314 return false;
315 }
316
317 if (jsessionId == NULL) {
318 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
319 return false;
320 }
321 return true;
322}
323
324static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
325 setDrm(env, thiz, NULL);
326}
327
328static void android_media_MediaDrm_native_init(JNIEnv *env) {
329 jclass clazz;
330 FIND_CLASS(clazz, "android/media/MediaDrm");
331 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
332
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700333 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
334 GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
335 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800336
337 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
338 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B");
339 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
340
341 FIND_CLASS(clazz, "java/util/ArrayList");
342 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
343 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
344
345 FIND_CLASS(clazz, "java/util/HashMap");
346 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
347 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
348 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
349 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
350 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
351
352 FIND_CLASS(clazz, "java/util/Set");
353 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
354
355 FIND_CLASS(clazz, "java/util/Iterator");
356 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
357 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
358
359 FIND_CLASS(clazz, "java/util/Map$Entry");
360 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
361 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
362}
363
364static void android_media_MediaDrm_native_setup(
365 JNIEnv *env, jobject thiz,
366 jobject weak_this, jbyteArray uuidObj) {
367
368 if (uuidObj == NULL) {
369 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
370 return;
371 }
372
373 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
374
375 if (uuid.size() != 16) {
376 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
377 return;
378 }
379
380 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
381
382 status_t err = drm->initCheck();
383
384 if (err != OK) {
385 jniThrowException(
386 env,
387 "android/media/MediaDrmException",
388 "Failed to instantiate drm object.");
389 return;
390 }
391
392 setDrm(env, thiz, drm);
393}
394
395static void android_media_MediaDrm_native_finalize(
396 JNIEnv *env, jobject thiz) {
397 android_media_MediaDrm_release(env, thiz);
398}
399
400static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
401 JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
402
403 if (uuidObj == NULL) {
404 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
405 return false;
406 }
407
408 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
409
410 if (uuid.size() != 16) {
411 jniThrowException(
412 env,
413 "java/lang/IllegalArgumentException",
414 NULL);
415 return false;
416 }
417
418 return JDrm::IsCryptoSchemeSupported(uuid.array());
419}
420
421static jbyteArray android_media_MediaDrm_openSession(
422 JNIEnv *env, jobject thiz) {
423 sp<IDrm> drm = GetDrm(env, thiz);
424
425 if (drm == NULL) {
426 jniThrowException(env, "java/lang/IllegalStateException", NULL);
427 return NULL;
428 }
429
430 Vector<uint8_t> sessionId;
431 status_t err = drm->openSession(sessionId);
432
433 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
434 return NULL;
435 }
436
437 return VectorToJByteArray(env, sessionId);
438}
439
440static void android_media_MediaDrm_closeSession(
441 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
442 sp<IDrm> drm = GetDrm(env, thiz);
443
444 if (!CheckSession(env, drm, jsessionId)) {
445 return;
446 }
447
448 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
449
450 status_t err = drm->closeSession(sessionId);
451
452 throwExceptionAsNecessary(env, err, "Failed to close session");
453}
454
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700455static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800456 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700457 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800458 sp<IDrm> drm = GetDrm(env, thiz);
459
460 if (!CheckSession(env, drm, jsessionId)) {
461 return NULL;
462 }
463
464 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
465
466 Vector<uint8_t> initData;
467 if (jinitData != NULL) {
468 initData = JByteArrayToVector(env, jinitData);
469 }
470
471 String8 mimeType;
472 if (jmimeType != NULL) {
473 mimeType = JStringToString8(env, jmimeType);
474 }
475
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700476 DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)jkeyType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800477
478 KeyedVector<String8, String8> optParams;
479 if (joptParams != NULL) {
480 optParams = HashMapToKeyedVector(env, joptParams);
481 }
482
483 Vector<uint8_t> request;
484 String8 defaultUrl;
485
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700486 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
487 keyType, optParams, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800488
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700489 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800490 return NULL;
491 }
492
493 // Fill out return obj
494 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700495 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800496
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700497 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800498
499 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700500 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800501 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700502 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800503
504 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700505 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800506 }
507
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700508 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800509}
510
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700511static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800512 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
513 sp<IDrm> drm = GetDrm(env, thiz);
514
515 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700516 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800517 }
518
519 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
520
521 if (jresponse == NULL) {
522 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700523 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800524 }
525 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700526 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800527
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700528 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800529
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700530 throwExceptionAsNecessary(env, err, "Failed to handle key response");
531 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800532}
533
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700534static void android_media_MediaDrm_removeKeys(
535 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
536 sp<IDrm> drm = GetDrm(env, thiz);
537
538 if (jkeysetId == NULL) {
539 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
540 return;
541 }
542
543 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
544
545 status_t err = drm->removeKeys(keySetId);
546
547 throwExceptionAsNecessary(env, err, "Failed to remove keys");
548}
549
550static void android_media_MediaDrm_restoreKeys(
551 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
552 jbyteArray jkeysetId) {
553
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800554 sp<IDrm> drm = GetDrm(env, thiz);
555
556 if (!CheckSession(env, drm, jsessionId)) {
557 return;
558 }
559
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700560 if (jkeysetId == NULL) {
561 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
562 return;
563 }
564
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800565 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700566 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800567
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700568 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800569
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700570 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800571}
572
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700573static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800574 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
575 sp<IDrm> drm = GetDrm(env, thiz);
576
577 if (!CheckSession(env, drm, jsessionId)) {
578 return NULL;
579 }
580 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
581
582 KeyedVector<String8, String8> infoMap;
583
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700584 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800585
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700586 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800587 return NULL;
588 }
589
590 return KeyedVectorToHashMap(env, infoMap);
591}
592
593static jobject android_media_MediaDrm_getProvisionRequest(
594 JNIEnv *env, jobject thiz) {
595 sp<IDrm> drm = GetDrm(env, thiz);
596
597 if (drm == NULL) {
598 jniThrowException(env, "java/lang/IllegalStateException", NULL);
599 return NULL;
600 }
601
602 Vector<uint8_t> request;
603 String8 defaultUrl;
604
605 status_t err = drm->getProvisionRequest(request, defaultUrl);
606
607 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
608 return NULL;
609 }
610
611 // Fill out return obj
612 jclass clazz;
613 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
614
615 jobject provisionObj = NULL;
616
617 if (clazz) {
618 provisionObj = env->AllocObject(clazz);
619 jbyteArray jrequest = VectorToJByteArray(env, request);
620 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
621
622 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
623 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
624 }
625
626 return provisionObj;
627}
628
629static void android_media_MediaDrm_provideProvisionResponse(
630 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
631 sp<IDrm> drm = GetDrm(env, thiz);
632
633 if (drm == NULL) {
634 jniThrowException(env, "java/lang/IllegalStateException", NULL);
635 return;
636 }
637
638 if (jresponse == NULL) {
639 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
640 return;
641 }
642
643 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
644
645 status_t err = drm->provideProvisionResponse(response);
646
647 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
648}
649
650static jobject android_media_MediaDrm_getSecureStops(
651 JNIEnv *env, jobject thiz) {
652 sp<IDrm> drm = GetDrm(env, thiz);
653
654 if (drm == NULL) {
655 jniThrowException(env, "java/lang/IllegalStateException", NULL);
656 return NULL;
657 }
658
659 List<Vector<uint8_t> > secureStops;
660
661 status_t err = drm->getSecureStops(secureStops);
662
663 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
664 return NULL;
665 }
666
667 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
668}
669
670static void android_media_MediaDrm_releaseSecureStops(
671 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
672 sp<IDrm> drm = GetDrm(env, thiz);
673
674 if (drm == NULL) {
675 jniThrowException(env, "java/lang/IllegalStateException", NULL);
676 return;
677 }
678
679 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
680
681 status_t err = drm->releaseSecureStops(ssRelease);
682
683 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
684}
685
686static jstring android_media_MediaDrm_getPropertyString(
687 JNIEnv *env, jobject thiz, jstring jname) {
688 sp<IDrm> drm = GetDrm(env, thiz);
689
690 if (drm == NULL) {
691 jniThrowException(env, "java/lang/IllegalStateException", NULL);
692 return NULL;
693 }
694
695 if (jname == NULL) {
696 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
697 return NULL;
698 }
699
700 String8 name = JStringToString8(env, jname);
701 String8 value;
702
703 status_t err = drm->getPropertyString(name, value);
704
705 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
706 return NULL;
707 }
708
709 return env->NewStringUTF(value.string());
710}
711
712static jbyteArray android_media_MediaDrm_getPropertyByteArray(
713 JNIEnv *env, jobject thiz, jstring jname) {
714 sp<IDrm> drm = GetDrm(env, thiz);
715
716 if (drm == NULL) {
717 jniThrowException(env, "java/lang/IllegalStateException", NULL);
718 return NULL;
719 }
720
721 if (jname == NULL) {
722 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
723 return NULL;
724 }
725
726 String8 name = JStringToString8(env, jname);
727 Vector<uint8_t> value;
728
729 status_t err = drm->getPropertyByteArray(name, value);
730
731 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
732 return NULL;
733 }
734
735 return VectorToJByteArray(env, value);
736}
737
738static void android_media_MediaDrm_setPropertyString(
739 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
740 sp<IDrm> drm = GetDrm(env, thiz);
741
742 if (drm == NULL) {
743 jniThrowException(env, "java/lang/IllegalStateException", NULL);
744 return;
745 }
746
747 if (jname == NULL || jvalue == NULL) {
748 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
749 return;
750 }
751
752 String8 name = JStringToString8(env, jname);
753 String8 value = JStringToString8(env, jvalue);
754
755 status_t err = drm->setPropertyString(name, value);
756
757 throwExceptionAsNecessary(env, err, "Failed to set property");
758}
759
760static void android_media_MediaDrm_setPropertyByteArray(
761 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
762 sp<IDrm> drm = GetDrm(env, thiz);
763
764 if (drm == NULL) {
765 jniThrowException(env, "java/lang/IllegalStateException", NULL);
766 return;
767 }
768
769 if (jname == NULL || jvalue == NULL) {
770 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
771 return;
772 }
773
774 String8 name = JStringToString8(env, jname);
775 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
776
777 status_t err = drm->setPropertyByteArray(name, value);
778
779 throwExceptionAsNecessary(env, err, "Failed to set property");
780}
781
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700782static void android_media_MediaDrm_setCipherAlgorithmNative(
783 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
784 jstring jalgorithm) {
785
786 sp<IDrm> drm = GetDrm(env, jdrm);
787
788 if (!CheckSession(env, drm, jsessionId)) {
789 return;
790 }
791
792 if (jalgorithm == NULL) {
793 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
794 return;
795 }
796
797 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
798 String8 algorithm = JStringToString8(env, jalgorithm);
799
800 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
801
802 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
803}
804
805static void android_media_MediaDrm_setMacAlgorithmNative(
806 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
807 jstring jalgorithm) {
808
809 sp<IDrm> drm = GetDrm(env, jdrm);
810
811 if (!CheckSession(env, drm, jsessionId)) {
812 return;
813 }
814
815 if (jalgorithm == NULL) {
816 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
817 return;
818 }
819
820 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
821 String8 algorithm = JStringToString8(env, jalgorithm);
822
823 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
824
825 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
826}
827
828
829static jbyteArray android_media_MediaDrm_encryptNative(
830 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
831 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
832
833 sp<IDrm> drm = GetDrm(env, jdrm);
834
835 if (!CheckSession(env, drm, jsessionId)) {
836 return NULL;
837 }
838
839 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
840 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
841 return NULL;
842 }
843
844 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
845 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
846 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
847 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
848 Vector<uint8_t> output;
849
850 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
851
852 throwExceptionAsNecessary(env, err, "Failed to encrypt");
853
854 return VectorToJByteArray(env, output);
855}
856
857static jbyteArray android_media_MediaDrm_decryptNative(
858 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
859 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
860
861 sp<IDrm> drm = GetDrm(env, jdrm);
862
863 if (!CheckSession(env, drm, jsessionId)) {
864 return NULL;
865 }
866
867 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
868 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
869 return NULL;
870 }
871
872 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
873 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
874 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
875 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
876 Vector<uint8_t> output;
877
878 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
879 throwExceptionAsNecessary(env, err, "Failed to decrypt");
880
881 return VectorToJByteArray(env, output);
882}
883
884static jbyteArray android_media_MediaDrm_signNative(
885 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
886 jbyteArray jkeyId, jbyteArray jmessage) {
887
888 sp<IDrm> drm = GetDrm(env, jdrm);
889
890 if (!CheckSession(env, drm, jsessionId)) {
891 return NULL;
892 }
893
894 if (jkeyId == NULL || jmessage == NULL) {
895 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
896 return NULL;
897 }
898
899 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
900 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
901 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
902 Vector<uint8_t> signature;
903
904 status_t err = drm->sign(sessionId, keyId, message, signature);
905
906 throwExceptionAsNecessary(env, err, "Failed to sign");
907
908 return VectorToJByteArray(env, signature);
909}
910
911static jboolean android_media_MediaDrm_verifyNative(
912 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
913 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
914
915 sp<IDrm> drm = GetDrm(env, jdrm);
916
917 if (!CheckSession(env, drm, jsessionId)) {
918 return false;
919 }
920
921 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
922 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
923 return false;
924 }
925
926 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
927 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
928 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
929 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
930 bool match;
931
932 status_t err = drm->verify(sessionId, keyId, message, signature, match);
933
934 throwExceptionAsNecessary(env, err, "Failed to verify");
935 return match;
936}
937
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800938
939static JNINativeMethod gMethods[] = {
940 { "release", "()V", (void *)android_media_MediaDrm_release },
941 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
942
943 { "native_setup", "(Ljava/lang/Object;[B)V",
944 (void *)android_media_MediaDrm_native_setup },
945
946 { "native_finalize", "()V",
947 (void *)android_media_MediaDrm_native_finalize },
948
949 { "isCryptoSchemeSupportedNative", "([B)Z",
950 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
951
952 { "openSession", "()[B",
953 (void *)android_media_MediaDrm_openSession },
954
955 { "closeSession", "([B)V",
956 (void *)android_media_MediaDrm_closeSession },
957
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700958 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
959 "Landroid/media/MediaDrm$KeyRequest;",
960 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800961
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700962 { "provideKeyResponse", "([B[B)[B",
963 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800964
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700965 { "removeKeys", "([B)V",
966 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800967
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700968 { "restoreKeys", "([B[B)V",
969 (void *)android_media_MediaDrm_restoreKeys },
970
971 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
972 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800973
974 { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
975 (void *)android_media_MediaDrm_getProvisionRequest },
976
977 { "provideProvisionResponse", "([B)V",
978 (void *)android_media_MediaDrm_provideProvisionResponse },
979
980 { "getSecureStops", "()Ljava/util/List;",
981 (void *)android_media_MediaDrm_getSecureStops },
982
983 { "releaseSecureStops", "([B)V",
984 (void *)android_media_MediaDrm_releaseSecureStops },
985
986 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
987 (void *)android_media_MediaDrm_getPropertyString },
988
989 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
990 (void *)android_media_MediaDrm_getPropertyByteArray },
991
992 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
993 (void *)android_media_MediaDrm_setPropertyString },
994
995 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
996 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700997
998 { "setCipherAlgorithmNative",
999 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1000 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1001
1002 { "setMacAlgorithmNative",
1003 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1004 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1005
1006 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1007 (void *)android_media_MediaDrm_encryptNative },
1008
1009 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1010 (void *)android_media_MediaDrm_decryptNative },
1011
1012 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1013 (void *)android_media_MediaDrm_signNative },
1014
1015 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1016 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001017};
1018
1019int register_android_media_Drm(JNIEnv *env) {
1020 return AndroidRuntime::registerNativeMethods(env,
1021 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1022}
1023