blob: ea35f78a3a7a3514771a199115ac76f41dc0c6ca [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/stagefright/foundation/ADebug.h>
Jeff Tinkerf7568b52013-04-17 14:24:40 -070035#include <media/stagefright/MediaErrors.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080036
37namespace android {
38
39#define FIND_CLASS(var, className) \
40 var = env->FindClass(className); \
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -070041 LOG_FATAL_IF(! (var), "Unable to find class " className);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080042
43#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
44 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -070045 LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080046
47#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
48 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -070049 LOG_FATAL_IF(! (var), "Unable to find method " fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080050
Jeff Tinker54cfbd62013-04-02 13:14:59 -070051#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
52 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -070053 LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070054
55#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
56 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -070057 LOG_FATAL_IF(! (var), "Unable to find static method " fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070058
59
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080060struct RequestFields {
61 jfieldID data;
62 jfieldID defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -070063 jfieldID requestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080064};
65
66struct ArrayListFields {
67 jmethodID init;
68 jmethodID add;
69};
70
71struct HashmapFields {
72 jmethodID init;
73 jmethodID get;
74 jmethodID put;
75 jmethodID entrySet;
76};
77
78struct SetFields {
79 jmethodID iterator;
80};
81
82struct IteratorFields {
83 jmethodID next;
84 jmethodID hasNext;
85};
86
87struct EntryFields {
88 jmethodID getKey;
89 jmethodID getValue;
90};
91
Jeff Tinker54cfbd62013-04-02 13:14:59 -070092struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -070093 jint kEventProvisionRequired;
94 jint kEventKeyRequired;
95 jint kEventKeyExpired;
96 jint kEventVendorDefined;
Ronghua Wua6d72092015-03-04 11:16:02 -080097 jint kEventSessionReclaimed;
Jeff Tinker54cfbd62013-04-02 13:14:59 -070098} gEventTypes;
99
Jeff Tinker74797f82015-03-31 15:44:34 -0700100struct EventWhat {
101 jint kWhatDrmEvent;
102 jint kWhatExpirationUpdate;
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700103 jint kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700104} gEventWhat;
105
Jeff Tinker17b89222013-05-21 12:35:06 -0700106struct KeyTypes {
107 jint kKeyTypeStreaming;
108 jint kKeyTypeOffline;
109 jint kKeyTypeRelease;
110} gKeyTypes;
111
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700112struct KeyRequestTypes {
113 jint kKeyRequestTypeInitial;
114 jint kKeyRequestTypeRenewal;
115 jint kKeyRequestTypeRelease;
116} gKeyRequestTypes;
117
Jeff Tinkere4095a82014-03-04 13:17:11 -0800118struct CertificateTypes {
119 jint kCertificateTypeNone;
120 jint kCertificateTypeX509;
121} gCertificateTypes;
122
123struct CertificateFields {
124 jfieldID wrappedPrivateKey;
125 jfieldID certificateData;
126};
127
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700128struct StateExceptionFields {
129 jmethodID init;
130 jclass classId;
131};
132
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800133struct fields_t {
134 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700135 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700136 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800137 RequestFields provisionRequest;
138 ArrayListFields arraylist;
139 HashmapFields hashmap;
140 SetFields set;
141 IteratorFields iterator;
142 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800143 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700144 StateExceptionFields stateException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800145 jclass certificateClassId;
146 jclass hashmapClassId;
147 jclass arraylistClassId;
148 jclass stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800149};
150
151static fields_t gFields;
152
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700153// ----------------------------------------------------------------------------
154// ref-counted object for callbacks
155class JNIDrmListener: public DrmListener
156{
157public:
158 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
159 ~JNIDrmListener();
160 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
161private:
162 JNIDrmListener();
163 jclass mClass; // Reference to MediaDrm class
164 jobject mObject; // Weak ref to MediaDrm Java object to call on
165};
166
167JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
168{
169 // Hold onto the MediaDrm class for use in calling the static method
170 // that posts events to the application thread.
171 jclass clazz = env->GetObjectClass(thiz);
172 if (clazz == NULL) {
173 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700174 jniThrowException(env, "java/lang/Exception",
175 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700176 return;
177 }
178 mClass = (jclass)env->NewGlobalRef(clazz);
179
180 // We use a weak reference so the MediaDrm object can be garbage collected.
181 // The reference is only used as a proxy for callbacks.
182 mObject = env->NewGlobalRef(weak_thiz);
183}
184
185JNIDrmListener::~JNIDrmListener()
186{
187 // remove global references
188 JNIEnv *env = AndroidRuntime::getJNIEnv();
189 env->DeleteGlobalRef(mObject);
190 env->DeleteGlobalRef(mClass);
191}
192
193void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
194 const Parcel *obj)
195{
Jeff Tinker74797f82015-03-31 15:44:34 -0700196 jint jwhat;
197 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700198
199 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700200 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700201 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700202 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700203 jeventType = gEventTypes.kEventProvisionRequired;
204 break;
205 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700206 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700207 jeventType = gEventTypes.kEventKeyRequired;
208 break;
209 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700210 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700211 jeventType = gEventTypes.kEventKeyExpired;
212 break;
213 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700214 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700215 jeventType = gEventTypes.kEventVendorDefined;
216 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800217 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700218 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800219 jeventType = gEventTypes.kEventSessionReclaimed;
220 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700221 case DrmPlugin::kDrmPluginEventExpirationUpdate:
222 jwhat = gEventWhat.kWhatExpirationUpdate;
223 break;
224 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700225 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700226 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700227 default:
228 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
229 return;
230 }
231
232 JNIEnv *env = AndroidRuntime::getJNIEnv();
233 if (obj && obj->dataSize() > 0) {
234 jobject jParcel = createJavaParcelObject(env);
235 if (jParcel != NULL) {
236 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
237 nativeParcel->setData(obj->data(), obj->dataSize());
238 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
Jeff Tinker74797f82015-03-31 15:44:34 -0700239 jwhat, jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100240 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700241 }
242 }
243
244 if (env->ExceptionCheck()) {
245 ALOGW("An exception occurred while notifying an event.");
246 LOGW_EX(env);
247 env->ExceptionClear();
248 }
249}
250
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700251static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
252 ALOGE("Illegal state exception: %s (%d)", msg, err);
253
254 jobject exception = env->NewObject(gFields.stateException.classId,
255 gFields.stateException.init, static_cast<int>(err),
256 env->NewStringUTF(msg));
257 env->Throw(static_cast<jthrowable>(exception));
258}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700259
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800260static bool throwExceptionAsNecessary(
261 JNIEnv *env, status_t err, const char *msg = NULL) {
262
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700263 const char *drmMessage = NULL;
264
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700265 switch (err) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700266 case ERROR_DRM_UNKNOWN:
267 drmMessage = "General DRM error";
268 break;
269 case ERROR_DRM_NO_LICENSE:
270 drmMessage = "No license";
271 break;
272 case ERROR_DRM_LICENSE_EXPIRED:
273 drmMessage = "License expired";
274 break;
275 case ERROR_DRM_SESSION_NOT_OPENED:
276 drmMessage = "Session not opened";
277 break;
278 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
279 drmMessage = "Not initialized";
280 break;
281 case ERROR_DRM_DECRYPT:
282 drmMessage = "Decrypt error";
283 break;
284 case ERROR_DRM_CANNOT_HANDLE:
285 drmMessage = "Unsupported scheme or data format";
286 break;
287 case ERROR_DRM_TAMPER_DETECTED:
288 drmMessage = "Invalid state";
289 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700290 default:
291 break;
292 }
293
294 String8 vendorMessage;
295 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
Jeff Tinker29799862014-08-27 11:05:13 -0700296 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700297 drmMessage = vendorMessage.string();
298 }
299
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800300 if (err == BAD_VALUE) {
301 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
302 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700303 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
304 jniThrowException(env, "android/media/NotProvisionedException", msg);
305 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700306 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
307 jniThrowException(env, "android/media/ResourceBusyException", msg);
308 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700309 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
310 jniThrowException(env, "android/media/DeniedByServerException", msg);
311 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700312 } else if (err == DEAD_OBJECT) {
313 jniThrowException(env, "android/media/MediaDrmResetException",
314 "mediaserver died");
315 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800316 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700317 String8 errbuf;
318 if (drmMessage != NULL) {
319 if (msg == NULL) {
320 msg = drmMessage;
321 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700322 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700323 msg = errbuf.string();
324 }
325 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700326 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800327 return true;
328 }
329 return false;
330}
331
332static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000333 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800334 return jdrm ? jdrm->getDrm() : NULL;
335}
336
337JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800338 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
339 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800340 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800341 mDrm = MakeDrm(uuid, appPackageName);
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();
357
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700358 sp<IBinder> binder = sm->getService(String16("media.drm"));
359 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
360 if (service == NULL) {
361 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800362 }
363
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700364 sp<IDrm> drm = service->makeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800365 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
366 return NULL;
367 }
368
369 return drm;
370}
371
372// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800373sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800374 sp<IDrm> drm = MakeDrm();
375
376 if (drm == NULL) {
377 return NULL;
378 }
379
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800380 status_t err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800381
382 if (err != OK) {
383 return NULL;
384 }
385
386 return drm;
387}
388
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700389status_t JDrm::setListener(const sp<DrmListener>& listener) {
390 Mutex::Autolock lock(mLock);
391 mListener = listener;
392 return OK;
393}
394
395void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
396 sp<DrmListener> listener;
397 mLock.lock();
398 listener = mListener;
399 mLock.unlock();
400
401 if (listener != NULL) {
402 Mutex::Autolock lock(mNotifyLock);
403 listener->notify(eventType, extra, obj);
404 }
405}
406
Jeff Tinker600071c2014-04-11 16:11:15 -0700407void JDrm::disconnect() {
408 if (mDrm != NULL) {
409 mDrm->destroyPlugin();
410 mDrm.clear();
411 }
412}
413
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700414
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800415// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700416bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800417 sp<IDrm> drm = MakeDrm();
418
419 if (drm == NULL) {
420 return false;
421 }
422
Jeff Tinker7cda4912013-08-21 11:52:34 -0700423 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800424}
425
426status_t JDrm::initCheck() const {
427 return mDrm == NULL ? NO_INIT : OK;
428}
429
430// JNI conversion utilities
431static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
432 Vector<uint8_t> vector;
433 size_t length = env->GetArrayLength(byteArray);
434 vector.insertAt((size_t)0, length);
435 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
436 return vector;
437}
438
439static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
440 size_t length = vector.size();
441 jbyteArray result = env->NewByteArray(length);
442 if (result != NULL) {
443 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
444 }
445 return result;
446}
447
448static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800449 String8 result;
450
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700451 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800452 if (s) {
453 result = s;
454 env->ReleaseStringUTFChars(jstr, s);
455 }
456 return result;
457}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700458
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800459/*
460 import java.util.HashMap;
461 import java.util.Set;
462 import java.Map.Entry;
463 import jav.util.Iterator;
464
465 HashMap<k, v> hm;
466 Set<Entry<k, v> > s = hm.entrySet();
467 Iterator i = s.iterator();
468 Entry e = s.next();
469*/
470
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200471static KeyedVector<String8, String8> HashMapToKeyedVector(
472 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800473 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800474 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200475 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800476
477 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
478 if (entrySet) {
479 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
480 if (iterator) {
481 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
482 while (hasNext) {
483 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
484 if (entry) {
485 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200486 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700487 jniThrowException(env, "java/lang/IllegalArgumentException",
488 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200489 env->DeleteLocalRef(entry);
490 *pIsOK = false;
491 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800492 }
493 jstring jkey = static_cast<jstring>(obj);
494
495 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200496 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700497 jniThrowException(env, "java/lang/IllegalArgumentException",
498 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200499 env->DeleteLocalRef(entry);
500 *pIsOK = false;
501 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800502 }
503 jstring jvalue = static_cast<jstring>(obj);
504
505 String8 key = JStringToString8(env, jkey);
506 String8 value = JStringToString8(env, jvalue);
507 keyedVector.add(key, value);
508
509 env->DeleteLocalRef(jkey);
510 env->DeleteLocalRef(jvalue);
511 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
512 }
513 env->DeleteLocalRef(entry);
514 }
515 env->DeleteLocalRef(iterator);
516 }
517 env->DeleteLocalRef(entrySet);
518 }
519 return keyedVector;
520}
521
522static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800523 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800524 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
525 for (size_t i = 0; i < map.size(); ++i) {
526 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
527 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
528 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
529 env->DeleteLocalRef(jkey);
530 env->DeleteLocalRef(jvalue);
531 }
532 return hashMap;
533}
534
535static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
536 List<Vector<uint8_t> > list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800537 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800538 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
539 List<Vector<uint8_t> >::iterator iter = list.begin();
540 while (iter != list.end()) {
541 jbyteArray byteArray = VectorToJByteArray(env, *iter);
542 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
543 env->DeleteLocalRef(byteArray);
544 iter++;
545 }
546
547 return arrayList;
548}
549
550} // namespace android
551
552using namespace android;
553
554static sp<JDrm> setDrm(
555 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000556 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800557 if (drm != NULL) {
558 drm->incStrong(thiz);
559 }
560 if (old != NULL) {
561 old->decStrong(thiz);
562 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000563 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800564
565 return old;
566}
567
568static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
569{
570 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700571 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800572 return false;
573 }
574
575 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700576 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800577 return false;
578 }
579 return true;
580}
581
582static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700583 sp<JDrm> drm = setDrm(env, thiz, NULL);
584 if (drm != NULL) {
585 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700586 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700587 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800588}
589
590static void android_media_MediaDrm_native_init(JNIEnv *env) {
591 jclass clazz;
592 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000593 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700594 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700595 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700596
597 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700598 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700599 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700600 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700601 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700602 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700603 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700604 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700605 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800606 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
607 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800608
Jeff Tinker74797f82015-03-31 15:44:34 -0700609 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
610 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
611 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
612 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700613 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
614 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700615
Jeff Tinker17b89222013-05-21 12:35:06 -0700616 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
617 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
618 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
619 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
620 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
621 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
622
Jeff Tinkere4095a82014-03-04 13:17:11 -0800623 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
624 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
625 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
626 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
627
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700628 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700629 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
630 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700631 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800632
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700633 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
634 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
635 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
636 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
637 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
638 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
639
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800640 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700641 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
642 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800643
Jeff Tinkere4095a82014-03-04 13:17:11 -0800644 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
645 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
646 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700647 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800648
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800649 FIND_CLASS(clazz, "java/util/ArrayList");
650 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
651 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
652
653 FIND_CLASS(clazz, "java/util/HashMap");
654 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
655 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
656 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
657 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
658 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
659
660 FIND_CLASS(clazz, "java/util/Set");
661 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
662
663 FIND_CLASS(clazz, "java/util/Iterator");
664 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
665 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
666
667 FIND_CLASS(clazz, "java/util/Map$Entry");
668 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
669 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800670
671 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700672 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800673
674 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700675 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800676
677 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700678 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700679
680 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
681 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
682 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800683}
684
685static void android_media_MediaDrm_native_setup(
686 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800687 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800688
689 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700690 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800691 return;
692 }
693
694 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
695
696 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700697 jniThrowException(env, "java/lang/IllegalArgumentException",
698 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800699 return;
700 }
701
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800702 String8 packageName;
703 if (jappPackageName == NULL) {
704 jniThrowException(env, "java/lang/IllegalArgumentException",
705 "application package name cannot be null");
706 return;
707 }
708
709 packageName = JStringToString8(env, jappPackageName);
710 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800711
712 status_t err = drm->initCheck();
713
714 if (err != OK) {
715 jniThrowException(
716 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700717 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800718 "Failed to instantiate drm object.");
719 return;
720 }
721
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700722 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
723 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800724 setDrm(env, thiz, drm);
725}
726
727static void android_media_MediaDrm_native_finalize(
728 JNIEnv *env, jobject thiz) {
729 android_media_MediaDrm_release(env, thiz);
730}
731
732static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800733 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800734
735 if (uuidObj == NULL) {
736 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
737 return false;
738 }
739
740 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
741
742 if (uuid.size() != 16) {
743 jniThrowException(
744 env,
745 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700746 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800747 return false;
748 }
749
Jeff Tinker7cda4912013-08-21 11:52:34 -0700750 String8 mimeType;
751 if (jmimeType != NULL) {
752 mimeType = JStringToString8(env, jmimeType);
753 }
754
755 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800756}
757
758static jbyteArray android_media_MediaDrm_openSession(
759 JNIEnv *env, jobject thiz) {
760 sp<IDrm> drm = GetDrm(env, thiz);
761
762 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700763 jniThrowException(env, "java/lang/IllegalStateException",
764 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800765 return NULL;
766 }
767
768 Vector<uint8_t> sessionId;
769 status_t err = drm->openSession(sessionId);
770
771 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
772 return NULL;
773 }
774
775 return VectorToJByteArray(env, sessionId);
776}
777
778static void android_media_MediaDrm_closeSession(
779 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
780 sp<IDrm> drm = GetDrm(env, thiz);
781
782 if (!CheckSession(env, drm, jsessionId)) {
783 return;
784 }
785
786 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
787
788 status_t err = drm->closeSession(sessionId);
789
790 throwExceptionAsNecessary(env, err, "Failed to close session");
791}
792
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700793static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800794 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700795 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800796 sp<IDrm> drm = GetDrm(env, thiz);
797
798 if (!CheckSession(env, drm, jsessionId)) {
799 return NULL;
800 }
801
802 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
803
804 Vector<uint8_t> initData;
805 if (jinitData != NULL) {
806 initData = JByteArrayToVector(env, jinitData);
807 }
808
809 String8 mimeType;
810 if (jmimeType != NULL) {
811 mimeType = JStringToString8(env, jmimeType);
812 }
813
Jeff Tinker17b89222013-05-21 12:35:06 -0700814 DrmPlugin::KeyType keyType;
815 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
816 keyType = DrmPlugin::kKeyType_Streaming;
817 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
818 keyType = DrmPlugin::kKeyType_Offline;
819 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
820 keyType = DrmPlugin::kKeyType_Release;
821 } else {
822 jniThrowException(env, "java/lang/IllegalArgumentException",
823 "invalid keyType");
824 return NULL;
825 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800826
827 KeyedVector<String8, String8> optParams;
828 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200829 bool isOK;
830 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
831 if (!isOK) {
832 return NULL;
833 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800834 }
835
836 Vector<uint8_t> request;
837 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700838 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800839
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700840 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700841 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800842
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700843 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800844 return NULL;
845 }
846
847 // Fill out return obj
848 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700849 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800850
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700851 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800852
853 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700854 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800855 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700856 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800857
858 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700859 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700860
861 switch (keyRequestType) {
862 case DrmPlugin::kKeyRequestType_Initial:
863 env->SetIntField(keyObj, gFields.keyRequest.requestType,
864 gKeyRequestTypes.kKeyRequestTypeInitial);
865 break;
866 case DrmPlugin::kKeyRequestType_Renewal:
867 env->SetIntField(keyObj, gFields.keyRequest.requestType,
868 gKeyRequestTypes.kKeyRequestTypeRenewal);
869 break;
870 case DrmPlugin::kKeyRequestType_Release:
871 env->SetIntField(keyObj, gFields.keyRequest.requestType,
872 gKeyRequestTypes.kKeyRequestTypeRelease);
873 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700874 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700875 throwStateException(env, "DRM plugin failure: unknown key request type",
876 ERROR_DRM_UNKNOWN);
877 break;
878 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800879 }
880
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700881 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800882}
883
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700884static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800885 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
886 sp<IDrm> drm = GetDrm(env, thiz);
887
888 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700889 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800890 }
891
892 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
893
894 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700895 jniThrowException(env, "java/lang/IllegalArgumentException",
896 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700897 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800898 }
899 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700900 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800901
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700902 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800903
Jeff Tinker8117d8f2013-08-16 13:46:02 -0700904 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
905 return NULL;
906 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700907 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800908}
909
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700910static void android_media_MediaDrm_removeKeys(
911 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
912 sp<IDrm> drm = GetDrm(env, thiz);
913
914 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700915 jniThrowException(env, "java/lang/IllegalArgumentException",
916 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700917 return;
918 }
919
920 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
921
922 status_t err = drm->removeKeys(keySetId);
923
924 throwExceptionAsNecessary(env, err, "Failed to remove keys");
925}
926
927static void android_media_MediaDrm_restoreKeys(
928 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
929 jbyteArray jkeysetId) {
930
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800931 sp<IDrm> drm = GetDrm(env, thiz);
932
933 if (!CheckSession(env, drm, jsessionId)) {
934 return;
935 }
936
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700937 if (jkeysetId == NULL) {
938 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
939 return;
940 }
941
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800942 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700943 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800944
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700945 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800946
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700947 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800948}
949
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700950static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800951 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
952 sp<IDrm> drm = GetDrm(env, thiz);
953
954 if (!CheckSession(env, drm, jsessionId)) {
955 return NULL;
956 }
957 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
958
959 KeyedVector<String8, String8> infoMap;
960
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700961 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800962
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700963 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800964 return NULL;
965 }
966
967 return KeyedVectorToHashMap(env, infoMap);
968}
969
Jeff Tinkere4095a82014-03-04 13:17:11 -0800970static jobject android_media_MediaDrm_getProvisionRequestNative(
971 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800972 sp<IDrm> drm = GetDrm(env, thiz);
973
974 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700975 jniThrowException(env, "java/lang/IllegalStateException",
976 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800977 return NULL;
978 }
979
980 Vector<uint8_t> request;
981 String8 defaultUrl;
982
Jeff Tinkere4095a82014-03-04 13:17:11 -0800983 String8 certType;
984 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
985 certType = "X.509";
986 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
987 certType = "none";
988 } else {
989 certType = "invalid";
990 }
991
992 String8 certAuthority = JStringToString8(env, jcertAuthority);
993 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800994
995 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
996 return NULL;
997 }
998
999 // Fill out return obj
1000 jclass clazz;
1001 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1002
1003 jobject provisionObj = NULL;
1004
1005 if (clazz) {
1006 provisionObj = env->AllocObject(clazz);
1007 jbyteArray jrequest = VectorToJByteArray(env, request);
1008 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1009
1010 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1011 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1012 }
1013
1014 return provisionObj;
1015}
1016
Jeff Tinkere4095a82014-03-04 13:17:11 -08001017static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001018 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1019 sp<IDrm> drm = GetDrm(env, thiz);
1020
1021 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001022 jniThrowException(env, "java/lang/IllegalStateException",
1023 "MediaDrm obj is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001024 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001025 }
1026
1027 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001028 jniThrowException(env, "java/lang/IllegalArgumentException",
1029 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001030 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001031 }
1032
1033 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001034 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001035
Jeff Tinkere4095a82014-03-04 13:17:11 -08001036 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1037
1038 // Fill out return obj
1039 jclass clazz = gFields.certificateClassId;
1040
1041 jobject certificateObj = NULL;
1042
1043 if (clazz && certificate.size() && wrappedKey.size()) {
1044 certificateObj = env->AllocObject(clazz);
1045 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1046 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1047
1048 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1049 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1050 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001051
1052 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001053 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001054}
1055
1056static jobject android_media_MediaDrm_getSecureStops(
1057 JNIEnv *env, jobject thiz) {
1058 sp<IDrm> drm = GetDrm(env, thiz);
1059
1060 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001061 jniThrowException(env, "java/lang/IllegalStateException",
1062 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001063 return NULL;
1064 }
1065
1066 List<Vector<uint8_t> > secureStops;
1067
1068 status_t err = drm->getSecureStops(secureStops);
1069
1070 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1071 return NULL;
1072 }
1073
1074 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1075}
1076
Jeff Tinker1b51c722014-10-31 00:54:26 -07001077static jbyteArray android_media_MediaDrm_getSecureStop(
1078 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1079 sp<IDrm> drm = GetDrm(env, thiz);
1080
1081 if (drm == NULL) {
1082 jniThrowException(env, "java/lang/IllegalStateException",
1083 "MediaDrm obj is null");
1084 return NULL;
1085 }
1086
1087 Vector<uint8_t> secureStop;
1088
1089 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1090
1091 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1092 return NULL;
1093 }
1094
1095 return VectorToJByteArray(env, secureStop);
1096}
1097
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001098static void android_media_MediaDrm_releaseSecureStops(
1099 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1100 sp<IDrm> drm = GetDrm(env, thiz);
1101
1102 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001103 jniThrowException(env, "java/lang/IllegalStateException",
1104 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001105 return;
1106 }
1107
1108 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1109
1110 status_t err = drm->releaseSecureStops(ssRelease);
1111
1112 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1113}
1114
Jeff Tinker1b51c722014-10-31 00:54:26 -07001115static void android_media_MediaDrm_releaseAllSecureStops(
1116 JNIEnv *env, jobject thiz) {
1117 sp<IDrm> drm = GetDrm(env, thiz);
1118
1119 if (drm == NULL) {
1120 jniThrowException(env, "java/lang/IllegalStateException",
1121 "MediaDrm obj is null");
1122 return;
1123 }
1124
1125 status_t err = drm->releaseAllSecureStops();
1126
1127 throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
1128}
1129
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001130static jstring android_media_MediaDrm_getPropertyString(
1131 JNIEnv *env, jobject thiz, jstring jname) {
1132 sp<IDrm> drm = GetDrm(env, thiz);
1133
1134 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001135 jniThrowException(env, "java/lang/IllegalStateException",
1136 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001137 return NULL;
1138 }
1139
1140 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001141 jniThrowException(env, "java/lang/IllegalArgumentException",
1142 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001143 return NULL;
1144 }
1145
1146 String8 name = JStringToString8(env, jname);
1147 String8 value;
1148
1149 status_t err = drm->getPropertyString(name, value);
1150
1151 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1152 return NULL;
1153 }
1154
1155 return env->NewStringUTF(value.string());
1156}
1157
1158static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1159 JNIEnv *env, jobject thiz, jstring jname) {
1160 sp<IDrm> drm = GetDrm(env, thiz);
1161
1162 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001163 jniThrowException(env, "java/lang/IllegalStateException",
1164 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001165 return NULL;
1166 }
1167
1168 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001169 jniThrowException(env, "java/lang/IllegalArgumentException",
1170 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001171 return NULL;
1172 }
1173
1174 String8 name = JStringToString8(env, jname);
1175 Vector<uint8_t> value;
1176
1177 status_t err = drm->getPropertyByteArray(name, value);
1178
1179 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1180 return NULL;
1181 }
1182
1183 return VectorToJByteArray(env, value);
1184}
1185
1186static void android_media_MediaDrm_setPropertyString(
1187 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1188 sp<IDrm> drm = GetDrm(env, thiz);
1189
1190 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001191 jniThrowException(env, "java/lang/IllegalStateException",
1192 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001193 return;
1194 }
1195
Jeff Tinkereada5372013-05-21 12:48:14 -07001196 if (jname == NULL) {
1197 jniThrowException(env, "java/lang/IllegalArgumentException",
1198 "property name String is null");
1199 return;
1200 }
1201
1202 if (jvalue == NULL) {
1203 jniThrowException(env, "java/lang/IllegalArgumentException",
1204 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001205 return;
1206 }
1207
1208 String8 name = JStringToString8(env, jname);
1209 String8 value = JStringToString8(env, jvalue);
1210
1211 status_t err = drm->setPropertyString(name, value);
1212
1213 throwExceptionAsNecessary(env, err, "Failed to set property");
1214}
1215
1216static void android_media_MediaDrm_setPropertyByteArray(
1217 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1218 sp<IDrm> drm = GetDrm(env, thiz);
1219
1220 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001221 jniThrowException(env, "java/lang/IllegalStateException",
1222 "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001223 return;
1224 }
1225
Jeff Tinkereada5372013-05-21 12:48:14 -07001226 if (jname == NULL) {
1227 jniThrowException(env, "java/lang/IllegalArgumentException",
1228 "property name String is null");
1229 return;
1230 }
1231
1232 if (jvalue == NULL) {
1233 jniThrowException(env, "java/lang/IllegalArgumentException",
1234 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001235 return;
1236 }
1237
1238 String8 name = JStringToString8(env, jname);
1239 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1240
1241 status_t err = drm->setPropertyByteArray(name, value);
1242
1243 throwExceptionAsNecessary(env, err, "Failed to set property");
1244}
1245
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001246static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001247 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001248 jstring jalgorithm) {
1249
1250 sp<IDrm> drm = GetDrm(env, jdrm);
1251
1252 if (!CheckSession(env, drm, jsessionId)) {
1253 return;
1254 }
1255
1256 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001257 jniThrowException(env, "java/lang/IllegalArgumentException",
1258 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001259 return;
1260 }
1261
1262 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1263 String8 algorithm = JStringToString8(env, jalgorithm);
1264
1265 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1266
1267 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1268}
1269
1270static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001271 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001272 jstring jalgorithm) {
1273
1274 sp<IDrm> drm = GetDrm(env, jdrm);
1275
1276 if (!CheckSession(env, drm, jsessionId)) {
1277 return;
1278 }
1279
1280 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001281 jniThrowException(env, "java/lang/IllegalArgumentException",
1282 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001283 return;
1284 }
1285
1286 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1287 String8 algorithm = JStringToString8(env, jalgorithm);
1288
1289 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1290
1291 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1292}
1293
1294
1295static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001296 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001297 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1298
1299 sp<IDrm> drm = GetDrm(env, jdrm);
1300
1301 if (!CheckSession(env, drm, jsessionId)) {
1302 return NULL;
1303 }
1304
1305 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001306 jniThrowException(env, "java/lang/IllegalArgumentException",
1307 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001308 return NULL;
1309 }
1310
1311 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1312 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1313 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1314 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1315 Vector<uint8_t> output;
1316
1317 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1318
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001319 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1320 return NULL;
1321 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001322
1323 return VectorToJByteArray(env, output);
1324}
1325
1326static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001327 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001328 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1329
1330 sp<IDrm> drm = GetDrm(env, jdrm);
1331
1332 if (!CheckSession(env, drm, jsessionId)) {
1333 return NULL;
1334 }
1335
1336 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001337 jniThrowException(env, "java/lang/IllegalArgumentException",
1338 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001339 return NULL;
1340 }
1341
1342 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1343 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1344 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1345 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1346 Vector<uint8_t> output;
1347
1348 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001349 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1350 return NULL;
1351 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001352
1353 return VectorToJByteArray(env, output);
1354}
1355
1356static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001357 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001358 jbyteArray jkeyId, jbyteArray jmessage) {
1359
1360 sp<IDrm> drm = GetDrm(env, jdrm);
1361
1362 if (!CheckSession(env, drm, jsessionId)) {
1363 return NULL;
1364 }
1365
1366 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001367 jniThrowException(env, "java/lang/IllegalArgumentException",
1368 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001369 return NULL;
1370 }
1371
1372 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1373 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1374 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1375 Vector<uint8_t> signature;
1376
1377 status_t err = drm->sign(sessionId, keyId, message, signature);
1378
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001379 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1380 return NULL;
1381 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001382
1383 return VectorToJByteArray(env, signature);
1384}
1385
1386static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001387 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001388 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1389
1390 sp<IDrm> drm = GetDrm(env, jdrm);
1391
1392 if (!CheckSession(env, drm, jsessionId)) {
1393 return false;
1394 }
1395
1396 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001397 jniThrowException(env, "java/lang/IllegalArgumentException",
1398 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001399 return false;
1400 }
1401
1402 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1403 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1404 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1405 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1406 bool match;
1407
1408 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1409
1410 throwExceptionAsNecessary(env, err, "Failed to verify");
1411 return match;
1412}
1413
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001414
Jeff Tinkere4095a82014-03-04 13:17:11 -08001415static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001416 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001417 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1418
1419 sp<IDrm> drm = GetDrm(env, jdrm);
1420
1421 if (!CheckSession(env, drm, jsessionId)) {
1422 return NULL;
1423 }
1424
1425 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1426 jniThrowException(env, "java/lang/IllegalArgumentException",
1427 "required argument is null");
1428 return NULL;
1429 }
1430
1431 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1432 String8 algorithm = JStringToString8(env, jalgorithm);
1433 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1434 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1435 Vector<uint8_t> signature;
1436
1437 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1438
1439 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1440 return NULL;
1441 }
1442
1443 return VectorToJByteArray(env, signature);
1444}
1445
1446
Daniel Micay76f6a862015-09-19 17:31:01 -04001447static const JNINativeMethod gMethods[] = {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001448 { "release", "()V", (void *)android_media_MediaDrm_release },
1449 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1450
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001451 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001452 (void *)android_media_MediaDrm_native_setup },
1453
1454 { "native_finalize", "()V",
1455 (void *)android_media_MediaDrm_native_finalize },
1456
Jeff Tinker7cda4912013-08-21 11:52:34 -07001457 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001458 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1459
1460 { "openSession", "()[B",
1461 (void *)android_media_MediaDrm_openSession },
1462
1463 { "closeSession", "([B)V",
1464 (void *)android_media_MediaDrm_closeSession },
1465
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001466 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1467 "Landroid/media/MediaDrm$KeyRequest;",
1468 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001469
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001470 { "provideKeyResponse", "([B[B)[B",
1471 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001472
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001473 { "removeKeys", "([B)V",
1474 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001475
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001476 { "restoreKeys", "([B[B)V",
1477 (void *)android_media_MediaDrm_restoreKeys },
1478
1479 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1480 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001481
Jeff Tinkere4095a82014-03-04 13:17:11 -08001482 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1483 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001484
Jeff Tinkere4095a82014-03-04 13:17:11 -08001485 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1486 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001487
1488 { "getSecureStops", "()Ljava/util/List;",
1489 (void *)android_media_MediaDrm_getSecureStops },
1490
Jeff Tinker1b51c722014-10-31 00:54:26 -07001491 { "getSecureStop", "([B)[B",
1492 (void *)android_media_MediaDrm_getSecureStop },
1493
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001494 { "releaseSecureStops", "([B)V",
1495 (void *)android_media_MediaDrm_releaseSecureStops },
1496
Jeff Tinker1b51c722014-10-31 00:54:26 -07001497 { "releaseAllSecureStops", "()V",
1498 (void *)android_media_MediaDrm_releaseAllSecureStops },
1499
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001500 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1501 (void *)android_media_MediaDrm_getPropertyString },
1502
1503 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1504 (void *)android_media_MediaDrm_getPropertyByteArray },
1505
1506 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1507 (void *)android_media_MediaDrm_setPropertyString },
1508
1509 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1510 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001511
1512 { "setCipherAlgorithmNative",
1513 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1514 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1515
1516 { "setMacAlgorithmNative",
1517 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1518 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1519
1520 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1521 (void *)android_media_MediaDrm_encryptNative },
1522
1523 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1524 (void *)android_media_MediaDrm_decryptNative },
1525
1526 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1527 (void *)android_media_MediaDrm_signNative },
1528
1529 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1530 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08001531
1532 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1533 (void *)android_media_MediaDrm_signRSANative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001534};
1535
1536int register_android_media_Drm(JNIEnv *env) {
1537 return AndroidRuntime::registerNativeMethods(env,
1538 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1539}