blob: 4fbd2a4a91eb2df2d5a55e85b265b1f1baf523ec [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 Tinkere4095a82014-03-04 13:17:11 -0800103struct CertificateTypes {
104 jint kCertificateTypeNone;
105 jint kCertificateTypeX509;
106} gCertificateTypes;
107
108struct CertificateFields {
109 jfieldID wrappedPrivateKey;
110 jfieldID certificateData;
111};
112
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800113struct fields_t {
114 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700115 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700116 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800117 RequestFields provisionRequest;
118 ArrayListFields arraylist;
119 HashmapFields hashmap;
120 SetFields set;
121 IteratorFields iterator;
122 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800123 CertificateFields certificate;
124 jclass certificateClassId;
125 jclass hashmapClassId;
126 jclass arraylistClassId;
127 jclass stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800128};
129
130static fields_t gFields;
131
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700132// ----------------------------------------------------------------------------
133// ref-counted object for callbacks
134class JNIDrmListener: public DrmListener
135{
136public:
137 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
138 ~JNIDrmListener();
139 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
140private:
141 JNIDrmListener();
142 jclass mClass; // Reference to MediaDrm class
143 jobject mObject; // Weak ref to MediaDrm Java object to call on
144};
145
146JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
147{
148 // Hold onto the MediaDrm class for use in calling the static method
149 // that posts events to the application thread.
150 jclass clazz = env->GetObjectClass(thiz);
151 if (clazz == NULL) {
152 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700153 jniThrowException(env, "java/lang/Exception",
154 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700155 return;
156 }
157 mClass = (jclass)env->NewGlobalRef(clazz);
158
159 // We use a weak reference so the MediaDrm object can be garbage collected.
160 // The reference is only used as a proxy for callbacks.
161 mObject = env->NewGlobalRef(weak_thiz);
162}
163
164JNIDrmListener::~JNIDrmListener()
165{
166 // remove global references
167 JNIEnv *env = AndroidRuntime::getJNIEnv();
168 env->DeleteGlobalRef(mObject);
169 env->DeleteGlobalRef(mClass);
170}
171
172void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
173 const Parcel *obj)
174{
175 jint jeventType;
176
177 // translate DrmPlugin event types into their java equivalents
178 switch(eventType) {
179 case DrmPlugin::kDrmPluginEventProvisionRequired:
180 jeventType = gEventTypes.kEventProvisionRequired;
181 break;
182 case DrmPlugin::kDrmPluginEventKeyNeeded:
183 jeventType = gEventTypes.kEventKeyRequired;
184 break;
185 case DrmPlugin::kDrmPluginEventKeyExpired:
186 jeventType = gEventTypes.kEventKeyExpired;
187 break;
188 case DrmPlugin::kDrmPluginEventVendorDefined:
189 jeventType = gEventTypes.kEventVendorDefined;
190 break;
191 default:
192 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
193 return;
194 }
195
196 JNIEnv *env = AndroidRuntime::getJNIEnv();
197 if (obj && obj->dataSize() > 0) {
198 jobject jParcel = createJavaParcelObject(env);
199 if (jParcel != NULL) {
200 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
201 nativeParcel->setData(obj->data(), obj->dataSize());
202 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
203 jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100204 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700205 }
206 }
207
208 if (env->ExceptionCheck()) {
209 ALOGW("An exception occurred while notifying an event.");
210 LOGW_EX(env);
211 env->ExceptionClear();
212 }
213}
214
215
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800216static bool throwExceptionAsNecessary(
217 JNIEnv *env, status_t err, const char *msg = NULL) {
218
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700219 const char *drmMessage = NULL;
220
221 switch(err) {
222 case ERROR_DRM_UNKNOWN:
223 drmMessage = "General DRM error";
224 break;
225 case ERROR_DRM_NO_LICENSE:
226 drmMessage = "No license";
227 break;
228 case ERROR_DRM_LICENSE_EXPIRED:
229 drmMessage = "License expired";
230 break;
231 case ERROR_DRM_SESSION_NOT_OPENED:
232 drmMessage = "Session not opened";
233 break;
234 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
235 drmMessage = "Not initialized";
236 break;
237 case ERROR_DRM_DECRYPT:
238 drmMessage = "Decrypt error";
239 break;
240 case ERROR_DRM_CANNOT_HANDLE:
241 drmMessage = "Unsupported scheme or data format";
242 break;
243 case ERROR_DRM_TAMPER_DETECTED:
244 drmMessage = "Invalid state";
245 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700246 default:
247 break;
248 }
249
250 String8 vendorMessage;
251 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
252 vendorMessage.format("DRM vendor-defined error: %d", err);
253 drmMessage = vendorMessage.string();
254 }
255
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800256 if (err == BAD_VALUE) {
257 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
258 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700259 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
260 jniThrowException(env, "android/media/NotProvisionedException", msg);
261 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700262 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
263 jniThrowException(env, "android/media/ResourceBusyException", msg);
264 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700265 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
266 jniThrowException(env, "android/media/DeniedByServerException", msg);
267 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800268 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700269 String8 errbuf;
270 if (drmMessage != NULL) {
271 if (msg == NULL) {
272 msg = drmMessage;
273 } else {
274 errbuf.format("%s: %s", msg, drmMessage);
275 msg = errbuf.string();
276 }
277 }
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700278 ALOGE("Illegal state exception: %s", msg);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800279 jniThrowException(env, "java/lang/IllegalStateException", msg);
280 return true;
281 }
282 return false;
283}
284
285static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000286 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800287 return jdrm ? jdrm->getDrm() : NULL;
288}
289
290JDrm::JDrm(
291 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
292 mObject = env->NewWeakGlobalRef(thiz);
293 mDrm = MakeDrm(uuid);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700294 if (mDrm != NULL) {
295 mDrm->setListener(this);
296 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800297}
298
299JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800300 JNIEnv *env = AndroidRuntime::getJNIEnv();
301
302 env->DeleteWeakGlobalRef(mObject);
303 mObject = NULL;
304}
305
306// static
307sp<IDrm> JDrm::MakeDrm() {
308 sp<IServiceManager> sm = defaultServiceManager();
309
310 sp<IBinder> binder =
311 sm->getService(String16("media.player"));
312
313 sp<IMediaPlayerService> service =
314 interface_cast<IMediaPlayerService>(binder);
315
316 if (service == NULL) {
317 return NULL;
318 }
319
320 sp<IDrm> drm = service->makeDrm();
321
322 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
323 return NULL;
324 }
325
326 return drm;
327}
328
329// static
330sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
331 sp<IDrm> drm = MakeDrm();
332
333 if (drm == NULL) {
334 return NULL;
335 }
336
337 status_t err = drm->createPlugin(uuid);
338
339 if (err != OK) {
340 return NULL;
341 }
342
343 return drm;
344}
345
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700346status_t JDrm::setListener(const sp<DrmListener>& listener) {
347 Mutex::Autolock lock(mLock);
348 mListener = listener;
349 return OK;
350}
351
352void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
353 sp<DrmListener> listener;
354 mLock.lock();
355 listener = mListener;
356 mLock.unlock();
357
358 if (listener != NULL) {
359 Mutex::Autolock lock(mNotifyLock);
360 listener->notify(eventType, extra, obj);
361 }
362}
363
Jeff Tinker600071c2014-04-11 16:11:15 -0700364void JDrm::disconnect() {
365 if (mDrm != NULL) {
366 mDrm->destroyPlugin();
367 mDrm.clear();
368 }
369}
370
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700371
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800372// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700373bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800374 sp<IDrm> drm = MakeDrm();
375
376 if (drm == NULL) {
377 return false;
378 }
379
Jeff Tinker7cda4912013-08-21 11:52:34 -0700380 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800381}
382
383status_t JDrm::initCheck() const {
384 return mDrm == NULL ? NO_INIT : OK;
385}
386
387// JNI conversion utilities
388static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
389 Vector<uint8_t> vector;
390 size_t length = env->GetArrayLength(byteArray);
391 vector.insertAt((size_t)0, length);
392 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
393 return vector;
394}
395
396static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
397 size_t length = vector.size();
398 jbyteArray result = env->NewByteArray(length);
399 if (result != NULL) {
400 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
401 }
402 return result;
403}
404
405static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800406 String8 result;
407
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700408 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800409 if (s) {
410 result = s;
411 env->ReleaseStringUTFChars(jstr, s);
412 }
413 return result;
414}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700415
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800416/*
417 import java.util.HashMap;
418 import java.util.Set;
419 import java.Map.Entry;
420 import jav.util.Iterator;
421
422 HashMap<k, v> hm;
423 Set<Entry<k, v> > s = hm.entrySet();
424 Iterator i = s.iterator();
425 Entry e = s.next();
426*/
427
428static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800429 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800430 KeyedVector<String8, String8> keyedVector;
431
432 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
433 if (entrySet) {
434 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
435 if (iterator) {
436 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
437 while (hasNext) {
438 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
439 if (entry) {
440 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
441 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700442 jniThrowException(env, "java/lang/IllegalArgumentException",
443 "HashMap key is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800444 }
445 jstring jkey = static_cast<jstring>(obj);
446
447 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
448 if (!env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700449 jniThrowException(env, "java/lang/IllegalArgumentException",
450 "HashMap value is not a String");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800451 }
452 jstring jvalue = static_cast<jstring>(obj);
453
454 String8 key = JStringToString8(env, jkey);
455 String8 value = JStringToString8(env, jvalue);
456 keyedVector.add(key, value);
457
458 env->DeleteLocalRef(jkey);
459 env->DeleteLocalRef(jvalue);
460 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
461 }
462 env->DeleteLocalRef(entry);
463 }
464 env->DeleteLocalRef(iterator);
465 }
466 env->DeleteLocalRef(entrySet);
467 }
468 return keyedVector;
469}
470
471static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800472 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800473 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
474 for (size_t i = 0; i < map.size(); ++i) {
475 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
476 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
477 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
478 env->DeleteLocalRef(jkey);
479 env->DeleteLocalRef(jvalue);
480 }
481 return hashMap;
482}
483
484static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
485 List<Vector<uint8_t> > list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800486 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800487 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
488 List<Vector<uint8_t> >::iterator iter = list.begin();
489 while (iter != list.end()) {
490 jbyteArray byteArray = VectorToJByteArray(env, *iter);
491 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
492 env->DeleteLocalRef(byteArray);
493 iter++;
494 }
495
496 return arrayList;
497}
498
499} // namespace android
500
501using namespace android;
502
503static sp<JDrm> setDrm(
504 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000505 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800506 if (drm != NULL) {
507 drm->incStrong(thiz);
508 }
509 if (old != NULL) {
510 old->decStrong(thiz);
511 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000512 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800513
514 return old;
515}
516
517static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
518{
519 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700520 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800521 return false;
522 }
523
524 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700525 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800526 return false;
527 }
528 return true;
529}
530
531static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700532 sp<JDrm> drm = setDrm(env, thiz, NULL);
533 if (drm != NULL) {
534 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700535 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700536 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800537}
538
539static void android_media_MediaDrm_native_init(JNIEnv *env) {
540 jclass clazz;
541 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000542 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700543 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
544 "(Ljava/lang/Object;IILjava/lang/Object;)V");
545
546 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700547 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700548 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700549 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700550 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700551 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700552 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700553 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700554 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800555
Jeff Tinker17b89222013-05-21 12:35:06 -0700556 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
557 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
558 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
559 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
560 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
561 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
562
Jeff Tinkere4095a82014-03-04 13:17:11 -0800563 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
564 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
565 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
566 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
567
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700568 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700569 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
570 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800571
572 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700573 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
574 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800575
Jeff Tinkere4095a82014-03-04 13:17:11 -0800576 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
577 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
578 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700579 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800580
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800581 FIND_CLASS(clazz, "java/util/ArrayList");
582 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
583 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
584
585 FIND_CLASS(clazz, "java/util/HashMap");
586 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
587 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
588 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
589 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
590 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
591
592 FIND_CLASS(clazz, "java/util/Set");
593 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
594
595 FIND_CLASS(clazz, "java/util/Iterator");
596 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
597 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
598
599 FIND_CLASS(clazz, "java/util/Map$Entry");
600 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
601 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800602
603 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700604 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800605
606 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700607 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800608
609 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700610 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800611}
612
613static void android_media_MediaDrm_native_setup(
614 JNIEnv *env, jobject thiz,
615 jobject weak_this, jbyteArray uuidObj) {
616
617 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700618 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800619 return;
620 }
621
622 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
623
624 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700625 jniThrowException(env, "java/lang/IllegalArgumentException",
626 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800627 return;
628 }
629
630 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
631
632 status_t err = drm->initCheck();
633
634 if (err != OK) {
635 jniThrowException(
636 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700637 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800638 "Failed to instantiate drm object.");
639 return;
640 }
641
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700642 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
643 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800644 setDrm(env, thiz, drm);
645}
646
647static void android_media_MediaDrm_native_finalize(
648 JNIEnv *env, jobject thiz) {
649 android_media_MediaDrm_release(env, thiz);
650}
651
652static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinker7cda4912013-08-21 11:52:34 -0700653 JNIEnv *env, jobject thiz, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800654
655 if (uuidObj == NULL) {
656 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
657 return false;
658 }
659
660 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
661
662 if (uuid.size() != 16) {
663 jniThrowException(
664 env,
665 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700666 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800667 return false;
668 }
669
Jeff Tinker7cda4912013-08-21 11:52:34 -0700670 String8 mimeType;
671 if (jmimeType != NULL) {
672 mimeType = JStringToString8(env, jmimeType);
673 }
674
675 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800676}
677
678static jbyteArray android_media_MediaDrm_openSession(
679 JNIEnv *env, jobject thiz) {
680 sp<IDrm> drm = GetDrm(env, thiz);
681
682 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700683 jniThrowException(env, "java/lang/IllegalStateException",
684 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800685 return NULL;
686 }
687
688 Vector<uint8_t> sessionId;
689 status_t err = drm->openSession(sessionId);
690
691 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
692 return NULL;
693 }
694
695 return VectorToJByteArray(env, sessionId);
696}
697
698static void android_media_MediaDrm_closeSession(
699 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
700 sp<IDrm> drm = GetDrm(env, thiz);
701
702 if (!CheckSession(env, drm, jsessionId)) {
703 return;
704 }
705
706 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
707
708 status_t err = drm->closeSession(sessionId);
709
710 throwExceptionAsNecessary(env, err, "Failed to close session");
711}
712
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700713static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800714 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700715 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800716 sp<IDrm> drm = GetDrm(env, thiz);
717
718 if (!CheckSession(env, drm, jsessionId)) {
719 return NULL;
720 }
721
722 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
723
724 Vector<uint8_t> initData;
725 if (jinitData != NULL) {
726 initData = JByteArrayToVector(env, jinitData);
727 }
728
729 String8 mimeType;
730 if (jmimeType != NULL) {
731 mimeType = JStringToString8(env, jmimeType);
732 }
733
Jeff Tinker17b89222013-05-21 12:35:06 -0700734 DrmPlugin::KeyType keyType;
735 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
736 keyType = DrmPlugin::kKeyType_Streaming;
737 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
738 keyType = DrmPlugin::kKeyType_Offline;
739 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
740 keyType = DrmPlugin::kKeyType_Release;
741 } else {
742 jniThrowException(env, "java/lang/IllegalArgumentException",
743 "invalid keyType");
744 return NULL;
745 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800746
747 KeyedVector<String8, String8> optParams;
748 if (joptParams != NULL) {
749 optParams = HashMapToKeyedVector(env, joptParams);
750 }
751
752 Vector<uint8_t> request;
753 String8 defaultUrl;
754
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700755 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
756 keyType, optParams, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800757
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700758 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800759 return NULL;
760 }
761
762 // Fill out return obj
763 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700764 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800765
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700766 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800767
768 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700769 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800770 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700771 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800772
773 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700774 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800775 }
776
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700777 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800778}
779
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700780static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800781 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
782 sp<IDrm> drm = GetDrm(env, thiz);
783
784 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700785 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800786 }
787
788 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
789
790 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700791 jniThrowException(env, "java/lang/IllegalArgumentException",
792 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700793 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800794 }
795 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700796 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800797
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700798 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800799
Jeff Tinker8117d8f2013-08-16 13:46:02 -0700800 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
801 return NULL;
802 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700803 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800804}
805
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700806static void android_media_MediaDrm_removeKeys(
807 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
808 sp<IDrm> drm = GetDrm(env, thiz);
809
810 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700811 jniThrowException(env, "java/lang/IllegalArgumentException",
812 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700813 return;
814 }
815
816 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
817
818 status_t err = drm->removeKeys(keySetId);
819
820 throwExceptionAsNecessary(env, err, "Failed to remove keys");
821}
822
823static void android_media_MediaDrm_restoreKeys(
824 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
825 jbyteArray jkeysetId) {
826
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800827 sp<IDrm> drm = GetDrm(env, thiz);
828
829 if (!CheckSession(env, drm, jsessionId)) {
830 return;
831 }
832
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700833 if (jkeysetId == NULL) {
834 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
835 return;
836 }
837
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800838 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700839 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800840
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700841 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800842
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700843 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800844}
845
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700846static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800847 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
848 sp<IDrm> drm = GetDrm(env, thiz);
849
850 if (!CheckSession(env, drm, jsessionId)) {
851 return NULL;
852 }
853 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
854
855 KeyedVector<String8, String8> infoMap;
856
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700857 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800858
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700859 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800860 return NULL;
861 }
862
863 return KeyedVectorToHashMap(env, infoMap);
864}
865
Jeff Tinkere4095a82014-03-04 13:17:11 -0800866static jobject android_media_MediaDrm_getProvisionRequestNative(
867 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800868 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 NULL;
874 }
875
876 Vector<uint8_t> request;
877 String8 defaultUrl;
878
Jeff Tinkere4095a82014-03-04 13:17:11 -0800879 String8 certType;
880 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
881 certType = "X.509";
882 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
883 certType = "none";
884 } else {
885 certType = "invalid";
886 }
887
888 String8 certAuthority = JStringToString8(env, jcertAuthority);
889 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800890
891 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
892 return NULL;
893 }
894
895 // Fill out return obj
896 jclass clazz;
897 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
898
899 jobject provisionObj = NULL;
900
901 if (clazz) {
902 provisionObj = env->AllocObject(clazz);
903 jbyteArray jrequest = VectorToJByteArray(env, request);
904 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
905
906 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
907 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
908 }
909
910 return provisionObj;
911}
912
Jeff Tinkere4095a82014-03-04 13:17:11 -0800913static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800914 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
915 sp<IDrm> drm = GetDrm(env, thiz);
916
917 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700918 jniThrowException(env, "java/lang/IllegalStateException",
919 "MediaDrm obj is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800920 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800921 }
922
923 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700924 jniThrowException(env, "java/lang/IllegalArgumentException",
925 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800926 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800927 }
928
929 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800930 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800931
Jeff Tinkere4095a82014-03-04 13:17:11 -0800932 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
933
934 // Fill out return obj
935 jclass clazz = gFields.certificateClassId;
936
937 jobject certificateObj = NULL;
938
939 if (clazz && certificate.size() && wrappedKey.size()) {
940 certificateObj = env->AllocObject(clazz);
941 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
942 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
943
944 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
945 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
946 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800947
948 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800949 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800950}
951
952static jobject android_media_MediaDrm_getSecureStops(
953 JNIEnv *env, jobject thiz) {
954 sp<IDrm> drm = GetDrm(env, thiz);
955
956 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700957 jniThrowException(env, "java/lang/IllegalStateException",
958 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800959 return NULL;
960 }
961
962 List<Vector<uint8_t> > secureStops;
963
964 status_t err = drm->getSecureStops(secureStops);
965
966 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
967 return NULL;
968 }
969
970 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
971}
972
973static void android_media_MediaDrm_releaseSecureStops(
974 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
975 sp<IDrm> drm = GetDrm(env, thiz);
976
977 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700978 jniThrowException(env, "java/lang/IllegalStateException",
979 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800980 return;
981 }
982
983 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
984
985 status_t err = drm->releaseSecureStops(ssRelease);
986
987 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
988}
989
990static jstring android_media_MediaDrm_getPropertyString(
991 JNIEnv *env, jobject thiz, jstring jname) {
992 sp<IDrm> drm = GetDrm(env, thiz);
993
994 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700995 jniThrowException(env, "java/lang/IllegalStateException",
996 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800997 return NULL;
998 }
999
1000 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001001 jniThrowException(env, "java/lang/IllegalArgumentException",
1002 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001003 return NULL;
1004 }
1005
1006 String8 name = JStringToString8(env, jname);
1007 String8 value;
1008
1009 status_t err = drm->getPropertyString(name, value);
1010
1011 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1012 return NULL;
1013 }
1014
1015 return env->NewStringUTF(value.string());
1016}
1017
1018static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1019 JNIEnv *env, jobject thiz, jstring jname) {
1020 sp<IDrm> drm = GetDrm(env, thiz);
1021
1022 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001023 jniThrowException(env, "java/lang/IllegalStateException",
1024 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001025 return NULL;
1026 }
1027
1028 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001029 jniThrowException(env, "java/lang/IllegalArgumentException",
1030 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001031 return NULL;
1032 }
1033
1034 String8 name = JStringToString8(env, jname);
1035 Vector<uint8_t> value;
1036
1037 status_t err = drm->getPropertyByteArray(name, value);
1038
1039 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1040 return NULL;
1041 }
1042
1043 return VectorToJByteArray(env, value);
1044}
1045
1046static void android_media_MediaDrm_setPropertyString(
1047 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1048 sp<IDrm> drm = GetDrm(env, thiz);
1049
1050 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001051 jniThrowException(env, "java/lang/IllegalStateException",
1052 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001053 return;
1054 }
1055
Jeff Tinkereada5372013-05-21 12:48:14 -07001056 if (jname == NULL) {
1057 jniThrowException(env, "java/lang/IllegalArgumentException",
1058 "property name String is null");
1059 return;
1060 }
1061
1062 if (jvalue == NULL) {
1063 jniThrowException(env, "java/lang/IllegalArgumentException",
1064 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001065 return;
1066 }
1067
1068 String8 name = JStringToString8(env, jname);
1069 String8 value = JStringToString8(env, jvalue);
1070
1071 status_t err = drm->setPropertyString(name, value);
1072
1073 throwExceptionAsNecessary(env, err, "Failed to set property");
1074}
1075
1076static void android_media_MediaDrm_setPropertyByteArray(
1077 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1078 sp<IDrm> drm = GetDrm(env, thiz);
1079
1080 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001081 jniThrowException(env, "java/lang/IllegalStateException",
1082 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001083 return;
1084 }
1085
Jeff Tinkereada5372013-05-21 12:48:14 -07001086 if (jname == NULL) {
1087 jniThrowException(env, "java/lang/IllegalArgumentException",
1088 "property name String is null");
1089 return;
1090 }
1091
1092 if (jvalue == NULL) {
1093 jniThrowException(env, "java/lang/IllegalArgumentException",
1094 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001095 return;
1096 }
1097
1098 String8 name = JStringToString8(env, jname);
1099 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1100
1101 status_t err = drm->setPropertyByteArray(name, value);
1102
1103 throwExceptionAsNecessary(env, err, "Failed to set property");
1104}
1105
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001106static void android_media_MediaDrm_setCipherAlgorithmNative(
1107 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1108 jstring jalgorithm) {
1109
1110 sp<IDrm> drm = GetDrm(env, jdrm);
1111
1112 if (!CheckSession(env, drm, jsessionId)) {
1113 return;
1114 }
1115
1116 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001117 jniThrowException(env, "java/lang/IllegalArgumentException",
1118 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001119 return;
1120 }
1121
1122 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1123 String8 algorithm = JStringToString8(env, jalgorithm);
1124
1125 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1126
1127 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1128}
1129
1130static void android_media_MediaDrm_setMacAlgorithmNative(
1131 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1132 jstring jalgorithm) {
1133
1134 sp<IDrm> drm = GetDrm(env, jdrm);
1135
1136 if (!CheckSession(env, drm, jsessionId)) {
1137 return;
1138 }
1139
1140 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001141 jniThrowException(env, "java/lang/IllegalArgumentException",
1142 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001143 return;
1144 }
1145
1146 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1147 String8 algorithm = JStringToString8(env, jalgorithm);
1148
1149 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1150
1151 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1152}
1153
1154
1155static jbyteArray android_media_MediaDrm_encryptNative(
1156 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1157 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1158
1159 sp<IDrm> drm = GetDrm(env, jdrm);
1160
1161 if (!CheckSession(env, drm, jsessionId)) {
1162 return NULL;
1163 }
1164
1165 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001166 jniThrowException(env, "java/lang/IllegalArgumentException",
1167 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001168 return NULL;
1169 }
1170
1171 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1172 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1173 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1174 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1175 Vector<uint8_t> output;
1176
1177 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1178
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001179 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1180 return NULL;
1181 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001182
1183 return VectorToJByteArray(env, output);
1184}
1185
1186static jbyteArray android_media_MediaDrm_decryptNative(
1187 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1188 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1189
1190 sp<IDrm> drm = GetDrm(env, jdrm);
1191
1192 if (!CheckSession(env, drm, jsessionId)) {
1193 return NULL;
1194 }
1195
1196 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001197 jniThrowException(env, "java/lang/IllegalArgumentException",
1198 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001199 return NULL;
1200 }
1201
1202 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1203 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1204 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1205 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1206 Vector<uint8_t> output;
1207
1208 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001209 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1210 return NULL;
1211 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001212
1213 return VectorToJByteArray(env, output);
1214}
1215
1216static jbyteArray android_media_MediaDrm_signNative(
1217 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1218 jbyteArray jkeyId, jbyteArray jmessage) {
1219
1220 sp<IDrm> drm = GetDrm(env, jdrm);
1221
1222 if (!CheckSession(env, drm, jsessionId)) {
1223 return NULL;
1224 }
1225
1226 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001227 jniThrowException(env, "java/lang/IllegalArgumentException",
1228 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001229 return NULL;
1230 }
1231
1232 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1233 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1234 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1235 Vector<uint8_t> signature;
1236
1237 status_t err = drm->sign(sessionId, keyId, message, signature);
1238
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001239 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1240 return NULL;
1241 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001242
1243 return VectorToJByteArray(env, signature);
1244}
1245
1246static jboolean android_media_MediaDrm_verifyNative(
1247 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1248 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1249
1250 sp<IDrm> drm = GetDrm(env, jdrm);
1251
1252 if (!CheckSession(env, drm, jsessionId)) {
1253 return false;
1254 }
1255
1256 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001257 jniThrowException(env, "java/lang/IllegalArgumentException",
1258 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001259 return false;
1260 }
1261
1262 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1263 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1264 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1265 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1266 bool match;
1267
1268 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1269
1270 throwExceptionAsNecessary(env, err, "Failed to verify");
1271 return match;
1272}
1273
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001274
Jeff Tinkere4095a82014-03-04 13:17:11 -08001275static jbyteArray android_media_MediaDrm_signRSANative(
1276 JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
1277 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1278
1279 sp<IDrm> drm = GetDrm(env, jdrm);
1280
1281 if (!CheckSession(env, drm, jsessionId)) {
1282 return NULL;
1283 }
1284
1285 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1286 jniThrowException(env, "java/lang/IllegalArgumentException",
1287 "required argument is null");
1288 return NULL;
1289 }
1290
1291 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1292 String8 algorithm = JStringToString8(env, jalgorithm);
1293 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1294 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1295 Vector<uint8_t> signature;
1296
1297 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1298
1299 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1300 return NULL;
1301 }
1302
1303 return VectorToJByteArray(env, signature);
1304}
1305
1306
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001307static JNINativeMethod gMethods[] = {
1308 { "release", "()V", (void *)android_media_MediaDrm_release },
1309 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1310
1311 { "native_setup", "(Ljava/lang/Object;[B)V",
1312 (void *)android_media_MediaDrm_native_setup },
1313
1314 { "native_finalize", "()V",
1315 (void *)android_media_MediaDrm_native_finalize },
1316
Jeff Tinker7cda4912013-08-21 11:52:34 -07001317 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001318 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1319
1320 { "openSession", "()[B",
1321 (void *)android_media_MediaDrm_openSession },
1322
1323 { "closeSession", "([B)V",
1324 (void *)android_media_MediaDrm_closeSession },
1325
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001326 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1327 "Landroid/media/MediaDrm$KeyRequest;",
1328 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001329
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001330 { "provideKeyResponse", "([B[B)[B",
1331 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001332
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001333 { "removeKeys", "([B)V",
1334 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001335
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001336 { "restoreKeys", "([B[B)V",
1337 (void *)android_media_MediaDrm_restoreKeys },
1338
1339 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1340 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001341
Jeff Tinkere4095a82014-03-04 13:17:11 -08001342 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1343 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001344
Jeff Tinkere4095a82014-03-04 13:17:11 -08001345 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1346 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001347
1348 { "getSecureStops", "()Ljava/util/List;",
1349 (void *)android_media_MediaDrm_getSecureStops },
1350
1351 { "releaseSecureStops", "([B)V",
1352 (void *)android_media_MediaDrm_releaseSecureStops },
1353
1354 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1355 (void *)android_media_MediaDrm_getPropertyString },
1356
1357 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1358 (void *)android_media_MediaDrm_getPropertyByteArray },
1359
1360 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1361 (void *)android_media_MediaDrm_setPropertyString },
1362
1363 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1364 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001365
1366 { "setCipherAlgorithmNative",
1367 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1368 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1369
1370 { "setMacAlgorithmNative",
1371 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1372 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1373
1374 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1375 (void *)android_media_MediaDrm_encryptNative },
1376
1377 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1378 (void *)android_media_MediaDrm_decryptNative },
1379
1380 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1381 (void *)android_media_MediaDrm_signNative },
1382
1383 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1384 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08001385
1386 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1387 (void *)android_media_MediaDrm_signRSANative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001388};
1389
1390int register_android_media_Drm(JNIEnv *env) {
1391 return AndroidRuntime::registerNativeMethods(env,
1392 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1393}
1394