blob: 9ec0312d0f2a1a08e9141c64fd0a3dc07d06c66b [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;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -070062 jfieldID requestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080063};
64
65struct ArrayListFields {
66 jmethodID init;
67 jmethodID add;
68};
69
70struct HashmapFields {
71 jmethodID init;
72 jmethodID get;
73 jmethodID put;
74 jmethodID entrySet;
75};
76
77struct SetFields {
78 jmethodID iterator;
79};
80
81struct IteratorFields {
82 jmethodID next;
83 jmethodID hasNext;
84};
85
86struct EntryFields {
87 jmethodID getKey;
88 jmethodID getValue;
89};
90
Jeff Tinker54cfbd62013-04-02 13:14:59 -070091struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -070092 jint kEventProvisionRequired;
93 jint kEventKeyRequired;
94 jint kEventKeyExpired;
95 jint kEventVendorDefined;
Ronghua Wua6d72092015-03-04 11:16:02 -080096 jint kEventSessionReclaimed;
Jeff Tinker54cfbd62013-04-02 13:14:59 -070097} gEventTypes;
98
Jeff Tinker74797f82015-03-31 15:44:34 -070099struct EventWhat {
100 jint kWhatDrmEvent;
101 jint kWhatExpirationUpdate;
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700102 jint kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700103} gEventWhat;
104
Jeff Tinker17b89222013-05-21 12:35:06 -0700105struct KeyTypes {
106 jint kKeyTypeStreaming;
107 jint kKeyTypeOffline;
108 jint kKeyTypeRelease;
109} gKeyTypes;
110
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700111struct KeyRequestTypes {
112 jint kKeyRequestTypeInitial;
113 jint kKeyRequestTypeRenewal;
114 jint kKeyRequestTypeRelease;
115} gKeyRequestTypes;
116
Jeff Tinkere4095a82014-03-04 13:17:11 -0800117struct CertificateTypes {
118 jint kCertificateTypeNone;
119 jint kCertificateTypeX509;
120} gCertificateTypes;
121
122struct CertificateFields {
123 jfieldID wrappedPrivateKey;
124 jfieldID certificateData;
125};
126
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700127struct StateExceptionFields {
128 jmethodID init;
129 jclass classId;
130};
131
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800132struct fields_t {
133 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700134 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700135 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800136 RequestFields provisionRequest;
137 ArrayListFields arraylist;
138 HashmapFields hashmap;
139 SetFields set;
140 IteratorFields iterator;
141 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800142 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700143 StateExceptionFields stateException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800144 jclass certificateClassId;
145 jclass hashmapClassId;
146 jclass arraylistClassId;
147 jclass stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800148};
149
150static fields_t gFields;
151
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700152// ----------------------------------------------------------------------------
153// ref-counted object for callbacks
154class JNIDrmListener: public DrmListener
155{
156public:
157 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
158 ~JNIDrmListener();
159 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
160private:
161 JNIDrmListener();
162 jclass mClass; // Reference to MediaDrm class
163 jobject mObject; // Weak ref to MediaDrm Java object to call on
164};
165
166JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
167{
168 // Hold onto the MediaDrm class for use in calling the static method
169 // that posts events to the application thread.
170 jclass clazz = env->GetObjectClass(thiz);
171 if (clazz == NULL) {
172 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700173 jniThrowException(env, "java/lang/Exception",
174 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700175 return;
176 }
177 mClass = (jclass)env->NewGlobalRef(clazz);
178
179 // We use a weak reference so the MediaDrm object can be garbage collected.
180 // The reference is only used as a proxy for callbacks.
181 mObject = env->NewGlobalRef(weak_thiz);
182}
183
184JNIDrmListener::~JNIDrmListener()
185{
186 // remove global references
187 JNIEnv *env = AndroidRuntime::getJNIEnv();
188 env->DeleteGlobalRef(mObject);
189 env->DeleteGlobalRef(mClass);
190}
191
192void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
193 const Parcel *obj)
194{
Jeff Tinker74797f82015-03-31 15:44:34 -0700195 jint jwhat;
196 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700197
198 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700199 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700200 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700201 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700202 jeventType = gEventTypes.kEventProvisionRequired;
203 break;
204 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700205 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700206 jeventType = gEventTypes.kEventKeyRequired;
207 break;
208 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700209 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700210 jeventType = gEventTypes.kEventKeyExpired;
211 break;
212 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700213 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700214 jeventType = gEventTypes.kEventVendorDefined;
215 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800216 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700217 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800218 jeventType = gEventTypes.kEventSessionReclaimed;
219 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700220 case DrmPlugin::kDrmPluginEventExpirationUpdate:
221 jwhat = gEventWhat.kWhatExpirationUpdate;
222 break;
223 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700224 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700225 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700226 default:
227 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
228 return;
229 }
230
231 JNIEnv *env = AndroidRuntime::getJNIEnv();
232 if (obj && obj->dataSize() > 0) {
233 jobject jParcel = createJavaParcelObject(env);
234 if (jParcel != NULL) {
235 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
236 nativeParcel->setData(obj->data(), obj->dataSize());
237 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
Jeff Tinker74797f82015-03-31 15:44:34 -0700238 jwhat, jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100239 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700240 }
241 }
242
243 if (env->ExceptionCheck()) {
244 ALOGW("An exception occurred while notifying an event.");
245 LOGW_EX(env);
246 env->ExceptionClear();
247 }
248}
249
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700250static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
251 ALOGE("Illegal state exception: %s (%d)", msg, err);
252
253 jobject exception = env->NewObject(gFields.stateException.classId,
254 gFields.stateException.init, static_cast<int>(err),
255 env->NewStringUTF(msg));
256 env->Throw(static_cast<jthrowable>(exception));
257}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700258
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800259static bool throwExceptionAsNecessary(
260 JNIEnv *env, status_t err, const char *msg = NULL) {
261
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700262 const char *drmMessage = NULL;
263
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700264 switch (err) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700265 case ERROR_DRM_UNKNOWN:
266 drmMessage = "General DRM error";
267 break;
268 case ERROR_DRM_NO_LICENSE:
269 drmMessage = "No license";
270 break;
271 case ERROR_DRM_LICENSE_EXPIRED:
272 drmMessage = "License expired";
273 break;
274 case ERROR_DRM_SESSION_NOT_OPENED:
275 drmMessage = "Session not opened";
276 break;
277 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
278 drmMessage = "Not initialized";
279 break;
280 case ERROR_DRM_DECRYPT:
281 drmMessage = "Decrypt error";
282 break;
283 case ERROR_DRM_CANNOT_HANDLE:
284 drmMessage = "Unsupported scheme or data format";
285 break;
286 case ERROR_DRM_TAMPER_DETECTED:
287 drmMessage = "Invalid state";
288 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700289 default:
290 break;
291 }
292
293 String8 vendorMessage;
294 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
Jeff Tinker29799862014-08-27 11:05:13 -0700295 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700296 drmMessage = vendorMessage.string();
297 }
298
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800299 if (err == BAD_VALUE) {
300 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
301 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700302 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
303 jniThrowException(env, "android/media/NotProvisionedException", msg);
304 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700305 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
306 jniThrowException(env, "android/media/ResourceBusyException", msg);
307 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700308 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
309 jniThrowException(env, "android/media/DeniedByServerException", msg);
310 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700311 } else if (err == DEAD_OBJECT) {
312 jniThrowException(env, "android/media/MediaDrmResetException",
313 "mediaserver died");
314 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800315 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700316 String8 errbuf;
317 if (drmMessage != NULL) {
318 if (msg == NULL) {
319 msg = drmMessage;
320 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700321 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700322 msg = errbuf.string();
323 }
324 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700325 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800326 return true;
327 }
328 return false;
329}
330
331static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000332 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800333 return jdrm ? jdrm->getDrm() : NULL;
334}
335
336JDrm::JDrm(
337 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
338 mObject = env->NewWeakGlobalRef(thiz);
339 mDrm = MakeDrm(uuid);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700340 if (mDrm != NULL) {
341 mDrm->setListener(this);
342 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800343}
344
345JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800346 JNIEnv *env = AndroidRuntime::getJNIEnv();
347
348 env->DeleteWeakGlobalRef(mObject);
349 mObject = NULL;
350}
351
352// static
353sp<IDrm> JDrm::MakeDrm() {
354 sp<IServiceManager> sm = defaultServiceManager();
355
356 sp<IBinder> binder =
357 sm->getService(String16("media.player"));
358
359 sp<IMediaPlayerService> service =
360 interface_cast<IMediaPlayerService>(binder);
361
362 if (service == NULL) {
363 return NULL;
364 }
365
366 sp<IDrm> drm = service->makeDrm();
367
368 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
369 return NULL;
370 }
371
372 return drm;
373}
374
375// static
376sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
377 sp<IDrm> drm = MakeDrm();
378
379 if (drm == NULL) {
380 return NULL;
381 }
382
383 status_t err = drm->createPlugin(uuid);
384
385 if (err != OK) {
386 return NULL;
387 }
388
389 return drm;
390}
391
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700392status_t JDrm::setListener(const sp<DrmListener>& listener) {
393 Mutex::Autolock lock(mLock);
394 mListener = listener;
395 return OK;
396}
397
398void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
399 sp<DrmListener> listener;
400 mLock.lock();
401 listener = mListener;
402 mLock.unlock();
403
404 if (listener != NULL) {
405 Mutex::Autolock lock(mNotifyLock);
406 listener->notify(eventType, extra, obj);
407 }
408}
409
Jeff Tinker600071c2014-04-11 16:11:15 -0700410void JDrm::disconnect() {
411 if (mDrm != NULL) {
412 mDrm->destroyPlugin();
413 mDrm.clear();
414 }
415}
416
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700417
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800418// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700419bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800420 sp<IDrm> drm = MakeDrm();
421
422 if (drm == NULL) {
423 return false;
424 }
425
Jeff Tinker7cda4912013-08-21 11:52:34 -0700426 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800427}
428
429status_t JDrm::initCheck() const {
430 return mDrm == NULL ? NO_INIT : OK;
431}
432
433// JNI conversion utilities
434static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
435 Vector<uint8_t> vector;
436 size_t length = env->GetArrayLength(byteArray);
437 vector.insertAt((size_t)0, length);
438 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
439 return vector;
440}
441
442static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
443 size_t length = vector.size();
444 jbyteArray result = env->NewByteArray(length);
445 if (result != NULL) {
446 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
447 }
448 return result;
449}
450
451static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800452 String8 result;
453
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700454 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800455 if (s) {
456 result = s;
457 env->ReleaseStringUTFChars(jstr, s);
458 }
459 return result;
460}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700461
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800462/*
463 import java.util.HashMap;
464 import java.util.Set;
465 import java.Map.Entry;
466 import jav.util.Iterator;
467
468 HashMap<k, v> hm;
469 Set<Entry<k, v> > s = hm.entrySet();
470 Iterator i = s.iterator();
471 Entry e = s.next();
472*/
473
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200474static KeyedVector<String8, String8> HashMapToKeyedVector(
475 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800476 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800477 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200478 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800479
480 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
481 if (entrySet) {
482 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
483 if (iterator) {
484 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
485 while (hasNext) {
486 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
487 if (entry) {
488 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200489 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700490 jniThrowException(env, "java/lang/IllegalArgumentException",
491 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200492 env->DeleteLocalRef(entry);
493 *pIsOK = false;
494 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800495 }
496 jstring jkey = static_cast<jstring>(obj);
497
498 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200499 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700500 jniThrowException(env, "java/lang/IllegalArgumentException",
501 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200502 env->DeleteLocalRef(entry);
503 *pIsOK = false;
504 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800505 }
506 jstring jvalue = static_cast<jstring>(obj);
507
508 String8 key = JStringToString8(env, jkey);
509 String8 value = JStringToString8(env, jvalue);
510 keyedVector.add(key, value);
511
512 env->DeleteLocalRef(jkey);
513 env->DeleteLocalRef(jvalue);
514 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
515 }
516 env->DeleteLocalRef(entry);
517 }
518 env->DeleteLocalRef(iterator);
519 }
520 env->DeleteLocalRef(entrySet);
521 }
522 return keyedVector;
523}
524
525static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800526 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800527 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
528 for (size_t i = 0; i < map.size(); ++i) {
529 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
530 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
531 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
532 env->DeleteLocalRef(jkey);
533 env->DeleteLocalRef(jvalue);
534 }
535 return hashMap;
536}
537
538static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
539 List<Vector<uint8_t> > list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800540 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800541 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
542 List<Vector<uint8_t> >::iterator iter = list.begin();
543 while (iter != list.end()) {
544 jbyteArray byteArray = VectorToJByteArray(env, *iter);
545 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
546 env->DeleteLocalRef(byteArray);
547 iter++;
548 }
549
550 return arrayList;
551}
552
553} // namespace android
554
555using namespace android;
556
557static sp<JDrm> setDrm(
558 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000559 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800560 if (drm != NULL) {
561 drm->incStrong(thiz);
562 }
563 if (old != NULL) {
564 old->decStrong(thiz);
565 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000566 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800567
568 return old;
569}
570
571static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
572{
573 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700574 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800575 return false;
576 }
577
578 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700579 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800580 return false;
581 }
582 return true;
583}
584
585static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700586 sp<JDrm> drm = setDrm(env, thiz, NULL);
587 if (drm != NULL) {
588 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700589 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700590 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800591}
592
593static void android_media_MediaDrm_native_init(JNIEnv *env) {
594 jclass clazz;
595 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000596 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700597 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700598 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700599
600 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700601 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700602 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700603 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700604 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700605 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700606 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700607 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700608 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800609 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
610 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800611
Jeff Tinker74797f82015-03-31 15:44:34 -0700612 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
613 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
614 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
615 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700616 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
617 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700618
Jeff Tinker17b89222013-05-21 12:35:06 -0700619 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
620 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
621 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
622 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
623 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
624 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
625
Jeff Tinkere4095a82014-03-04 13:17:11 -0800626 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
627 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
628 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
629 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
630
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700631 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700632 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
633 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700634 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800635
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700636 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
637 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
638 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
639 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
640 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
641 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
642
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800643 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700644 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
645 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800646
Jeff Tinkere4095a82014-03-04 13:17:11 -0800647 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
648 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
649 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700650 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800651
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800652 FIND_CLASS(clazz, "java/util/ArrayList");
653 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
654 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
655
656 FIND_CLASS(clazz, "java/util/HashMap");
657 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
658 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
659 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
660 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
661 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
662
663 FIND_CLASS(clazz, "java/util/Set");
664 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
665
666 FIND_CLASS(clazz, "java/util/Iterator");
667 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
668 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
669
670 FIND_CLASS(clazz, "java/util/Map$Entry");
671 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
672 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800673
674 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700675 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800676
677 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700678 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800679
680 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700681 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700682
683 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
684 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
685 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800686}
687
688static void android_media_MediaDrm_native_setup(
689 JNIEnv *env, jobject thiz,
690 jobject weak_this, jbyteArray uuidObj) {
691
692 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700693 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800694 return;
695 }
696
697 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
698
699 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700700 jniThrowException(env, "java/lang/IllegalArgumentException",
701 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800702 return;
703 }
704
705 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
706
707 status_t err = drm->initCheck();
708
709 if (err != OK) {
710 jniThrowException(
711 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700712 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800713 "Failed to instantiate drm object.");
714 return;
715 }
716
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700717 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
718 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800719 setDrm(env, thiz, drm);
720}
721
722static void android_media_MediaDrm_native_finalize(
723 JNIEnv *env, jobject thiz) {
724 android_media_MediaDrm_release(env, thiz);
725}
726
727static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800728 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800729
730 if (uuidObj == NULL) {
731 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
732 return false;
733 }
734
735 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
736
737 if (uuid.size() != 16) {
738 jniThrowException(
739 env,
740 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700741 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800742 return false;
743 }
744
Jeff Tinker7cda4912013-08-21 11:52:34 -0700745 String8 mimeType;
746 if (jmimeType != NULL) {
747 mimeType = JStringToString8(env, jmimeType);
748 }
749
750 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800751}
752
753static jbyteArray android_media_MediaDrm_openSession(
754 JNIEnv *env, jobject thiz) {
755 sp<IDrm> drm = GetDrm(env, thiz);
756
757 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700758 jniThrowException(env, "java/lang/IllegalStateException",
759 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800760 return NULL;
761 }
762
763 Vector<uint8_t> sessionId;
764 status_t err = drm->openSession(sessionId);
765
766 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
767 return NULL;
768 }
769
770 return VectorToJByteArray(env, sessionId);
771}
772
773static void android_media_MediaDrm_closeSession(
774 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
775 sp<IDrm> drm = GetDrm(env, thiz);
776
777 if (!CheckSession(env, drm, jsessionId)) {
778 return;
779 }
780
781 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
782
783 status_t err = drm->closeSession(sessionId);
784
785 throwExceptionAsNecessary(env, err, "Failed to close session");
786}
787
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700788static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800789 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700790 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800791 sp<IDrm> drm = GetDrm(env, thiz);
792
793 if (!CheckSession(env, drm, jsessionId)) {
794 return NULL;
795 }
796
797 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
798
799 Vector<uint8_t> initData;
800 if (jinitData != NULL) {
801 initData = JByteArrayToVector(env, jinitData);
802 }
803
804 String8 mimeType;
805 if (jmimeType != NULL) {
806 mimeType = JStringToString8(env, jmimeType);
807 }
808
Jeff Tinker17b89222013-05-21 12:35:06 -0700809 DrmPlugin::KeyType keyType;
810 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
811 keyType = DrmPlugin::kKeyType_Streaming;
812 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
813 keyType = DrmPlugin::kKeyType_Offline;
814 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
815 keyType = DrmPlugin::kKeyType_Release;
816 } else {
817 jniThrowException(env, "java/lang/IllegalArgumentException",
818 "invalid keyType");
819 return NULL;
820 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800821
822 KeyedVector<String8, String8> optParams;
823 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200824 bool isOK;
825 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
826 if (!isOK) {
827 return NULL;
828 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800829 }
830
831 Vector<uint8_t> request;
832 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700833 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800834
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700835 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700836 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800837
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700838 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800839 return NULL;
840 }
841
842 // Fill out return obj
843 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700844 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800845
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700846 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800847
848 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700849 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800850 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700851 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800852
853 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700854 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700855
856 switch (keyRequestType) {
857 case DrmPlugin::kKeyRequestType_Initial:
858 env->SetIntField(keyObj, gFields.keyRequest.requestType,
859 gKeyRequestTypes.kKeyRequestTypeInitial);
860 break;
861 case DrmPlugin::kKeyRequestType_Renewal:
862 env->SetIntField(keyObj, gFields.keyRequest.requestType,
863 gKeyRequestTypes.kKeyRequestTypeRenewal);
864 break;
865 case DrmPlugin::kKeyRequestType_Release:
866 env->SetIntField(keyObj, gFields.keyRequest.requestType,
867 gKeyRequestTypes.kKeyRequestTypeRelease);
868 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700869 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700870 throwStateException(env, "DRM plugin failure: unknown key request type",
871 ERROR_DRM_UNKNOWN);
872 break;
873 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800874 }
875
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700876 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800877}
878
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700879static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800880 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
881 sp<IDrm> drm = GetDrm(env, thiz);
882
883 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700884 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800885 }
886
887 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
888
889 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700890 jniThrowException(env, "java/lang/IllegalArgumentException",
891 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700892 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800893 }
894 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700895 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800896
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700897 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800898
Jeff Tinker8117d8f2013-08-16 13:46:02 -0700899 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
900 return NULL;
901 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700902 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800903}
904
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700905static void android_media_MediaDrm_removeKeys(
906 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
907 sp<IDrm> drm = GetDrm(env, thiz);
908
909 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700910 jniThrowException(env, "java/lang/IllegalArgumentException",
911 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700912 return;
913 }
914
915 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
916
917 status_t err = drm->removeKeys(keySetId);
918
919 throwExceptionAsNecessary(env, err, "Failed to remove keys");
920}
921
922static void android_media_MediaDrm_restoreKeys(
923 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
924 jbyteArray jkeysetId) {
925
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800926 sp<IDrm> drm = GetDrm(env, thiz);
927
928 if (!CheckSession(env, drm, jsessionId)) {
929 return;
930 }
931
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700932 if (jkeysetId == NULL) {
933 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
934 return;
935 }
936
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800937 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700938 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800939
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700940 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800941
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700942 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800943}
944
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700945static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800946 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
947 sp<IDrm> drm = GetDrm(env, thiz);
948
949 if (!CheckSession(env, drm, jsessionId)) {
950 return NULL;
951 }
952 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
953
954 KeyedVector<String8, String8> infoMap;
955
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700956 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800957
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700958 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800959 return NULL;
960 }
961
962 return KeyedVectorToHashMap(env, infoMap);
963}
964
Jeff Tinkere4095a82014-03-04 13:17:11 -0800965static jobject android_media_MediaDrm_getProvisionRequestNative(
966 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800967 sp<IDrm> drm = GetDrm(env, thiz);
968
969 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700970 jniThrowException(env, "java/lang/IllegalStateException",
971 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800972 return NULL;
973 }
974
975 Vector<uint8_t> request;
976 String8 defaultUrl;
977
Jeff Tinkere4095a82014-03-04 13:17:11 -0800978 String8 certType;
979 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
980 certType = "X.509";
981 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
982 certType = "none";
983 } else {
984 certType = "invalid";
985 }
986
987 String8 certAuthority = JStringToString8(env, jcertAuthority);
988 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800989
990 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
991 return NULL;
992 }
993
994 // Fill out return obj
995 jclass clazz;
996 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
997
998 jobject provisionObj = NULL;
999
1000 if (clazz) {
1001 provisionObj = env->AllocObject(clazz);
1002 jbyteArray jrequest = VectorToJByteArray(env, request);
1003 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1004
1005 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1006 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1007 }
1008
1009 return provisionObj;
1010}
1011
Jeff Tinkere4095a82014-03-04 13:17:11 -08001012static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001013 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
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 Tinkere4095a82014-03-04 13:17:11 -08001019 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001020 }
1021
1022 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001023 jniThrowException(env, "java/lang/IllegalArgumentException",
1024 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001025 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001026 }
1027
1028 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001029 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001030
Jeff Tinkere4095a82014-03-04 13:17:11 -08001031 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1032
1033 // Fill out return obj
1034 jclass clazz = gFields.certificateClassId;
1035
1036 jobject certificateObj = NULL;
1037
1038 if (clazz && certificate.size() && wrappedKey.size()) {
1039 certificateObj = env->AllocObject(clazz);
1040 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1041 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1042
1043 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1044 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1045 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001046
1047 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001048 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001049}
1050
Jeff Tinker6bf5b602014-04-30 10:02:39 -07001051static void android_media_MediaDrm_unprovisionDeviceNative(
1052 JNIEnv *env, jobject thiz) {
1053 sp<IDrm> drm = GetDrm(env, thiz);
1054
1055 if (drm == NULL) {
1056 jniThrowException(env, "java/lang/IllegalStateException",
1057 "MediaDrm obj is null");
1058 return;
1059 }
1060
1061 status_t err = drm->unprovisionDevice();
1062
1063 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
1064 return;
1065}
1066
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001067static jobject android_media_MediaDrm_getSecureStops(
1068 JNIEnv *env, jobject thiz) {
1069 sp<IDrm> drm = GetDrm(env, thiz);
1070
1071 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001072 jniThrowException(env, "java/lang/IllegalStateException",
1073 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001074 return NULL;
1075 }
1076
1077 List<Vector<uint8_t> > secureStops;
1078
1079 status_t err = drm->getSecureStops(secureStops);
1080
1081 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1082 return NULL;
1083 }
1084
1085 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1086}
1087
Jeff Tinker1b51c722014-10-31 00:54:26 -07001088static jbyteArray android_media_MediaDrm_getSecureStop(
1089 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1090 sp<IDrm> drm = GetDrm(env, thiz);
1091
1092 if (drm == NULL) {
1093 jniThrowException(env, "java/lang/IllegalStateException",
1094 "MediaDrm obj is null");
1095 return NULL;
1096 }
1097
1098 Vector<uint8_t> secureStop;
1099
1100 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1101
1102 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1103 return NULL;
1104 }
1105
1106 return VectorToJByteArray(env, secureStop);
1107}
1108
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001109static void android_media_MediaDrm_releaseSecureStops(
1110 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1111 sp<IDrm> drm = GetDrm(env, thiz);
1112
1113 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001114 jniThrowException(env, "java/lang/IllegalStateException",
1115 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001116 return;
1117 }
1118
1119 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1120
1121 status_t err = drm->releaseSecureStops(ssRelease);
1122
1123 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1124}
1125
Jeff Tinker1b51c722014-10-31 00:54:26 -07001126static void android_media_MediaDrm_releaseAllSecureStops(
1127 JNIEnv *env, jobject thiz) {
1128 sp<IDrm> drm = GetDrm(env, thiz);
1129
1130 if (drm == NULL) {
1131 jniThrowException(env, "java/lang/IllegalStateException",
1132 "MediaDrm obj is null");
1133 return;
1134 }
1135
1136 status_t err = drm->releaseAllSecureStops();
1137
1138 throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
1139}
1140
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001141static jstring android_media_MediaDrm_getPropertyString(
1142 JNIEnv *env, jobject thiz, jstring jname) {
1143 sp<IDrm> drm = GetDrm(env, thiz);
1144
1145 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001146 jniThrowException(env, "java/lang/IllegalStateException",
1147 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001148 return NULL;
1149 }
1150
1151 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001152 jniThrowException(env, "java/lang/IllegalArgumentException",
1153 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001154 return NULL;
1155 }
1156
1157 String8 name = JStringToString8(env, jname);
1158 String8 value;
1159
1160 status_t err = drm->getPropertyString(name, value);
1161
1162 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1163 return NULL;
1164 }
1165
1166 return env->NewStringUTF(value.string());
1167}
1168
1169static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1170 JNIEnv *env, jobject thiz, jstring jname) {
1171 sp<IDrm> drm = GetDrm(env, thiz);
1172
1173 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001174 jniThrowException(env, "java/lang/IllegalStateException",
1175 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001176 return NULL;
1177 }
1178
1179 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001180 jniThrowException(env, "java/lang/IllegalArgumentException",
1181 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001182 return NULL;
1183 }
1184
1185 String8 name = JStringToString8(env, jname);
1186 Vector<uint8_t> value;
1187
1188 status_t err = drm->getPropertyByteArray(name, value);
1189
1190 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1191 return NULL;
1192 }
1193
1194 return VectorToJByteArray(env, value);
1195}
1196
1197static void android_media_MediaDrm_setPropertyString(
1198 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1199 sp<IDrm> drm = GetDrm(env, thiz);
1200
1201 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001202 jniThrowException(env, "java/lang/IllegalStateException",
1203 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001204 return;
1205 }
1206
Jeff Tinkereada5372013-05-21 12:48:14 -07001207 if (jname == NULL) {
1208 jniThrowException(env, "java/lang/IllegalArgumentException",
1209 "property name String is null");
1210 return;
1211 }
1212
1213 if (jvalue == NULL) {
1214 jniThrowException(env, "java/lang/IllegalArgumentException",
1215 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001216 return;
1217 }
1218
1219 String8 name = JStringToString8(env, jname);
1220 String8 value = JStringToString8(env, jvalue);
1221
1222 status_t err = drm->setPropertyString(name, value);
1223
1224 throwExceptionAsNecessary(env, err, "Failed to set property");
1225}
1226
1227static void android_media_MediaDrm_setPropertyByteArray(
1228 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1229 sp<IDrm> drm = GetDrm(env, thiz);
1230
1231 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001232 jniThrowException(env, "java/lang/IllegalStateException",
1233 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001234 return;
1235 }
1236
Jeff Tinkereada5372013-05-21 12:48:14 -07001237 if (jname == NULL) {
1238 jniThrowException(env, "java/lang/IllegalArgumentException",
1239 "property name String is null");
1240 return;
1241 }
1242
1243 if (jvalue == NULL) {
1244 jniThrowException(env, "java/lang/IllegalArgumentException",
1245 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001246 return;
1247 }
1248
1249 String8 name = JStringToString8(env, jname);
1250 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1251
1252 status_t err = drm->setPropertyByteArray(name, value);
1253
1254 throwExceptionAsNecessary(env, err, "Failed to set property");
1255}
1256
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001257static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001258 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001259 jstring jalgorithm) {
1260
1261 sp<IDrm> drm = GetDrm(env, jdrm);
1262
1263 if (!CheckSession(env, drm, jsessionId)) {
1264 return;
1265 }
1266
1267 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001268 jniThrowException(env, "java/lang/IllegalArgumentException",
1269 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001270 return;
1271 }
1272
1273 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1274 String8 algorithm = JStringToString8(env, jalgorithm);
1275
1276 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1277
1278 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1279}
1280
1281static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001282 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001283 jstring jalgorithm) {
1284
1285 sp<IDrm> drm = GetDrm(env, jdrm);
1286
1287 if (!CheckSession(env, drm, jsessionId)) {
1288 return;
1289 }
1290
1291 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001292 jniThrowException(env, "java/lang/IllegalArgumentException",
1293 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001294 return;
1295 }
1296
1297 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1298 String8 algorithm = JStringToString8(env, jalgorithm);
1299
1300 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1301
1302 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1303}
1304
1305
1306static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001307 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001308 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1309
1310 sp<IDrm> drm = GetDrm(env, jdrm);
1311
1312 if (!CheckSession(env, drm, jsessionId)) {
1313 return NULL;
1314 }
1315
1316 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001317 jniThrowException(env, "java/lang/IllegalArgumentException",
1318 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001319 return NULL;
1320 }
1321
1322 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1323 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1324 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1325 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1326 Vector<uint8_t> output;
1327
1328 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1329
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001330 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1331 return NULL;
1332 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001333
1334 return VectorToJByteArray(env, output);
1335}
1336
1337static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001338 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001339 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1340
1341 sp<IDrm> drm = GetDrm(env, jdrm);
1342
1343 if (!CheckSession(env, drm, jsessionId)) {
1344 return NULL;
1345 }
1346
1347 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001348 jniThrowException(env, "java/lang/IllegalArgumentException",
1349 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001350 return NULL;
1351 }
1352
1353 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1354 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1355 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1356 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1357 Vector<uint8_t> output;
1358
1359 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001360 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1361 return NULL;
1362 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001363
1364 return VectorToJByteArray(env, output);
1365}
1366
1367static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001368 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001369 jbyteArray jkeyId, jbyteArray jmessage) {
1370
1371 sp<IDrm> drm = GetDrm(env, jdrm);
1372
1373 if (!CheckSession(env, drm, jsessionId)) {
1374 return NULL;
1375 }
1376
1377 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001378 jniThrowException(env, "java/lang/IllegalArgumentException",
1379 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001380 return NULL;
1381 }
1382
1383 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1384 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1385 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1386 Vector<uint8_t> signature;
1387
1388 status_t err = drm->sign(sessionId, keyId, message, signature);
1389
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001390 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1391 return NULL;
1392 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001393
1394 return VectorToJByteArray(env, signature);
1395}
1396
1397static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001398 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001399 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1400
1401 sp<IDrm> drm = GetDrm(env, jdrm);
1402
1403 if (!CheckSession(env, drm, jsessionId)) {
1404 return false;
1405 }
1406
1407 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001408 jniThrowException(env, "java/lang/IllegalArgumentException",
1409 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001410 return false;
1411 }
1412
1413 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1414 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1415 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1416 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1417 bool match;
1418
1419 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1420
1421 throwExceptionAsNecessary(env, err, "Failed to verify");
1422 return match;
1423}
1424
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001425
Jeff Tinkere4095a82014-03-04 13:17:11 -08001426static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001427 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001428 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1429
1430 sp<IDrm> drm = GetDrm(env, jdrm);
1431
1432 if (!CheckSession(env, drm, jsessionId)) {
1433 return NULL;
1434 }
1435
1436 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1437 jniThrowException(env, "java/lang/IllegalArgumentException",
1438 "required argument is null");
1439 return NULL;
1440 }
1441
1442 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1443 String8 algorithm = JStringToString8(env, jalgorithm);
1444 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1445 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1446 Vector<uint8_t> signature;
1447
1448 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1449
1450 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1451 return NULL;
1452 }
1453
1454 return VectorToJByteArray(env, signature);
1455}
1456
1457
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001458static JNINativeMethod gMethods[] = {
1459 { "release", "()V", (void *)android_media_MediaDrm_release },
1460 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1461
1462 { "native_setup", "(Ljava/lang/Object;[B)V",
1463 (void *)android_media_MediaDrm_native_setup },
1464
1465 { "native_finalize", "()V",
1466 (void *)android_media_MediaDrm_native_finalize },
1467
Jeff Tinker7cda4912013-08-21 11:52:34 -07001468 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001469 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1470
1471 { "openSession", "()[B",
1472 (void *)android_media_MediaDrm_openSession },
1473
1474 { "closeSession", "([B)V",
1475 (void *)android_media_MediaDrm_closeSession },
1476
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001477 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1478 "Landroid/media/MediaDrm$KeyRequest;",
1479 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001480
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001481 { "provideKeyResponse", "([B[B)[B",
1482 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001483
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001484 { "removeKeys", "([B)V",
1485 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001486
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001487 { "restoreKeys", "([B[B)V",
1488 (void *)android_media_MediaDrm_restoreKeys },
1489
1490 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1491 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001492
Jeff Tinkere4095a82014-03-04 13:17:11 -08001493 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1494 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001495
Jeff Tinkere4095a82014-03-04 13:17:11 -08001496 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1497 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001498
Jeff Tinker6bf5b602014-04-30 10:02:39 -07001499 { "unprovisionDevice", "()V",
1500 (void *)android_media_MediaDrm_unprovisionDeviceNative },
1501
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001502 { "getSecureStops", "()Ljava/util/List;",
1503 (void *)android_media_MediaDrm_getSecureStops },
1504
Jeff Tinker1b51c722014-10-31 00:54:26 -07001505 { "getSecureStop", "([B)[B",
1506 (void *)android_media_MediaDrm_getSecureStop },
1507
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001508 { "releaseSecureStops", "([B)V",
1509 (void *)android_media_MediaDrm_releaseSecureStops },
1510
Jeff Tinker1b51c722014-10-31 00:54:26 -07001511 { "releaseAllSecureStops", "()V",
1512 (void *)android_media_MediaDrm_releaseAllSecureStops },
1513
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001514 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1515 (void *)android_media_MediaDrm_getPropertyString },
1516
1517 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1518 (void *)android_media_MediaDrm_getPropertyByteArray },
1519
1520 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1521 (void *)android_media_MediaDrm_setPropertyString },
1522
1523 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1524 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001525
1526 { "setCipherAlgorithmNative",
1527 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1528 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1529
1530 { "setMacAlgorithmNative",
1531 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1532 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1533
1534 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1535 (void *)android_media_MediaDrm_encryptNative },
1536
1537 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1538 (void *)android_media_MediaDrm_decryptNative },
1539
1540 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1541 (void *)android_media_MediaDrm_signNative },
1542
1543 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1544 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08001545
1546 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1547 (void *)android_media_MediaDrm_signRSANative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001548};
1549
1550int register_android_media_Drm(JNIEnv *env) {
1551 return AndroidRuntime::registerNativeMethods(env,
1552 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1553}