blob: d456dc1080d2ab13cf10c1fb880935031d836f7c [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 Tinker8a0c80f2013-02-08 10:20:44 -0800311 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700312 String8 errbuf;
313 if (drmMessage != NULL) {
314 if (msg == NULL) {
315 msg = drmMessage;
316 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700317 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700318 msg = errbuf.string();
319 }
320 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700321 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800322 return true;
323 }
324 return false;
325}
326
327static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000328 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800329 return jdrm ? jdrm->getDrm() : NULL;
330}
331
332JDrm::JDrm(
333 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
334 mObject = env->NewWeakGlobalRef(thiz);
335 mDrm = MakeDrm(uuid);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700336 if (mDrm != NULL) {
337 mDrm->setListener(this);
338 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800339}
340
341JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800342 JNIEnv *env = AndroidRuntime::getJNIEnv();
343
344 env->DeleteWeakGlobalRef(mObject);
345 mObject = NULL;
346}
347
348// static
349sp<IDrm> JDrm::MakeDrm() {
350 sp<IServiceManager> sm = defaultServiceManager();
351
352 sp<IBinder> binder =
353 sm->getService(String16("media.player"));
354
355 sp<IMediaPlayerService> service =
356 interface_cast<IMediaPlayerService>(binder);
357
358 if (service == NULL) {
359 return NULL;
360 }
361
362 sp<IDrm> drm = service->makeDrm();
363
364 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
365 return NULL;
366 }
367
368 return drm;
369}
370
371// static
372sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
373 sp<IDrm> drm = MakeDrm();
374
375 if (drm == NULL) {
376 return NULL;
377 }
378
379 status_t err = drm->createPlugin(uuid);
380
381 if (err != OK) {
382 return NULL;
383 }
384
385 return drm;
386}
387
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700388status_t JDrm::setListener(const sp<DrmListener>& listener) {
389 Mutex::Autolock lock(mLock);
390 mListener = listener;
391 return OK;
392}
393
394void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
395 sp<DrmListener> listener;
396 mLock.lock();
397 listener = mListener;
398 mLock.unlock();
399
400 if (listener != NULL) {
401 Mutex::Autolock lock(mNotifyLock);
402 listener->notify(eventType, extra, obj);
403 }
404}
405
Jeff Tinker600071c2014-04-11 16:11:15 -0700406void JDrm::disconnect() {
407 if (mDrm != NULL) {
408 mDrm->destroyPlugin();
409 mDrm.clear();
410 }
411}
412
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700413
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800414// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700415bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800416 sp<IDrm> drm = MakeDrm();
417
418 if (drm == NULL) {
419 return false;
420 }
421
Jeff Tinker7cda4912013-08-21 11:52:34 -0700422 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800423}
424
425status_t JDrm::initCheck() const {
426 return mDrm == NULL ? NO_INIT : OK;
427}
428
429// JNI conversion utilities
430static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
431 Vector<uint8_t> vector;
432 size_t length = env->GetArrayLength(byteArray);
433 vector.insertAt((size_t)0, length);
434 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
435 return vector;
436}
437
438static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
439 size_t length = vector.size();
440 jbyteArray result = env->NewByteArray(length);
441 if (result != NULL) {
442 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
443 }
444 return result;
445}
446
447static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800448 String8 result;
449
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700450 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800451 if (s) {
452 result = s;
453 env->ReleaseStringUTFChars(jstr, s);
454 }
455 return result;
456}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700457
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800458/*
459 import java.util.HashMap;
460 import java.util.Set;
461 import java.Map.Entry;
462 import jav.util.Iterator;
463
464 HashMap<k, v> hm;
465 Set<Entry<k, v> > s = hm.entrySet();
466 Iterator i = s.iterator();
467 Entry e = s.next();
468*/
469
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200470static KeyedVector<String8, String8> HashMapToKeyedVector(
471 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800472 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800473 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200474 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800475
476 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
477 if (entrySet) {
478 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
479 if (iterator) {
480 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
481 while (hasNext) {
482 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
483 if (entry) {
484 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200485 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700486 jniThrowException(env, "java/lang/IllegalArgumentException",
487 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200488 env->DeleteLocalRef(entry);
489 *pIsOK = false;
490 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800491 }
492 jstring jkey = static_cast<jstring>(obj);
493
494 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200495 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700496 jniThrowException(env, "java/lang/IllegalArgumentException",
497 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200498 env->DeleteLocalRef(entry);
499 *pIsOK = false;
500 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800501 }
502 jstring jvalue = static_cast<jstring>(obj);
503
504 String8 key = JStringToString8(env, jkey);
505 String8 value = JStringToString8(env, jvalue);
506 keyedVector.add(key, value);
507
508 env->DeleteLocalRef(jkey);
509 env->DeleteLocalRef(jvalue);
510 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
511 }
512 env->DeleteLocalRef(entry);
513 }
514 env->DeleteLocalRef(iterator);
515 }
516 env->DeleteLocalRef(entrySet);
517 }
518 return keyedVector;
519}
520
521static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800522 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800523 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
524 for (size_t i = 0; i < map.size(); ++i) {
525 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
526 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
527 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
528 env->DeleteLocalRef(jkey);
529 env->DeleteLocalRef(jvalue);
530 }
531 return hashMap;
532}
533
534static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
535 List<Vector<uint8_t> > list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800536 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800537 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
538 List<Vector<uint8_t> >::iterator iter = list.begin();
539 while (iter != list.end()) {
540 jbyteArray byteArray = VectorToJByteArray(env, *iter);
541 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
542 env->DeleteLocalRef(byteArray);
543 iter++;
544 }
545
546 return arrayList;
547}
548
549} // namespace android
550
551using namespace android;
552
553static sp<JDrm> setDrm(
554 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000555 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800556 if (drm != NULL) {
557 drm->incStrong(thiz);
558 }
559 if (old != NULL) {
560 old->decStrong(thiz);
561 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000562 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800563
564 return old;
565}
566
567static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
568{
569 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700570 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800571 return false;
572 }
573
574 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700575 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800576 return false;
577 }
578 return true;
579}
580
581static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700582 sp<JDrm> drm = setDrm(env, thiz, NULL);
583 if (drm != NULL) {
584 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700585 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700586 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800587}
588
589static void android_media_MediaDrm_native_init(JNIEnv *env) {
590 jclass clazz;
591 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000592 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700593 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700594 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700595
596 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700597 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700598 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700599 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700600 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700601 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700602 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700603 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700604 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800605 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
606 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800607
Jeff Tinker74797f82015-03-31 15:44:34 -0700608 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
609 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
610 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
611 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700612 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
613 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700614
Jeff Tinker17b89222013-05-21 12:35:06 -0700615 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
616 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
617 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
618 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
619 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
620 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
621
Jeff Tinkere4095a82014-03-04 13:17:11 -0800622 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
623 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
624 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
625 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
626
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700627 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700628 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
629 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700630 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800631
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700632 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
633 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
634 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
635 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
636 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
637 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
638
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800639 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700640 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
641 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800642
Jeff Tinkere4095a82014-03-04 13:17:11 -0800643 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
644 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
645 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700646 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800647
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800648 FIND_CLASS(clazz, "java/util/ArrayList");
649 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
650 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
651
652 FIND_CLASS(clazz, "java/util/HashMap");
653 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
654 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
655 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
656 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
657 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
658
659 FIND_CLASS(clazz, "java/util/Set");
660 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
661
662 FIND_CLASS(clazz, "java/util/Iterator");
663 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
664 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
665
666 FIND_CLASS(clazz, "java/util/Map$Entry");
667 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
668 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800669
670 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700671 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800672
673 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700674 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800675
676 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700677 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700678
679 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
680 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
681 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800682}
683
684static void android_media_MediaDrm_native_setup(
685 JNIEnv *env, jobject thiz,
686 jobject weak_this, jbyteArray uuidObj) {
687
688 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700689 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800690 return;
691 }
692
693 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
694
695 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700696 jniThrowException(env, "java/lang/IllegalArgumentException",
697 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800698 return;
699 }
700
701 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
702
703 status_t err = drm->initCheck();
704
705 if (err != OK) {
706 jniThrowException(
707 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700708 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800709 "Failed to instantiate drm object.");
710 return;
711 }
712
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700713 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
714 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800715 setDrm(env, thiz, drm);
716}
717
718static void android_media_MediaDrm_native_finalize(
719 JNIEnv *env, jobject thiz) {
720 android_media_MediaDrm_release(env, thiz);
721}
722
723static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800724 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800725
726 if (uuidObj == NULL) {
727 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
728 return false;
729 }
730
731 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
732
733 if (uuid.size() != 16) {
734 jniThrowException(
735 env,
736 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700737 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800738 return false;
739 }
740
Jeff Tinker7cda4912013-08-21 11:52:34 -0700741 String8 mimeType;
742 if (jmimeType != NULL) {
743 mimeType = JStringToString8(env, jmimeType);
744 }
745
746 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800747}
748
749static jbyteArray android_media_MediaDrm_openSession(
750 JNIEnv *env, jobject thiz) {
751 sp<IDrm> drm = GetDrm(env, thiz);
752
753 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700754 jniThrowException(env, "java/lang/IllegalStateException",
755 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800756 return NULL;
757 }
758
759 Vector<uint8_t> sessionId;
760 status_t err = drm->openSession(sessionId);
761
762 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
763 return NULL;
764 }
765
766 return VectorToJByteArray(env, sessionId);
767}
768
769static void android_media_MediaDrm_closeSession(
770 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
771 sp<IDrm> drm = GetDrm(env, thiz);
772
773 if (!CheckSession(env, drm, jsessionId)) {
774 return;
775 }
776
777 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
778
779 status_t err = drm->closeSession(sessionId);
780
781 throwExceptionAsNecessary(env, err, "Failed to close session");
782}
783
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700784static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800785 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700786 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800787 sp<IDrm> drm = GetDrm(env, thiz);
788
789 if (!CheckSession(env, drm, jsessionId)) {
790 return NULL;
791 }
792
793 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
794
795 Vector<uint8_t> initData;
796 if (jinitData != NULL) {
797 initData = JByteArrayToVector(env, jinitData);
798 }
799
800 String8 mimeType;
801 if (jmimeType != NULL) {
802 mimeType = JStringToString8(env, jmimeType);
803 }
804
Jeff Tinker17b89222013-05-21 12:35:06 -0700805 DrmPlugin::KeyType keyType;
806 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
807 keyType = DrmPlugin::kKeyType_Streaming;
808 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
809 keyType = DrmPlugin::kKeyType_Offline;
810 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
811 keyType = DrmPlugin::kKeyType_Release;
812 } else {
813 jniThrowException(env, "java/lang/IllegalArgumentException",
814 "invalid keyType");
815 return NULL;
816 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800817
818 KeyedVector<String8, String8> optParams;
819 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200820 bool isOK;
821 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
822 if (!isOK) {
823 return NULL;
824 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800825 }
826
827 Vector<uint8_t> request;
828 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700829 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800830
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700831 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700832 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800833
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700834 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800835 return NULL;
836 }
837
838 // Fill out return obj
839 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700840 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800841
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700842 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800843
844 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700845 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800846 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700847 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800848
849 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700850 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700851
852 switch (keyRequestType) {
853 case DrmPlugin::kKeyRequestType_Initial:
854 env->SetIntField(keyObj, gFields.keyRequest.requestType,
855 gKeyRequestTypes.kKeyRequestTypeInitial);
856 break;
857 case DrmPlugin::kKeyRequestType_Renewal:
858 env->SetIntField(keyObj, gFields.keyRequest.requestType,
859 gKeyRequestTypes.kKeyRequestTypeRenewal);
860 break;
861 case DrmPlugin::kKeyRequestType_Release:
862 env->SetIntField(keyObj, gFields.keyRequest.requestType,
863 gKeyRequestTypes.kKeyRequestTypeRelease);
864 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700865 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700866 throwStateException(env, "DRM plugin failure: unknown key request type",
867 ERROR_DRM_UNKNOWN);
868 break;
869 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800870 }
871
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700872 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800873}
874
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700875static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800876 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
877 sp<IDrm> drm = GetDrm(env, thiz);
878
879 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700880 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800881 }
882
883 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
884
885 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700886 jniThrowException(env, "java/lang/IllegalArgumentException",
887 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700888 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800889 }
890 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700891 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800892
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700893 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800894
Jeff Tinker8117d8f2013-08-16 13:46:02 -0700895 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
896 return NULL;
897 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700898 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800899}
900
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700901static void android_media_MediaDrm_removeKeys(
902 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
903 sp<IDrm> drm = GetDrm(env, thiz);
904
905 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700906 jniThrowException(env, "java/lang/IllegalArgumentException",
907 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700908 return;
909 }
910
911 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
912
913 status_t err = drm->removeKeys(keySetId);
914
915 throwExceptionAsNecessary(env, err, "Failed to remove keys");
916}
917
918static void android_media_MediaDrm_restoreKeys(
919 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
920 jbyteArray jkeysetId) {
921
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800922 sp<IDrm> drm = GetDrm(env, thiz);
923
924 if (!CheckSession(env, drm, jsessionId)) {
925 return;
926 }
927
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700928 if (jkeysetId == NULL) {
929 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
930 return;
931 }
932
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800933 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700934 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800935
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700936 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800937
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700938 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800939}
940
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700941static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800942 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
943 sp<IDrm> drm = GetDrm(env, thiz);
944
945 if (!CheckSession(env, drm, jsessionId)) {
946 return NULL;
947 }
948 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
949
950 KeyedVector<String8, String8> infoMap;
951
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700952 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800953
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700954 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800955 return NULL;
956 }
957
958 return KeyedVectorToHashMap(env, infoMap);
959}
960
Jeff Tinkere4095a82014-03-04 13:17:11 -0800961static jobject android_media_MediaDrm_getProvisionRequestNative(
962 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800963 sp<IDrm> drm = GetDrm(env, thiz);
964
965 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700966 jniThrowException(env, "java/lang/IllegalStateException",
967 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800968 return NULL;
969 }
970
971 Vector<uint8_t> request;
972 String8 defaultUrl;
973
Jeff Tinkere4095a82014-03-04 13:17:11 -0800974 String8 certType;
975 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
976 certType = "X.509";
977 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
978 certType = "none";
979 } else {
980 certType = "invalid";
981 }
982
983 String8 certAuthority = JStringToString8(env, jcertAuthority);
984 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800985
986 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
987 return NULL;
988 }
989
990 // Fill out return obj
991 jclass clazz;
992 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
993
994 jobject provisionObj = NULL;
995
996 if (clazz) {
997 provisionObj = env->AllocObject(clazz);
998 jbyteArray jrequest = VectorToJByteArray(env, request);
999 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1000
1001 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1002 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1003 }
1004
1005 return provisionObj;
1006}
1007
Jeff Tinkere4095a82014-03-04 13:17:11 -08001008static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001009 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1010 sp<IDrm> drm = GetDrm(env, thiz);
1011
1012 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001013 jniThrowException(env, "java/lang/IllegalStateException",
1014 "MediaDrm obj is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001015 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001016 }
1017
1018 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001019 jniThrowException(env, "java/lang/IllegalArgumentException",
1020 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001021 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001022 }
1023
1024 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001025 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001026
Jeff Tinkere4095a82014-03-04 13:17:11 -08001027 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1028
1029 // Fill out return obj
1030 jclass clazz = gFields.certificateClassId;
1031
1032 jobject certificateObj = NULL;
1033
1034 if (clazz && certificate.size() && wrappedKey.size()) {
1035 certificateObj = env->AllocObject(clazz);
1036 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1037 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1038
1039 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1040 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1041 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001042
1043 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001044 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001045}
1046
Jeff Tinker6bf5b602014-04-30 10:02:39 -07001047static void android_media_MediaDrm_unprovisionDeviceNative(
1048 JNIEnv *env, jobject thiz) {
1049 sp<IDrm> drm = GetDrm(env, thiz);
1050
1051 if (drm == NULL) {
1052 jniThrowException(env, "java/lang/IllegalStateException",
1053 "MediaDrm obj is null");
1054 return;
1055 }
1056
1057 status_t err = drm->unprovisionDevice();
1058
1059 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
1060 return;
1061}
1062
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001063static jobject android_media_MediaDrm_getSecureStops(
1064 JNIEnv *env, jobject thiz) {
1065 sp<IDrm> drm = GetDrm(env, thiz);
1066
1067 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001068 jniThrowException(env, "java/lang/IllegalStateException",
1069 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001070 return NULL;
1071 }
1072
1073 List<Vector<uint8_t> > secureStops;
1074
1075 status_t err = drm->getSecureStops(secureStops);
1076
1077 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1078 return NULL;
1079 }
1080
1081 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1082}
1083
Jeff Tinker1b51c722014-10-31 00:54:26 -07001084static jbyteArray android_media_MediaDrm_getSecureStop(
1085 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1086 sp<IDrm> drm = GetDrm(env, thiz);
1087
1088 if (drm == NULL) {
1089 jniThrowException(env, "java/lang/IllegalStateException",
1090 "MediaDrm obj is null");
1091 return NULL;
1092 }
1093
1094 Vector<uint8_t> secureStop;
1095
1096 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1097
1098 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1099 return NULL;
1100 }
1101
1102 return VectorToJByteArray(env, secureStop);
1103}
1104
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001105static void android_media_MediaDrm_releaseSecureStops(
1106 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1107 sp<IDrm> drm = GetDrm(env, thiz);
1108
1109 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001110 jniThrowException(env, "java/lang/IllegalStateException",
1111 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001112 return;
1113 }
1114
1115 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1116
1117 status_t err = drm->releaseSecureStops(ssRelease);
1118
1119 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1120}
1121
Jeff Tinker1b51c722014-10-31 00:54:26 -07001122static void android_media_MediaDrm_releaseAllSecureStops(
1123 JNIEnv *env, jobject thiz) {
1124 sp<IDrm> drm = GetDrm(env, thiz);
1125
1126 if (drm == NULL) {
1127 jniThrowException(env, "java/lang/IllegalStateException",
1128 "MediaDrm obj is null");
1129 return;
1130 }
1131
1132 status_t err = drm->releaseAllSecureStops();
1133
1134 throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
1135}
1136
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001137static jstring android_media_MediaDrm_getPropertyString(
1138 JNIEnv *env, jobject thiz, jstring jname) {
1139 sp<IDrm> drm = GetDrm(env, thiz);
1140
1141 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001142 jniThrowException(env, "java/lang/IllegalStateException",
1143 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001144 return NULL;
1145 }
1146
1147 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001148 jniThrowException(env, "java/lang/IllegalArgumentException",
1149 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001150 return NULL;
1151 }
1152
1153 String8 name = JStringToString8(env, jname);
1154 String8 value;
1155
1156 status_t err = drm->getPropertyString(name, value);
1157
1158 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1159 return NULL;
1160 }
1161
1162 return env->NewStringUTF(value.string());
1163}
1164
1165static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1166 JNIEnv *env, jobject thiz, jstring jname) {
1167 sp<IDrm> drm = GetDrm(env, thiz);
1168
1169 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001170 jniThrowException(env, "java/lang/IllegalStateException",
1171 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001172 return NULL;
1173 }
1174
1175 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001176 jniThrowException(env, "java/lang/IllegalArgumentException",
1177 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001178 return NULL;
1179 }
1180
1181 String8 name = JStringToString8(env, jname);
1182 Vector<uint8_t> value;
1183
1184 status_t err = drm->getPropertyByteArray(name, value);
1185
1186 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1187 return NULL;
1188 }
1189
1190 return VectorToJByteArray(env, value);
1191}
1192
1193static void android_media_MediaDrm_setPropertyString(
1194 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1195 sp<IDrm> drm = GetDrm(env, thiz);
1196
1197 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001198 jniThrowException(env, "java/lang/IllegalStateException",
1199 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001200 return;
1201 }
1202
Jeff Tinkereada5372013-05-21 12:48:14 -07001203 if (jname == NULL) {
1204 jniThrowException(env, "java/lang/IllegalArgumentException",
1205 "property name String is null");
1206 return;
1207 }
1208
1209 if (jvalue == NULL) {
1210 jniThrowException(env, "java/lang/IllegalArgumentException",
1211 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001212 return;
1213 }
1214
1215 String8 name = JStringToString8(env, jname);
1216 String8 value = JStringToString8(env, jvalue);
1217
1218 status_t err = drm->setPropertyString(name, value);
1219
1220 throwExceptionAsNecessary(env, err, "Failed to set property");
1221}
1222
1223static void android_media_MediaDrm_setPropertyByteArray(
1224 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1225 sp<IDrm> drm = GetDrm(env, thiz);
1226
1227 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001228 jniThrowException(env, "java/lang/IllegalStateException",
1229 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001230 return;
1231 }
1232
Jeff Tinkereada5372013-05-21 12:48:14 -07001233 if (jname == NULL) {
1234 jniThrowException(env, "java/lang/IllegalArgumentException",
1235 "property name String is null");
1236 return;
1237 }
1238
1239 if (jvalue == NULL) {
1240 jniThrowException(env, "java/lang/IllegalArgumentException",
1241 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001242 return;
1243 }
1244
1245 String8 name = JStringToString8(env, jname);
1246 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1247
1248 status_t err = drm->setPropertyByteArray(name, value);
1249
1250 throwExceptionAsNecessary(env, err, "Failed to set property");
1251}
1252
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001253static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001254 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001255 jstring jalgorithm) {
1256
1257 sp<IDrm> drm = GetDrm(env, jdrm);
1258
1259 if (!CheckSession(env, drm, jsessionId)) {
1260 return;
1261 }
1262
1263 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001264 jniThrowException(env, "java/lang/IllegalArgumentException",
1265 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001266 return;
1267 }
1268
1269 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1270 String8 algorithm = JStringToString8(env, jalgorithm);
1271
1272 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1273
1274 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1275}
1276
1277static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001278 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001279 jstring jalgorithm) {
1280
1281 sp<IDrm> drm = GetDrm(env, jdrm);
1282
1283 if (!CheckSession(env, drm, jsessionId)) {
1284 return;
1285 }
1286
1287 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001288 jniThrowException(env, "java/lang/IllegalArgumentException",
1289 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001290 return;
1291 }
1292
1293 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1294 String8 algorithm = JStringToString8(env, jalgorithm);
1295
1296 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1297
1298 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1299}
1300
1301
1302static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001303 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001304 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1305
1306 sp<IDrm> drm = GetDrm(env, jdrm);
1307
1308 if (!CheckSession(env, drm, jsessionId)) {
1309 return NULL;
1310 }
1311
1312 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001313 jniThrowException(env, "java/lang/IllegalArgumentException",
1314 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001315 return NULL;
1316 }
1317
1318 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1319 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1320 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1321 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1322 Vector<uint8_t> output;
1323
1324 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1325
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001326 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1327 return NULL;
1328 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001329
1330 return VectorToJByteArray(env, output);
1331}
1332
1333static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001334 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001335 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1336
1337 sp<IDrm> drm = GetDrm(env, jdrm);
1338
1339 if (!CheckSession(env, drm, jsessionId)) {
1340 return NULL;
1341 }
1342
1343 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001344 jniThrowException(env, "java/lang/IllegalArgumentException",
1345 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001346 return NULL;
1347 }
1348
1349 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1350 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1351 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1352 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1353 Vector<uint8_t> output;
1354
1355 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001356 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1357 return NULL;
1358 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001359
1360 return VectorToJByteArray(env, output);
1361}
1362
1363static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001364 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001365 jbyteArray jkeyId, jbyteArray jmessage) {
1366
1367 sp<IDrm> drm = GetDrm(env, jdrm);
1368
1369 if (!CheckSession(env, drm, jsessionId)) {
1370 return NULL;
1371 }
1372
1373 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001374 jniThrowException(env, "java/lang/IllegalArgumentException",
1375 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001376 return NULL;
1377 }
1378
1379 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1380 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1381 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1382 Vector<uint8_t> signature;
1383
1384 status_t err = drm->sign(sessionId, keyId, message, signature);
1385
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001386 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1387 return NULL;
1388 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001389
1390 return VectorToJByteArray(env, signature);
1391}
1392
1393static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001394 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001395 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1396
1397 sp<IDrm> drm = GetDrm(env, jdrm);
1398
1399 if (!CheckSession(env, drm, jsessionId)) {
1400 return false;
1401 }
1402
1403 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001404 jniThrowException(env, "java/lang/IllegalArgumentException",
1405 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001406 return false;
1407 }
1408
1409 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1410 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1411 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1412 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1413 bool match;
1414
1415 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1416
1417 throwExceptionAsNecessary(env, err, "Failed to verify");
1418 return match;
1419}
1420
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001421
Jeff Tinkere4095a82014-03-04 13:17:11 -08001422static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001423 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001424 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1425
1426 sp<IDrm> drm = GetDrm(env, jdrm);
1427
1428 if (!CheckSession(env, drm, jsessionId)) {
1429 return NULL;
1430 }
1431
1432 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1433 jniThrowException(env, "java/lang/IllegalArgumentException",
1434 "required argument is null");
1435 return NULL;
1436 }
1437
1438 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1439 String8 algorithm = JStringToString8(env, jalgorithm);
1440 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1441 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1442 Vector<uint8_t> signature;
1443
1444 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1445
1446 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1447 return NULL;
1448 }
1449
1450 return VectorToJByteArray(env, signature);
1451}
1452
1453
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001454static JNINativeMethod gMethods[] = {
1455 { "release", "()V", (void *)android_media_MediaDrm_release },
1456 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1457
1458 { "native_setup", "(Ljava/lang/Object;[B)V",
1459 (void *)android_media_MediaDrm_native_setup },
1460
1461 { "native_finalize", "()V",
1462 (void *)android_media_MediaDrm_native_finalize },
1463
Jeff Tinker7cda4912013-08-21 11:52:34 -07001464 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001465 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1466
1467 { "openSession", "()[B",
1468 (void *)android_media_MediaDrm_openSession },
1469
1470 { "closeSession", "([B)V",
1471 (void *)android_media_MediaDrm_closeSession },
1472
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001473 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1474 "Landroid/media/MediaDrm$KeyRequest;",
1475 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001476
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001477 { "provideKeyResponse", "([B[B)[B",
1478 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001479
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001480 { "removeKeys", "([B)V",
1481 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001482
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001483 { "restoreKeys", "([B[B)V",
1484 (void *)android_media_MediaDrm_restoreKeys },
1485
1486 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1487 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001488
Jeff Tinkere4095a82014-03-04 13:17:11 -08001489 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1490 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001491
Jeff Tinkere4095a82014-03-04 13:17:11 -08001492 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1493 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001494
Jeff Tinker6bf5b602014-04-30 10:02:39 -07001495 { "unprovisionDevice", "()V",
1496 (void *)android_media_MediaDrm_unprovisionDeviceNative },
1497
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001498 { "getSecureStops", "()Ljava/util/List;",
1499 (void *)android_media_MediaDrm_getSecureStops },
1500
Jeff Tinker1b51c722014-10-31 00:54:26 -07001501 { "getSecureStop", "([B)[B",
1502 (void *)android_media_MediaDrm_getSecureStop },
1503
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001504 { "releaseSecureStops", "([B)V",
1505 (void *)android_media_MediaDrm_releaseSecureStops },
1506
Jeff Tinker1b51c722014-10-31 00:54:26 -07001507 { "releaseAllSecureStops", "()V",
1508 (void *)android_media_MediaDrm_releaseAllSecureStops },
1509
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001510 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1511 (void *)android_media_MediaDrm_getPropertyString },
1512
1513 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1514 (void *)android_media_MediaDrm_getPropertyByteArray },
1515
1516 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1517 (void *)android_media_MediaDrm_setPropertyString },
1518
1519 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1520 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001521
1522 { "setCipherAlgorithmNative",
1523 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1524 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1525
1526 { "setMacAlgorithmNative",
1527 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1528 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1529
1530 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1531 (void *)android_media_MediaDrm_encryptNative },
1532
1533 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1534 (void *)android_media_MediaDrm_decryptNative },
1535
1536 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1537 (void *)android_media_MediaDrm_signNative },
1538
1539 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1540 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08001541
1542 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1543 (void *)android_media_MediaDrm_signRSANative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001544};
1545
1546int register_android_media_Drm(JNIEnv *env) {
1547 return AndroidRuntime::registerNativeMethods(env,
1548 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1549}