blob: 73ddedf2bec12f68b62a3d0ceadeda7d6ac1562a [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 Tinkerdc614f82016-02-12 08:58:32 -080031#include <cutils/properties.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080032#include <media/IDrm.h>
Jeff Tinkerdc614f82016-02-12 08:58:32 -080033#include <media/IMediaDrmService.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080034#include <media/IMediaPlayerService.h>
35#include <media/stagefright/foundation/ADebug.h>
Jeff Tinkerf7568b52013-04-17 14:24:40 -070036#include <media/stagefright/MediaErrors.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080037
38namespace android {
39
40#define FIND_CLASS(var, className) \
41 var = env->FindClass(className); \
42 LOG_FATAL_IF(! var, "Unable to find class " className);
43
44#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
45 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
46 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
47
48#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
49 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
50 LOG_FATAL_IF(! var, "Unable to find method " fieldName);
51
Jeff Tinker54cfbd62013-04-02 13:14:59 -070052#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
53 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
54 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
55
56#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
57 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
58 LOG_FATAL_IF(! var, "Unable to find static method " fieldName);
59
60
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080061struct RequestFields {
62 jfieldID data;
63 jfieldID defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -070064 jfieldID requestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080065};
66
67struct ArrayListFields {
68 jmethodID init;
69 jmethodID add;
70};
71
72struct HashmapFields {
73 jmethodID init;
74 jmethodID get;
75 jmethodID put;
76 jmethodID entrySet;
77};
78
79struct SetFields {
80 jmethodID iterator;
81};
82
83struct IteratorFields {
84 jmethodID next;
85 jmethodID hasNext;
86};
87
88struct EntryFields {
89 jmethodID getKey;
90 jmethodID getValue;
91};
92
Jeff Tinker54cfbd62013-04-02 13:14:59 -070093struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -070094 jint kEventProvisionRequired;
95 jint kEventKeyRequired;
96 jint kEventKeyExpired;
97 jint kEventVendorDefined;
Ronghua Wua6d72092015-03-04 11:16:02 -080098 jint kEventSessionReclaimed;
Jeff Tinker54cfbd62013-04-02 13:14:59 -070099} gEventTypes;
100
Jeff Tinker74797f82015-03-31 15:44:34 -0700101struct EventWhat {
102 jint kWhatDrmEvent;
103 jint kWhatExpirationUpdate;
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700104 jint kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700105} gEventWhat;
106
Jeff Tinker17b89222013-05-21 12:35:06 -0700107struct KeyTypes {
108 jint kKeyTypeStreaming;
109 jint kKeyTypeOffline;
110 jint kKeyTypeRelease;
111} gKeyTypes;
112
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700113struct KeyRequestTypes {
114 jint kKeyRequestTypeInitial;
115 jint kKeyRequestTypeRenewal;
116 jint kKeyRequestTypeRelease;
117} gKeyRequestTypes;
118
Jeff Tinkere4095a82014-03-04 13:17:11 -0800119struct CertificateTypes {
120 jint kCertificateTypeNone;
121 jint kCertificateTypeX509;
122} gCertificateTypes;
123
124struct CertificateFields {
125 jfieldID wrappedPrivateKey;
126 jfieldID certificateData;
127};
128
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700129struct StateExceptionFields {
130 jmethodID init;
131 jclass classId;
132};
133
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800134struct fields_t {
135 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700136 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700137 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800138 RequestFields provisionRequest;
139 ArrayListFields arraylist;
140 HashmapFields hashmap;
141 SetFields set;
142 IteratorFields iterator;
143 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800144 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700145 StateExceptionFields stateException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800146 jclass certificateClassId;
147 jclass hashmapClassId;
148 jclass arraylistClassId;
149 jclass stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800150};
151
152static fields_t gFields;
153
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700154// ----------------------------------------------------------------------------
155// ref-counted object for callbacks
156class JNIDrmListener: public DrmListener
157{
158public:
159 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
160 ~JNIDrmListener();
161 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
162private:
163 JNIDrmListener();
164 jclass mClass; // Reference to MediaDrm class
165 jobject mObject; // Weak ref to MediaDrm Java object to call on
166};
167
168JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
169{
170 // Hold onto the MediaDrm class for use in calling the static method
171 // that posts events to the application thread.
172 jclass clazz = env->GetObjectClass(thiz);
173 if (clazz == NULL) {
174 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700175 jniThrowException(env, "java/lang/Exception",
176 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700177 return;
178 }
179 mClass = (jclass)env->NewGlobalRef(clazz);
180
181 // We use a weak reference so the MediaDrm object can be garbage collected.
182 // The reference is only used as a proxy for callbacks.
183 mObject = env->NewGlobalRef(weak_thiz);
184}
185
186JNIDrmListener::~JNIDrmListener()
187{
188 // remove global references
189 JNIEnv *env = AndroidRuntime::getJNIEnv();
190 env->DeleteGlobalRef(mObject);
191 env->DeleteGlobalRef(mClass);
192}
193
194void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
195 const Parcel *obj)
196{
Jeff Tinker74797f82015-03-31 15:44:34 -0700197 jint jwhat;
198 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700199
200 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700201 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700202 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700203 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700204 jeventType = gEventTypes.kEventProvisionRequired;
205 break;
206 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700207 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700208 jeventType = gEventTypes.kEventKeyRequired;
209 break;
210 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700211 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700212 jeventType = gEventTypes.kEventKeyExpired;
213 break;
214 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700215 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700216 jeventType = gEventTypes.kEventVendorDefined;
217 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800218 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700219 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800220 jeventType = gEventTypes.kEventSessionReclaimed;
221 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700222 case DrmPlugin::kDrmPluginEventExpirationUpdate:
223 jwhat = gEventWhat.kWhatExpirationUpdate;
224 break;
225 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700226 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700227 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700228 default:
229 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
230 return;
231 }
232
233 JNIEnv *env = AndroidRuntime::getJNIEnv();
234 if (obj && obj->dataSize() > 0) {
235 jobject jParcel = createJavaParcelObject(env);
236 if (jParcel != NULL) {
237 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
238 nativeParcel->setData(obj->data(), obj->dataSize());
239 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
Jeff Tinker74797f82015-03-31 15:44:34 -0700240 jwhat, jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100241 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700242 }
243 }
244
245 if (env->ExceptionCheck()) {
246 ALOGW("An exception occurred while notifying an event.");
247 LOGW_EX(env);
248 env->ExceptionClear();
249 }
250}
251
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700252static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
253 ALOGE("Illegal state exception: %s (%d)", msg, err);
254
255 jobject exception = env->NewObject(gFields.stateException.classId,
256 gFields.stateException.init, static_cast<int>(err),
257 env->NewStringUTF(msg));
258 env->Throw(static_cast<jthrowable>(exception));
259}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700260
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800261static bool throwExceptionAsNecessary(
262 JNIEnv *env, status_t err, const char *msg = NULL) {
263
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700264 const char *drmMessage = NULL;
265
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700266 switch (err) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700267 case ERROR_DRM_UNKNOWN:
268 drmMessage = "General DRM error";
269 break;
270 case ERROR_DRM_NO_LICENSE:
271 drmMessage = "No license";
272 break;
273 case ERROR_DRM_LICENSE_EXPIRED:
274 drmMessage = "License expired";
275 break;
276 case ERROR_DRM_SESSION_NOT_OPENED:
277 drmMessage = "Session not opened";
278 break;
279 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
280 drmMessage = "Not initialized";
281 break;
282 case ERROR_DRM_DECRYPT:
283 drmMessage = "Decrypt error";
284 break;
285 case ERROR_DRM_CANNOT_HANDLE:
286 drmMessage = "Unsupported scheme or data format";
287 break;
288 case ERROR_DRM_TAMPER_DETECTED:
289 drmMessage = "Invalid state";
290 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700291 default:
292 break;
293 }
294
295 String8 vendorMessage;
296 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
Jeff Tinker29799862014-08-27 11:05:13 -0700297 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700298 drmMessage = vendorMessage.string();
299 }
300
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800301 if (err == BAD_VALUE) {
302 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
303 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700304 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
305 jniThrowException(env, "android/media/NotProvisionedException", msg);
306 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700307 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
308 jniThrowException(env, "android/media/ResourceBusyException", msg);
309 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700310 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
311 jniThrowException(env, "android/media/DeniedByServerException", msg);
312 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700313 } else if (err == DEAD_OBJECT) {
314 jniThrowException(env, "android/media/MediaDrmResetException",
315 "mediaserver died");
316 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800317 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700318 String8 errbuf;
319 if (drmMessage != NULL) {
320 if (msg == NULL) {
321 msg = drmMessage;
322 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700323 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700324 msg = errbuf.string();
325 }
326 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700327 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800328 return true;
329 }
330 return false;
331}
332
333static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000334 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800335 return jdrm ? jdrm->getDrm() : NULL;
336}
337
338JDrm::JDrm(
339 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
340 mObject = env->NewWeakGlobalRef(thiz);
341 mDrm = MakeDrm(uuid);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700342 if (mDrm != NULL) {
343 mDrm->setListener(this);
344 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800345}
346
347JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800348 JNIEnv *env = AndroidRuntime::getJNIEnv();
349
350 env->DeleteWeakGlobalRef(mObject);
351 mObject = NULL;
352}
353
354// static
355sp<IDrm> JDrm::MakeDrm() {
356 sp<IServiceManager> sm = defaultServiceManager();
Jeff Tinkerdc614f82016-02-12 08:58:32 -0800357 sp<IDrm> drm;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800358
Jeff Tinkerdc614f82016-02-12 08:58:32 -0800359 char value[PROPERTY_VALUE_MAX];
360 if (property_get("media.mediadrmservice.enable", value, NULL)
361 && (!strcmp("1", value) || !strcasecmp("true", value))) {
362 sp<IBinder> binder =
363 sm->getService(String16("media.drm"));
364 sp<IMediaDrmService> service =
365 interface_cast<IMediaDrmService>(binder);
366 if (service == NULL) {
367 return NULL;
368 }
369 drm = service->makeDrm();
370 } else {
371 sp<IBinder> binder =
372 sm->getService(String16("media.player"));
373 sp<IMediaPlayerService> service =
374 interface_cast<IMediaPlayerService>(binder);
375 if (service == NULL) {
376 return NULL;
377 }
378 drm = service->makeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800379 }
380
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800381 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
382 return NULL;
383 }
384
385 return drm;
386}
387
388// static
389sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
390 sp<IDrm> drm = MakeDrm();
391
392 if (drm == NULL) {
393 return NULL;
394 }
395
396 status_t err = drm->createPlugin(uuid);
397
398 if (err != OK) {
399 return NULL;
400 }
401
402 return drm;
403}
404
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700405status_t JDrm::setListener(const sp<DrmListener>& listener) {
406 Mutex::Autolock lock(mLock);
407 mListener = listener;
408 return OK;
409}
410
411void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
412 sp<DrmListener> listener;
413 mLock.lock();
414 listener = mListener;
415 mLock.unlock();
416
417 if (listener != NULL) {
418 Mutex::Autolock lock(mNotifyLock);
419 listener->notify(eventType, extra, obj);
420 }
421}
422
Jeff Tinker600071c2014-04-11 16:11:15 -0700423void JDrm::disconnect() {
424 if (mDrm != NULL) {
425 mDrm->destroyPlugin();
426 mDrm.clear();
427 }
428}
429
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700430
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800431// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700432bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800433 sp<IDrm> drm = MakeDrm();
434
435 if (drm == NULL) {
436 return false;
437 }
438
Jeff Tinker7cda4912013-08-21 11:52:34 -0700439 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800440}
441
442status_t JDrm::initCheck() const {
443 return mDrm == NULL ? NO_INIT : OK;
444}
445
446// JNI conversion utilities
447static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
448 Vector<uint8_t> vector;
449 size_t length = env->GetArrayLength(byteArray);
450 vector.insertAt((size_t)0, length);
451 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
452 return vector;
453}
454
455static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
456 size_t length = vector.size();
457 jbyteArray result = env->NewByteArray(length);
458 if (result != NULL) {
459 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
460 }
461 return result;
462}
463
464static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800465 String8 result;
466
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700467 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800468 if (s) {
469 result = s;
470 env->ReleaseStringUTFChars(jstr, s);
471 }
472 return result;
473}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700474
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800475/*
476 import java.util.HashMap;
477 import java.util.Set;
478 import java.Map.Entry;
479 import jav.util.Iterator;
480
481 HashMap<k, v> hm;
482 Set<Entry<k, v> > s = hm.entrySet();
483 Iterator i = s.iterator();
484 Entry e = s.next();
485*/
486
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200487static KeyedVector<String8, String8> HashMapToKeyedVector(
488 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800489 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800490 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200491 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800492
493 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
494 if (entrySet) {
495 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
496 if (iterator) {
497 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
498 while (hasNext) {
499 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
500 if (entry) {
501 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200502 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700503 jniThrowException(env, "java/lang/IllegalArgumentException",
504 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200505 env->DeleteLocalRef(entry);
506 *pIsOK = false;
507 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800508 }
509 jstring jkey = static_cast<jstring>(obj);
510
511 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200512 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700513 jniThrowException(env, "java/lang/IllegalArgumentException",
514 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200515 env->DeleteLocalRef(entry);
516 *pIsOK = false;
517 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800518 }
519 jstring jvalue = static_cast<jstring>(obj);
520
521 String8 key = JStringToString8(env, jkey);
522 String8 value = JStringToString8(env, jvalue);
523 keyedVector.add(key, value);
524
525 env->DeleteLocalRef(jkey);
526 env->DeleteLocalRef(jvalue);
527 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
528 }
529 env->DeleteLocalRef(entry);
530 }
531 env->DeleteLocalRef(iterator);
532 }
533 env->DeleteLocalRef(entrySet);
534 }
535 return keyedVector;
536}
537
538static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800539 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800540 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
541 for (size_t i = 0; i < map.size(); ++i) {
542 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
543 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
544 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
545 env->DeleteLocalRef(jkey);
546 env->DeleteLocalRef(jvalue);
547 }
548 return hashMap;
549}
550
551static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
552 List<Vector<uint8_t> > list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800553 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800554 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
555 List<Vector<uint8_t> >::iterator iter = list.begin();
556 while (iter != list.end()) {
557 jbyteArray byteArray = VectorToJByteArray(env, *iter);
558 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
559 env->DeleteLocalRef(byteArray);
560 iter++;
561 }
562
563 return arrayList;
564}
565
566} // namespace android
567
568using namespace android;
569
570static sp<JDrm> setDrm(
571 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000572 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800573 if (drm != NULL) {
574 drm->incStrong(thiz);
575 }
576 if (old != NULL) {
577 old->decStrong(thiz);
578 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000579 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800580
581 return old;
582}
583
584static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
585{
586 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700587 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800588 return false;
589 }
590
591 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700592 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800593 return false;
594 }
595 return true;
596}
597
598static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700599 sp<JDrm> drm = setDrm(env, thiz, NULL);
600 if (drm != NULL) {
601 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700602 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700603 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800604}
605
606static void android_media_MediaDrm_native_init(JNIEnv *env) {
607 jclass clazz;
608 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000609 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700610 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700611 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700612
613 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700614 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700615 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700616 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700617 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700618 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700619 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700620 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700621 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800622 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
623 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800624
Jeff Tinker74797f82015-03-31 15:44:34 -0700625 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
626 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
627 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
628 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700629 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
630 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700631
Jeff Tinker17b89222013-05-21 12:35:06 -0700632 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
633 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
634 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
635 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
636 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
637 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
638
Jeff Tinkere4095a82014-03-04 13:17:11 -0800639 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
640 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
641 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
642 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
643
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700644 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700645 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
646 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700647 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800648
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700649 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
650 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
651 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
652 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
653 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
654 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
655
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800656 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700657 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
658 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800659
Jeff Tinkere4095a82014-03-04 13:17:11 -0800660 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
661 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
662 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700663 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800664
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800665 FIND_CLASS(clazz, "java/util/ArrayList");
666 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
667 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
668
669 FIND_CLASS(clazz, "java/util/HashMap");
670 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
671 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
672 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
673 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
674 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
675
676 FIND_CLASS(clazz, "java/util/Set");
677 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
678
679 FIND_CLASS(clazz, "java/util/Iterator");
680 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
681 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
682
683 FIND_CLASS(clazz, "java/util/Map$Entry");
684 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
685 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800686
687 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700688 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800689
690 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700691 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800692
693 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700694 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700695
696 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
697 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
698 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800699}
700
701static void android_media_MediaDrm_native_setup(
702 JNIEnv *env, jobject thiz,
703 jobject weak_this, jbyteArray uuidObj) {
704
705 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700706 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800707 return;
708 }
709
710 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
711
712 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700713 jniThrowException(env, "java/lang/IllegalArgumentException",
714 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800715 return;
716 }
717
718 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
719
720 status_t err = drm->initCheck();
721
722 if (err != OK) {
723 jniThrowException(
724 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700725 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800726 "Failed to instantiate drm object.");
727 return;
728 }
729
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700730 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
731 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800732 setDrm(env, thiz, drm);
733}
734
735static void android_media_MediaDrm_native_finalize(
736 JNIEnv *env, jobject thiz) {
737 android_media_MediaDrm_release(env, thiz);
738}
739
740static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800741 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800742
743 if (uuidObj == NULL) {
744 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
745 return false;
746 }
747
748 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
749
750 if (uuid.size() != 16) {
751 jniThrowException(
752 env,
753 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700754 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800755 return false;
756 }
757
Jeff Tinker7cda4912013-08-21 11:52:34 -0700758 String8 mimeType;
759 if (jmimeType != NULL) {
760 mimeType = JStringToString8(env, jmimeType);
761 }
762
763 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800764}
765
766static jbyteArray android_media_MediaDrm_openSession(
767 JNIEnv *env, jobject thiz) {
768 sp<IDrm> drm = GetDrm(env, thiz);
769
770 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700771 jniThrowException(env, "java/lang/IllegalStateException",
772 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800773 return NULL;
774 }
775
776 Vector<uint8_t> sessionId;
777 status_t err = drm->openSession(sessionId);
778
779 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
780 return NULL;
781 }
782
783 return VectorToJByteArray(env, sessionId);
784}
785
786static void android_media_MediaDrm_closeSession(
787 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
788 sp<IDrm> drm = GetDrm(env, thiz);
789
790 if (!CheckSession(env, drm, jsessionId)) {
791 return;
792 }
793
794 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
795
796 status_t err = drm->closeSession(sessionId);
797
798 throwExceptionAsNecessary(env, err, "Failed to close session");
799}
800
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700801static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800802 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700803 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800804 sp<IDrm> drm = GetDrm(env, thiz);
805
806 if (!CheckSession(env, drm, jsessionId)) {
807 return NULL;
808 }
809
810 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
811
812 Vector<uint8_t> initData;
813 if (jinitData != NULL) {
814 initData = JByteArrayToVector(env, jinitData);
815 }
816
817 String8 mimeType;
818 if (jmimeType != NULL) {
819 mimeType = JStringToString8(env, jmimeType);
820 }
821
Jeff Tinker17b89222013-05-21 12:35:06 -0700822 DrmPlugin::KeyType keyType;
823 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
824 keyType = DrmPlugin::kKeyType_Streaming;
825 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
826 keyType = DrmPlugin::kKeyType_Offline;
827 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
828 keyType = DrmPlugin::kKeyType_Release;
829 } else {
830 jniThrowException(env, "java/lang/IllegalArgumentException",
831 "invalid keyType");
832 return NULL;
833 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800834
835 KeyedVector<String8, String8> optParams;
836 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200837 bool isOK;
838 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
839 if (!isOK) {
840 return NULL;
841 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800842 }
843
844 Vector<uint8_t> request;
845 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700846 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800847
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700848 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700849 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800850
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700851 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800852 return NULL;
853 }
854
855 // Fill out return obj
856 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700857 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800858
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700859 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800860
861 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700862 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800863 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700864 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800865
866 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700867 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700868
869 switch (keyRequestType) {
870 case DrmPlugin::kKeyRequestType_Initial:
871 env->SetIntField(keyObj, gFields.keyRequest.requestType,
872 gKeyRequestTypes.kKeyRequestTypeInitial);
873 break;
874 case DrmPlugin::kKeyRequestType_Renewal:
875 env->SetIntField(keyObj, gFields.keyRequest.requestType,
876 gKeyRequestTypes.kKeyRequestTypeRenewal);
877 break;
878 case DrmPlugin::kKeyRequestType_Release:
879 env->SetIntField(keyObj, gFields.keyRequest.requestType,
880 gKeyRequestTypes.kKeyRequestTypeRelease);
881 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700882 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700883 throwStateException(env, "DRM plugin failure: unknown key request type",
884 ERROR_DRM_UNKNOWN);
885 break;
886 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800887 }
888
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700889 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800890}
891
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700892static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800893 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
894 sp<IDrm> drm = GetDrm(env, thiz);
895
896 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700897 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800898 }
899
900 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
901
902 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700903 jniThrowException(env, "java/lang/IllegalArgumentException",
904 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700905 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800906 }
907 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700908 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800909
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700910 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800911
Jeff Tinker8117d8f2013-08-16 13:46:02 -0700912 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
913 return NULL;
914 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700915 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800916}
917
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700918static void android_media_MediaDrm_removeKeys(
919 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
920 sp<IDrm> drm = GetDrm(env, thiz);
921
922 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700923 jniThrowException(env, "java/lang/IllegalArgumentException",
924 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700925 return;
926 }
927
928 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
929
930 status_t err = drm->removeKeys(keySetId);
931
932 throwExceptionAsNecessary(env, err, "Failed to remove keys");
933}
934
935static void android_media_MediaDrm_restoreKeys(
936 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
937 jbyteArray jkeysetId) {
938
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800939 sp<IDrm> drm = GetDrm(env, thiz);
940
941 if (!CheckSession(env, drm, jsessionId)) {
942 return;
943 }
944
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700945 if (jkeysetId == NULL) {
946 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
947 return;
948 }
949
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800950 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700951 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800952
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700953 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800954
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700955 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800956}
957
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700958static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800959 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
960 sp<IDrm> drm = GetDrm(env, thiz);
961
962 if (!CheckSession(env, drm, jsessionId)) {
963 return NULL;
964 }
965 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
966
967 KeyedVector<String8, String8> infoMap;
968
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700969 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800970
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700971 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800972 return NULL;
973 }
974
975 return KeyedVectorToHashMap(env, infoMap);
976}
977
Jeff Tinkere4095a82014-03-04 13:17:11 -0800978static jobject android_media_MediaDrm_getProvisionRequestNative(
979 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800980 sp<IDrm> drm = GetDrm(env, thiz);
981
982 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700983 jniThrowException(env, "java/lang/IllegalStateException",
984 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800985 return NULL;
986 }
987
988 Vector<uint8_t> request;
989 String8 defaultUrl;
990
Jeff Tinkere4095a82014-03-04 13:17:11 -0800991 String8 certType;
992 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
993 certType = "X.509";
994 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
995 certType = "none";
996 } else {
997 certType = "invalid";
998 }
999
1000 String8 certAuthority = JStringToString8(env, jcertAuthority);
1001 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001002
1003 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
1004 return NULL;
1005 }
1006
1007 // Fill out return obj
1008 jclass clazz;
1009 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1010
1011 jobject provisionObj = NULL;
1012
1013 if (clazz) {
1014 provisionObj = env->AllocObject(clazz);
1015 jbyteArray jrequest = VectorToJByteArray(env, request);
1016 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1017
1018 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1019 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1020 }
1021
1022 return provisionObj;
1023}
1024
Jeff Tinkere4095a82014-03-04 13:17:11 -08001025static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001026 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1027 sp<IDrm> drm = GetDrm(env, thiz);
1028
1029 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001030 jniThrowException(env, "java/lang/IllegalStateException",
1031 "MediaDrm obj is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001032 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001033 }
1034
1035 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001036 jniThrowException(env, "java/lang/IllegalArgumentException",
1037 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001038 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001039 }
1040
1041 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001042 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001043
Jeff Tinkere4095a82014-03-04 13:17:11 -08001044 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1045
1046 // Fill out return obj
1047 jclass clazz = gFields.certificateClassId;
1048
1049 jobject certificateObj = NULL;
1050
1051 if (clazz && certificate.size() && wrappedKey.size()) {
1052 certificateObj = env->AllocObject(clazz);
1053 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1054 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1055
1056 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1057 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1058 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001059
1060 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001061 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001062}
1063
1064static jobject android_media_MediaDrm_getSecureStops(
1065 JNIEnv *env, jobject thiz) {
1066 sp<IDrm> drm = GetDrm(env, thiz);
1067
1068 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001069 jniThrowException(env, "java/lang/IllegalStateException",
1070 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001071 return NULL;
1072 }
1073
1074 List<Vector<uint8_t> > secureStops;
1075
1076 status_t err = drm->getSecureStops(secureStops);
1077
1078 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1079 return NULL;
1080 }
1081
1082 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1083}
1084
Jeff Tinker1b51c722014-10-31 00:54:26 -07001085static jbyteArray android_media_MediaDrm_getSecureStop(
1086 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1087 sp<IDrm> drm = GetDrm(env, thiz);
1088
1089 if (drm == NULL) {
1090 jniThrowException(env, "java/lang/IllegalStateException",
1091 "MediaDrm obj is null");
1092 return NULL;
1093 }
1094
1095 Vector<uint8_t> secureStop;
1096
1097 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1098
1099 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1100 return NULL;
1101 }
1102
1103 return VectorToJByteArray(env, secureStop);
1104}
1105
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001106static void android_media_MediaDrm_releaseSecureStops(
1107 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1108 sp<IDrm> drm = GetDrm(env, thiz);
1109
1110 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001111 jniThrowException(env, "java/lang/IllegalStateException",
1112 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001113 return;
1114 }
1115
1116 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1117
1118 status_t err = drm->releaseSecureStops(ssRelease);
1119
1120 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1121}
1122
Jeff Tinker1b51c722014-10-31 00:54:26 -07001123static void android_media_MediaDrm_releaseAllSecureStops(
1124 JNIEnv *env, jobject thiz) {
1125 sp<IDrm> drm = GetDrm(env, thiz);
1126
1127 if (drm == NULL) {
1128 jniThrowException(env, "java/lang/IllegalStateException",
1129 "MediaDrm obj is null");
1130 return;
1131 }
1132
1133 status_t err = drm->releaseAllSecureStops();
1134
1135 throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
1136}
1137
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001138static jstring android_media_MediaDrm_getPropertyString(
1139 JNIEnv *env, jobject thiz, jstring jname) {
1140 sp<IDrm> drm = GetDrm(env, thiz);
1141
1142 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001143 jniThrowException(env, "java/lang/IllegalStateException",
1144 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001145 return NULL;
1146 }
1147
1148 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001149 jniThrowException(env, "java/lang/IllegalArgumentException",
1150 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001151 return NULL;
1152 }
1153
1154 String8 name = JStringToString8(env, jname);
1155 String8 value;
1156
1157 status_t err = drm->getPropertyString(name, value);
1158
1159 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1160 return NULL;
1161 }
1162
1163 return env->NewStringUTF(value.string());
1164}
1165
1166static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1167 JNIEnv *env, jobject thiz, jstring jname) {
1168 sp<IDrm> drm = GetDrm(env, thiz);
1169
1170 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001171 jniThrowException(env, "java/lang/IllegalStateException",
1172 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001173 return NULL;
1174 }
1175
1176 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001177 jniThrowException(env, "java/lang/IllegalArgumentException",
1178 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001179 return NULL;
1180 }
1181
1182 String8 name = JStringToString8(env, jname);
1183 Vector<uint8_t> value;
1184
1185 status_t err = drm->getPropertyByteArray(name, value);
1186
1187 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1188 return NULL;
1189 }
1190
1191 return VectorToJByteArray(env, value);
1192}
1193
1194static void android_media_MediaDrm_setPropertyString(
1195 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1196 sp<IDrm> drm = GetDrm(env, thiz);
1197
1198 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001199 jniThrowException(env, "java/lang/IllegalStateException",
1200 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001201 return;
1202 }
1203
Jeff Tinkereada5372013-05-21 12:48:14 -07001204 if (jname == NULL) {
1205 jniThrowException(env, "java/lang/IllegalArgumentException",
1206 "property name String is null");
1207 return;
1208 }
1209
1210 if (jvalue == NULL) {
1211 jniThrowException(env, "java/lang/IllegalArgumentException",
1212 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001213 return;
1214 }
1215
1216 String8 name = JStringToString8(env, jname);
1217 String8 value = JStringToString8(env, jvalue);
1218
1219 status_t err = drm->setPropertyString(name, value);
1220
1221 throwExceptionAsNecessary(env, err, "Failed to set property");
1222}
1223
1224static void android_media_MediaDrm_setPropertyByteArray(
1225 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1226 sp<IDrm> drm = GetDrm(env, thiz);
1227
1228 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001229 jniThrowException(env, "java/lang/IllegalStateException",
1230 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001231 return;
1232 }
1233
Jeff Tinkereada5372013-05-21 12:48:14 -07001234 if (jname == NULL) {
1235 jniThrowException(env, "java/lang/IllegalArgumentException",
1236 "property name String is null");
1237 return;
1238 }
1239
1240 if (jvalue == NULL) {
1241 jniThrowException(env, "java/lang/IllegalArgumentException",
1242 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001243 return;
1244 }
1245
1246 String8 name = JStringToString8(env, jname);
1247 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1248
1249 status_t err = drm->setPropertyByteArray(name, value);
1250
1251 throwExceptionAsNecessary(env, err, "Failed to set property");
1252}
1253
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001254static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001255 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001256 jstring jalgorithm) {
1257
1258 sp<IDrm> drm = GetDrm(env, jdrm);
1259
1260 if (!CheckSession(env, drm, jsessionId)) {
1261 return;
1262 }
1263
1264 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001265 jniThrowException(env, "java/lang/IllegalArgumentException",
1266 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001267 return;
1268 }
1269
1270 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1271 String8 algorithm = JStringToString8(env, jalgorithm);
1272
1273 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1274
1275 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1276}
1277
1278static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001279 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001280 jstring jalgorithm) {
1281
1282 sp<IDrm> drm = GetDrm(env, jdrm);
1283
1284 if (!CheckSession(env, drm, jsessionId)) {
1285 return;
1286 }
1287
1288 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001289 jniThrowException(env, "java/lang/IllegalArgumentException",
1290 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001291 return;
1292 }
1293
1294 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1295 String8 algorithm = JStringToString8(env, jalgorithm);
1296
1297 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1298
1299 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1300}
1301
1302
1303static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001304 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001305 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1306
1307 sp<IDrm> drm = GetDrm(env, jdrm);
1308
1309 if (!CheckSession(env, drm, jsessionId)) {
1310 return NULL;
1311 }
1312
1313 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001314 jniThrowException(env, "java/lang/IllegalArgumentException",
1315 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001316 return NULL;
1317 }
1318
1319 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1320 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1321 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1322 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1323 Vector<uint8_t> output;
1324
1325 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1326
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001327 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1328 return NULL;
1329 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001330
1331 return VectorToJByteArray(env, output);
1332}
1333
1334static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001335 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001336 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1337
1338 sp<IDrm> drm = GetDrm(env, jdrm);
1339
1340 if (!CheckSession(env, drm, jsessionId)) {
1341 return NULL;
1342 }
1343
1344 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001345 jniThrowException(env, "java/lang/IllegalArgumentException",
1346 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001347 return NULL;
1348 }
1349
1350 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1351 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1352 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1353 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1354 Vector<uint8_t> output;
1355
1356 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001357 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1358 return NULL;
1359 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001360
1361 return VectorToJByteArray(env, output);
1362}
1363
1364static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001365 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001366 jbyteArray jkeyId, jbyteArray jmessage) {
1367
1368 sp<IDrm> drm = GetDrm(env, jdrm);
1369
1370 if (!CheckSession(env, drm, jsessionId)) {
1371 return NULL;
1372 }
1373
1374 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001375 jniThrowException(env, "java/lang/IllegalArgumentException",
1376 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001377 return NULL;
1378 }
1379
1380 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1381 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1382 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1383 Vector<uint8_t> signature;
1384
1385 status_t err = drm->sign(sessionId, keyId, message, signature);
1386
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001387 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1388 return NULL;
1389 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001390
1391 return VectorToJByteArray(env, signature);
1392}
1393
1394static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001395 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001396 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1397
1398 sp<IDrm> drm = GetDrm(env, jdrm);
1399
1400 if (!CheckSession(env, drm, jsessionId)) {
1401 return false;
1402 }
1403
1404 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001405 jniThrowException(env, "java/lang/IllegalArgumentException",
1406 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001407 return false;
1408 }
1409
1410 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1411 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1412 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1413 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1414 bool match;
1415
1416 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1417
1418 throwExceptionAsNecessary(env, err, "Failed to verify");
1419 return match;
1420}
1421
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001422
Jeff Tinkere4095a82014-03-04 13:17:11 -08001423static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001424 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001425 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1426
1427 sp<IDrm> drm = GetDrm(env, jdrm);
1428
1429 if (!CheckSession(env, drm, jsessionId)) {
1430 return NULL;
1431 }
1432
1433 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1434 jniThrowException(env, "java/lang/IllegalArgumentException",
1435 "required argument is null");
1436 return NULL;
1437 }
1438
1439 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1440 String8 algorithm = JStringToString8(env, jalgorithm);
1441 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1442 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1443 Vector<uint8_t> signature;
1444
1445 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1446
1447 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1448 return NULL;
1449 }
1450
1451 return VectorToJByteArray(env, signature);
1452}
1453
1454
Daniel Micay76f6a862015-09-19 17:31:01 -04001455static const JNINativeMethod gMethods[] = {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001456 { "release", "()V", (void *)android_media_MediaDrm_release },
1457 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1458
1459 { "native_setup", "(Ljava/lang/Object;[B)V",
1460 (void *)android_media_MediaDrm_native_setup },
1461
1462 { "native_finalize", "()V",
1463 (void *)android_media_MediaDrm_native_finalize },
1464
Jeff Tinker7cda4912013-08-21 11:52:34 -07001465 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001466 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1467
1468 { "openSession", "()[B",
1469 (void *)android_media_MediaDrm_openSession },
1470
1471 { "closeSession", "([B)V",
1472 (void *)android_media_MediaDrm_closeSession },
1473
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001474 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1475 "Landroid/media/MediaDrm$KeyRequest;",
1476 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001477
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001478 { "provideKeyResponse", "([B[B)[B",
1479 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001480
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001481 { "removeKeys", "([B)V",
1482 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001483
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001484 { "restoreKeys", "([B[B)V",
1485 (void *)android_media_MediaDrm_restoreKeys },
1486
1487 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1488 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001489
Jeff Tinkere4095a82014-03-04 13:17:11 -08001490 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1491 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001492
Jeff Tinkere4095a82014-03-04 13:17:11 -08001493 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1494 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001495
1496 { "getSecureStops", "()Ljava/util/List;",
1497 (void *)android_media_MediaDrm_getSecureStops },
1498
Jeff Tinker1b51c722014-10-31 00:54:26 -07001499 { "getSecureStop", "([B)[B",
1500 (void *)android_media_MediaDrm_getSecureStop },
1501
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001502 { "releaseSecureStops", "([B)V",
1503 (void *)android_media_MediaDrm_releaseSecureStops },
1504
Jeff Tinker1b51c722014-10-31 00:54:26 -07001505 { "releaseAllSecureStops", "()V",
1506 (void *)android_media_MediaDrm_releaseAllSecureStops },
1507
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001508 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1509 (void *)android_media_MediaDrm_getPropertyString },
1510
1511 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1512 (void *)android_media_MediaDrm_getPropertyByteArray },
1513
1514 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1515 (void *)android_media_MediaDrm_setPropertyString },
1516
1517 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1518 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001519
1520 { "setCipherAlgorithmNative",
1521 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1522 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1523
1524 { "setMacAlgorithmNative",
1525 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1526 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1527
1528 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1529 (void *)android_media_MediaDrm_encryptNative },
1530
1531 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1532 (void *)android_media_MediaDrm_decryptNative },
1533
1534 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1535 (void *)android_media_MediaDrm_signNative },
1536
1537 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1538 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08001539
1540 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1541 (void *)android_media_MediaDrm_signRSANative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001542};
1543
1544int register_android_media_Drm(JNIEnv *env) {
1545 return AndroidRuntime::registerNativeMethods(env,
1546 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1547}