blob: be71dad571bbaf4b566c83a7614a0df77c593df2 [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"
Adam Stonec06e10e2017-12-19 12:54:33 -080022#include "android_media_MediaMetricsJNI.h"
Adam Stone94395c92018-01-30 12:07:00 -080023#include "android_os_Parcel.h"
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080024#include "android_runtime/AndroidRuntime.h"
Ruben Brunk87eac992013-09-09 17:44:59 -070025#include "android_runtime/Log.h"
Jeff Tinker54cfbd62013-04-02 13:14:59 -070026#include "android_os_Parcel.h"
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080027#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070028#include <nativehelper/JNIHelp.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080029
30#include <binder/IServiceManager.h>
Jeff Tinker54cfbd62013-04-02 13:14:59 -070031#include <binder/Parcel.h>
Adam Stone94395c92018-01-30 12:07:00 -080032#include <binder/PersistableBundle.h>
Jeff Tinkerdc614f82016-02-12 08:58:32 -080033#include <cutils/properties.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 Tinkercd4d28f2018-02-16 16:24:49 -080036#include <mediadrm/IDrm.h>
37#include <mediadrm/IMediaDrmService.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080038
Adam Stone94395c92018-01-30 12:07:00 -080039using ::android::os::PersistableBundle;
40
41
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080042namespace android {
43
44#define FIND_CLASS(var, className) \
45 var = env->FindClass(className); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070046 LOG_FATAL_IF(! (var), "Unable to find class %s", className);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080047
48#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
49 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070050 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080051
52#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
53 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070054 LOG_FATAL_IF(! (var), "Unable to find method %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080055
Jeff Tinker54cfbd62013-04-02 13:14:59 -070056#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
57 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070058 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070059
60#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
61 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070062 LOG_FATAL_IF(! (var), "Unable to find static method %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070063
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070064#define GET_STATIC_OBJECT_FIELD(var, clazz, fieldId) \
65 var = env->GetStaticObjectField(clazz, fieldId); \
66 LOG_FATAL_IF(! (var), "Unable to find static object field %p", fieldId);
Adam Stone94395c92018-01-30 12:07:00 -080067
Jeff Tinker54cfbd62013-04-02 13:14:59 -070068
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080069struct RequestFields {
70 jfieldID data;
71 jfieldID defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -070072 jfieldID requestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080073};
74
75struct ArrayListFields {
76 jmethodID init;
77 jmethodID add;
78};
79
80struct HashmapFields {
81 jmethodID init;
82 jmethodID get;
83 jmethodID put;
84 jmethodID entrySet;
85};
86
87struct SetFields {
88 jmethodID iterator;
89};
90
91struct IteratorFields {
92 jmethodID next;
93 jmethodID hasNext;
94};
95
96struct EntryFields {
97 jmethodID getKey;
98 jmethodID getValue;
99};
100
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700101struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -0700102 jint kEventProvisionRequired;
103 jint kEventKeyRequired;
104 jint kEventKeyExpired;
105 jint kEventVendorDefined;
Ronghua Wua6d72092015-03-04 11:16:02 -0800106 jint kEventSessionReclaimed;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700107} gEventTypes;
108
Jeff Tinker74797f82015-03-31 15:44:34 -0700109struct EventWhat {
110 jint kWhatDrmEvent;
111 jint kWhatExpirationUpdate;
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700112 jint kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700113} gEventWhat;
114
Jeff Tinker17b89222013-05-21 12:35:06 -0700115struct KeyTypes {
116 jint kKeyTypeStreaming;
117 jint kKeyTypeOffline;
118 jint kKeyTypeRelease;
119} gKeyTypes;
120
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700121struct KeyRequestTypes {
122 jint kKeyRequestTypeInitial;
123 jint kKeyRequestTypeRenewal;
124 jint kKeyRequestTypeRelease;
Rahul Frias8f761ba2018-01-22 23:43:54 -0800125 jint kKeyRequestTypeNone;
126 jint kKeyRequestTypeUpdate;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700127} gKeyRequestTypes;
128
Jeff Tinkere4095a82014-03-04 13:17:11 -0800129struct CertificateTypes {
130 jint kCertificateTypeNone;
131 jint kCertificateTypeX509;
132} gCertificateTypes;
133
134struct CertificateFields {
135 jfieldID wrappedPrivateKey;
136 jfieldID certificateData;
137};
138
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700139struct StateExceptionFields {
140 jmethodID init;
141 jclass classId;
142};
143
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800144struct HDCPLevels {
145 jint kHdcpLevelUnknown;
146 jint kHdcpNone;
147 jint kHdcpV1;
148 jint kHdcpV2;
149 jint kHdcpV2_1;
150 jint kHdcpV2_2;
151 jint kHdcpNoOutput;
152} gHdcpLevels;
153
154struct SecurityLevels {
155 jint kSecurityLevelUnknown;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000156 jint kSecurityLevelMax;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800157 jint kSecurityLevelSwSecureCrypto;
158 jint kSecurityLevelSwSecureDecode;
159 jint kSecurityLevelHwSecureCrypto;
160 jint kSecurityLevelHwSecureDecode;
161 jint kSecurityLevelHwSecureAll;
162} gSecurityLevels;
163
Jeff Tinker55d26242018-10-10 16:10:43 -0700164struct OfflineLicenseState {
165 jint kOfflineLicenseStateUsable;
166 jint kOfflineLicenseStateInactive;
167 jint kOfflineLicenseStateUnknown;
168} gOfflineLicenseStates;
169
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800170
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800171struct fields_t {
172 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700173 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700174 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800175 RequestFields provisionRequest;
176 ArrayListFields arraylist;
177 HashmapFields hashmap;
178 SetFields set;
179 IteratorFields iterator;
180 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800181 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700182 StateExceptionFields stateException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800183 jclass certificateClassId;
184 jclass hashmapClassId;
185 jclass arraylistClassId;
186 jclass stringClassId;
Adam Stone94395c92018-01-30 12:07:00 -0800187 jobject bundleCreator;
188 jmethodID createFromParcelId;
189 jclass parcelCreatorClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800190};
191
192static fields_t gFields;
193
Adam Stone94395c92018-01-30 12:07:00 -0800194namespace {
195
196// Helper function to convert a native PersistableBundle to a Java
197// PersistableBundle.
198jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
199 PersistableBundle* nativeBundle) {
200 if (env == NULL || thiz == NULL || nativeBundle == NULL) {
201 ALOGE("Unexpected NULL parmeter");
202 return NULL;
203 }
204
205 // Create a Java parcel with the native parcel data.
206 // Then create a new PersistableBundle with that parcel as a parameter.
207 jobject jParcel = android::createJavaParcelObject(env);
208 if (jParcel == NULL) {
209 ALOGE("Failed to create a Java Parcel.");
210 return NULL;
211 }
212
213 android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
214 if (nativeParcel == NULL) {
215 ALOGE("Failed to get the native Parcel.");
216 return NULL;
217 }
218
219 android::status_t result = nativeBundle->writeToParcel(nativeParcel);
220 nativeParcel->setDataPosition(0);
221 if (result != android::OK) {
222 ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
223 return NULL;
224 }
225
226 jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
227 gFields.createFromParcelId,
228 jParcel);
229 if (newBundle == NULL) {
230 ALOGE("Failed to create a new PersistableBundle "
231 "from the createFromParcel call.");
232 }
233
234 return newBundle;
235}
236
237} // namespace anonymous
238
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700239// ----------------------------------------------------------------------------
240// ref-counted object for callbacks
241class JNIDrmListener: public DrmListener
242{
243public:
244 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
245 ~JNIDrmListener();
246 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
247private:
248 JNIDrmListener();
249 jclass mClass; // Reference to MediaDrm class
250 jobject mObject; // Weak ref to MediaDrm Java object to call on
251};
252
253JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
254{
255 // Hold onto the MediaDrm class for use in calling the static method
256 // that posts events to the application thread.
257 jclass clazz = env->GetObjectClass(thiz);
258 if (clazz == NULL) {
259 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700260 jniThrowException(env, "java/lang/Exception",
261 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700262 return;
263 }
264 mClass = (jclass)env->NewGlobalRef(clazz);
265
266 // We use a weak reference so the MediaDrm object can be garbage collected.
267 // The reference is only used as a proxy for callbacks.
268 mObject = env->NewGlobalRef(weak_thiz);
269}
270
271JNIDrmListener::~JNIDrmListener()
272{
273 // remove global references
274 JNIEnv *env = AndroidRuntime::getJNIEnv();
275 env->DeleteGlobalRef(mObject);
276 env->DeleteGlobalRef(mClass);
277}
278
279void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
280 const Parcel *obj)
281{
Jeff Tinker74797f82015-03-31 15:44:34 -0700282 jint jwhat;
283 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700284
285 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700286 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700287 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700288 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700289 jeventType = gEventTypes.kEventProvisionRequired;
290 break;
291 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700292 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700293 jeventType = gEventTypes.kEventKeyRequired;
294 break;
295 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700296 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700297 jeventType = gEventTypes.kEventKeyExpired;
298 break;
299 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700300 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700301 jeventType = gEventTypes.kEventVendorDefined;
302 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800303 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700304 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800305 jeventType = gEventTypes.kEventSessionReclaimed;
306 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700307 case DrmPlugin::kDrmPluginEventExpirationUpdate:
308 jwhat = gEventWhat.kWhatExpirationUpdate;
309 break;
310 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700311 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700312 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700313 default:
314 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
315 return;
316 }
317
318 JNIEnv *env = AndroidRuntime::getJNIEnv();
319 if (obj && obj->dataSize() > 0) {
320 jobject jParcel = createJavaParcelObject(env);
321 if (jParcel != NULL) {
322 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
323 nativeParcel->setData(obj->data(), obj->dataSize());
324 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
Jeff Tinker74797f82015-03-31 15:44:34 -0700325 jwhat, jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100326 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700327 }
328 }
329
330 if (env->ExceptionCheck()) {
331 ALOGW("An exception occurred while notifying an event.");
332 LOGW_EX(env);
333 env->ExceptionClear();
334 }
335}
336
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700337static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
338 ALOGE("Illegal state exception: %s (%d)", msg, err);
339
340 jobject exception = env->NewObject(gFields.stateException.classId,
341 gFields.stateException.init, static_cast<int>(err),
342 env->NewStringUTF(msg));
343 env->Throw(static_cast<jthrowable>(exception));
344}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700345
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800346static bool throwExceptionAsNecessary(
347 JNIEnv *env, status_t err, const char *msg = NULL) {
348
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700349 const char *drmMessage = NULL;
350
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700351 switch (err) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700352 case ERROR_DRM_UNKNOWN:
353 drmMessage = "General DRM error";
354 break;
355 case ERROR_DRM_NO_LICENSE:
356 drmMessage = "No license";
357 break;
358 case ERROR_DRM_LICENSE_EXPIRED:
359 drmMessage = "License expired";
360 break;
361 case ERROR_DRM_SESSION_NOT_OPENED:
362 drmMessage = "Session not opened";
363 break;
364 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
365 drmMessage = "Not initialized";
366 break;
367 case ERROR_DRM_DECRYPT:
368 drmMessage = "Decrypt error";
369 break;
370 case ERROR_DRM_CANNOT_HANDLE:
Jeff Tinkereb13c762017-11-01 15:29:38 -0700371 drmMessage = "Invalid parameter or data format";
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700372 break;
373 case ERROR_DRM_TAMPER_DETECTED:
374 drmMessage = "Invalid state";
375 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700376 default:
377 break;
378 }
379
380 String8 vendorMessage;
381 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
Jeff Tinker29799862014-08-27 11:05:13 -0700382 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700383 drmMessage = vendorMessage.string();
384 }
385
Jeff Tinkereb13c762017-11-01 15:29:38 -0700386 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800387 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
388 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700389 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
390 jniThrowException(env, "android/media/NotProvisionedException", msg);
391 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700392 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
393 jniThrowException(env, "android/media/ResourceBusyException", msg);
394 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700395 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
396 jniThrowException(env, "android/media/DeniedByServerException", msg);
397 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700398 } else if (err == DEAD_OBJECT) {
399 jniThrowException(env, "android/media/MediaDrmResetException",
400 "mediaserver died");
401 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800402 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700403 String8 errbuf;
404 if (drmMessage != NULL) {
405 if (msg == NULL) {
406 msg = drmMessage;
407 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700408 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700409 msg = errbuf.string();
410 }
411 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700412 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800413 return true;
414 }
415 return false;
416}
417
418static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000419 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800420 return jdrm ? jdrm->getDrm() : NULL;
421}
422
423JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800424 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
425 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800426 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800427 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700428 if (mDrm != NULL) {
429 mDrm->setListener(this);
430 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800431}
432
433JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800434 JNIEnv *env = AndroidRuntime::getJNIEnv();
435
436 env->DeleteWeakGlobalRef(mObject);
437 mObject = NULL;
438}
439
440// static
441sp<IDrm> JDrm::MakeDrm() {
442 sp<IServiceManager> sm = defaultServiceManager();
443
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700444 sp<IBinder> binder = sm->getService(String16("media.drm"));
445 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
446 if (service == NULL) {
447 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800448 }
449
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700450 sp<IDrm> drm = service->makeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800451 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
452 return NULL;
453 }
454
455 return drm;
456}
457
458// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800459sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800460 sp<IDrm> drm = MakeDrm();
461
462 if (drm == NULL) {
463 return NULL;
464 }
465
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800466 status_t err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800467
468 if (err != OK) {
469 return NULL;
470 }
471
472 return drm;
473}
474
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700475status_t JDrm::setListener(const sp<DrmListener>& listener) {
476 Mutex::Autolock lock(mLock);
477 mListener = listener;
478 return OK;
479}
480
481void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
482 sp<DrmListener> listener;
483 mLock.lock();
484 listener = mListener;
485 mLock.unlock();
486
487 if (listener != NULL) {
488 Mutex::Autolock lock(mNotifyLock);
489 listener->notify(eventType, extra, obj);
490 }
491}
492
Jeff Tinker600071c2014-04-11 16:11:15 -0700493void JDrm::disconnect() {
494 if (mDrm != NULL) {
495 mDrm->destroyPlugin();
496 mDrm.clear();
497 }
498}
499
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700500
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800501// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700502bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800503 sp<IDrm> drm = MakeDrm();
504
505 if (drm == NULL) {
506 return false;
507 }
508
Jeff Tinker7cda4912013-08-21 11:52:34 -0700509 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800510}
511
512status_t JDrm::initCheck() const {
513 return mDrm == NULL ? NO_INIT : OK;
514}
515
516// JNI conversion utilities
517static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
518 Vector<uint8_t> vector;
519 size_t length = env->GetArrayLength(byteArray);
520 vector.insertAt((size_t)0, length);
521 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
522 return vector;
523}
524
525static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
526 size_t length = vector.size();
527 jbyteArray result = env->NewByteArray(length);
528 if (result != NULL) {
529 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
530 }
531 return result;
532}
533
534static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800535 String8 result;
536
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700537 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800538 if (s) {
539 result = s;
540 env->ReleaseStringUTFChars(jstr, s);
541 }
542 return result;
543}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700544
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800545/*
546 import java.util.HashMap;
547 import java.util.Set;
548 import java.Map.Entry;
549 import jav.util.Iterator;
550
551 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800552 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800553 Iterator i = s.iterator();
554 Entry e = s.next();
555*/
556
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200557static KeyedVector<String8, String8> HashMapToKeyedVector(
558 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800559 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800560 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200561 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800562
563 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
564 if (entrySet) {
565 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
566 if (iterator) {
567 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
568 while (hasNext) {
569 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
570 if (entry) {
571 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200572 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700573 jniThrowException(env, "java/lang/IllegalArgumentException",
574 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200575 env->DeleteLocalRef(entry);
576 *pIsOK = false;
577 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800578 }
579 jstring jkey = static_cast<jstring>(obj);
580
581 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200582 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700583 jniThrowException(env, "java/lang/IllegalArgumentException",
584 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200585 env->DeleteLocalRef(entry);
586 *pIsOK = false;
587 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800588 }
589 jstring jvalue = static_cast<jstring>(obj);
590
591 String8 key = JStringToString8(env, jkey);
592 String8 value = JStringToString8(env, jvalue);
593 keyedVector.add(key, value);
594
595 env->DeleteLocalRef(jkey);
596 env->DeleteLocalRef(jvalue);
597 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
598 }
599 env->DeleteLocalRef(entry);
600 }
601 env->DeleteLocalRef(iterator);
602 }
603 env->DeleteLocalRef(entrySet);
604 }
605 return keyedVector;
606}
607
608static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800609 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800610 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
611 for (size_t i = 0; i < map.size(); ++i) {
612 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
613 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
614 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
615 env->DeleteLocalRef(jkey);
616 env->DeleteLocalRef(jvalue);
617 }
618 return hashMap;
619}
620
621static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800622 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800623 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800624 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800625 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800626 while (iter != list.end()) {
627 jbyteArray byteArray = VectorToJByteArray(env, *iter);
628 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
629 env->DeleteLocalRef(byteArray);
630 iter++;
631 }
632
633 return arrayList;
634}
635
636} // namespace android
637
638using namespace android;
639
640static sp<JDrm> setDrm(
641 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000642 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800643 if (drm != NULL) {
644 drm->incStrong(thiz);
645 }
646 if (old != NULL) {
647 old->decStrong(thiz);
648 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000649 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800650
651 return old;
652}
653
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800654static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800655 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700656 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800657 return false;
658 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800659 return true;
660}
661
662static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
663{
664 if (!CheckDrm(env, drm)) {
665 return false;
666 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800667
668 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700669 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800670 return false;
671 }
672 return true;
673}
674
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800675static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700676 sp<JDrm> drm = setDrm(env, thiz, NULL);
677 if (drm != NULL) {
678 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700679 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700680 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800681}
682
683static void android_media_MediaDrm_native_init(JNIEnv *env) {
684 jclass clazz;
685 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000686 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700687 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700688 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700689
690 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700691 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700692 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700693 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700694 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700695 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700696 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700697 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700698 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800699 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
700 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800701
Jeff Tinker74797f82015-03-31 15:44:34 -0700702 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
703 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
704 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
705 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700706 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
707 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700708
Jeff Tinker17b89222013-05-21 12:35:06 -0700709 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
710 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
711 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
712 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
713 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
714 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
715
Jeff Tinkere4095a82014-03-04 13:17:11 -0800716 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
717 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
718 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
719 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
720
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800721 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
722 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
723 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
724 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
725 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
726 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
727 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
728 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
729 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
730 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
731 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
732 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
733 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
734 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
735
736 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
737 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700738 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800739 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700740 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800741 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700742 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800743 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700744 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800745 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700746 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800747 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
748
Jeff Tinker55d26242018-10-10 16:10:43 -0700749 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_USABLE", "I");
750 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
751 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_INACTIVE", "I");
752 gOfflineLicenseStates.kOfflineLicenseStateInactive = env->GetStaticIntField(clazz, field);
753 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
754 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
755
756 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
757
Jeff Tinker2bca5252018-02-11 18:59:14 +0000758 jmethodID getMaxSecurityLevel;
759 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
760 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
761
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700762 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700763 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
764 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700765 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800766
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700767 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
768 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
769 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
770 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
771 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
772 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800773 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
774 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
775 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
776 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700777
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800778 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700779 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
780 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800781
Jeff Tinkere4095a82014-03-04 13:17:11 -0800782 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
783 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
784 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700785 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800786
Adam Stone94395c92018-01-30 12:07:00 -0800787 // Metrics-related fields and classes.
788 FIND_CLASS(clazz, "android/os/PersistableBundle");
789 jfieldID bundleCreatorId;
790 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
791 "Landroid/os/Parcelable$Creator;");
792 jobject bundleCreator;
793 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
794 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
795 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
796 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
797 "(Landroid/os/Parcel;)Ljava/lang/Object;");
798 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
799
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800800 FIND_CLASS(clazz, "java/util/ArrayList");
801 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
802 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
803
804 FIND_CLASS(clazz, "java/util/HashMap");
805 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
806 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
807 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
808 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
809 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
810
811 FIND_CLASS(clazz, "java/util/Set");
812 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
813
814 FIND_CLASS(clazz, "java/util/Iterator");
815 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
816 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
817
818 FIND_CLASS(clazz, "java/util/Map$Entry");
819 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
820 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800821
822 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700823 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800824
825 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700826 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800827
828 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700829 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700830
831 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
832 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
833 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800834}
835
836static void android_media_MediaDrm_native_setup(
837 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800838 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800839
840 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700841 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800842 return;
843 }
844
845 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
846
847 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700848 jniThrowException(env, "java/lang/IllegalArgumentException",
849 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800850 return;
851 }
852
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800853 String8 packageName;
854 if (jappPackageName == NULL) {
855 jniThrowException(env, "java/lang/IllegalArgumentException",
856 "application package name cannot be null");
857 return;
858 }
859
860 packageName = JStringToString8(env, jappPackageName);
861 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800862
863 status_t err = drm->initCheck();
864
865 if (err != OK) {
866 jniThrowException(
867 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700868 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800869 "Failed to instantiate drm object.");
870 return;
871 }
872
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700873 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
874 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800875 setDrm(env, thiz, drm);
876}
877
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800878static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800879 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800880
881 if (uuidObj == NULL) {
882 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
883 return false;
884 }
885
886 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
887
888 if (uuid.size() != 16) {
889 jniThrowException(
890 env,
891 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700892 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800893 return false;
894 }
895
Jeff Tinker7cda4912013-08-21 11:52:34 -0700896 String8 mimeType;
897 if (jmimeType != NULL) {
898 mimeType = JStringToString8(env, jmimeType);
899 }
900
901 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800902}
903
904static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +0000905 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800906 sp<IDrm> drm = GetDrm(env, thiz);
907
Jeff Tinker55d26242018-10-10 16:10:43 -0700908 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800909 return NULL;
910 }
911
912 Vector<uint8_t> sessionId;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000913 DrmPlugin::SecurityLevel level;
914
915 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
916 level = DrmPlugin::kSecurityLevelMax;
917 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
918 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
919 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
920 level = DrmPlugin::kSecurityLevelSwSecureDecode;
921 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
922 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
923 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
924 level = DrmPlugin::kSecurityLevelHwSecureDecode;
925 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
926 level = DrmPlugin::kSecurityLevelHwSecureAll;
927 } else {
928 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
929 return NULL;
930 }
931
932 status_t err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800933
934 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
935 return NULL;
936 }
937
938 return VectorToJByteArray(env, sessionId);
939}
940
941static void android_media_MediaDrm_closeSession(
942 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
943 sp<IDrm> drm = GetDrm(env, thiz);
944
945 if (!CheckSession(env, drm, jsessionId)) {
946 return;
947 }
948
949 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
950
951 status_t err = drm->closeSession(sessionId);
952
953 throwExceptionAsNecessary(env, err, "Failed to close session");
954}
955
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700956static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800957 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700958 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800959 sp<IDrm> drm = GetDrm(env, thiz);
960
961 if (!CheckSession(env, drm, jsessionId)) {
962 return NULL;
963 }
964
965 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
966
967 Vector<uint8_t> initData;
968 if (jinitData != NULL) {
969 initData = JByteArrayToVector(env, jinitData);
970 }
971
972 String8 mimeType;
973 if (jmimeType != NULL) {
974 mimeType = JStringToString8(env, jmimeType);
975 }
976
Jeff Tinker17b89222013-05-21 12:35:06 -0700977 DrmPlugin::KeyType keyType;
978 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
979 keyType = DrmPlugin::kKeyType_Streaming;
980 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
981 keyType = DrmPlugin::kKeyType_Offline;
982 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
983 keyType = DrmPlugin::kKeyType_Release;
984 } else {
985 jniThrowException(env, "java/lang/IllegalArgumentException",
986 "invalid keyType");
987 return NULL;
988 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800989
990 KeyedVector<String8, String8> optParams;
991 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200992 bool isOK;
993 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
994 if (!isOK) {
995 return NULL;
996 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800997 }
998
999 Vector<uint8_t> request;
1000 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001001 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001002
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001003 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001004 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001005
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001006 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001007 return NULL;
1008 }
1009
1010 // Fill out return obj
1011 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001012 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001013
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001014 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001015
1016 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001017 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001018 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001019 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001020
1021 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001022 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001023
1024 switch (keyRequestType) {
1025 case DrmPlugin::kKeyRequestType_Initial:
1026 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1027 gKeyRequestTypes.kKeyRequestTypeInitial);
1028 break;
1029 case DrmPlugin::kKeyRequestType_Renewal:
1030 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1031 gKeyRequestTypes.kKeyRequestTypeRenewal);
1032 break;
1033 case DrmPlugin::kKeyRequestType_Release:
1034 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1035 gKeyRequestTypes.kKeyRequestTypeRelease);
1036 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001037 case DrmPlugin::kKeyRequestType_None:
1038 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1039 gKeyRequestTypes.kKeyRequestTypeNone);
1040 break;
1041 case DrmPlugin::kKeyRequestType_Update:
1042 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1043 gKeyRequestTypes.kKeyRequestTypeUpdate);
1044 break;
1045
Jeff Tinker74797f82015-03-31 15:44:34 -07001046 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001047 throwStateException(env, "DRM plugin failure: unknown key request type",
1048 ERROR_DRM_UNKNOWN);
1049 break;
1050 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001051 }
1052
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001053 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001054}
1055
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001056static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001057 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1058 sp<IDrm> drm = GetDrm(env, thiz);
1059
1060 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001061 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001062 }
1063
1064 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1065
1066 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001067 jniThrowException(env, "java/lang/IllegalArgumentException",
1068 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001069 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001070 }
1071 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001072 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001073
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001074 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001075
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001076 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
1077 return NULL;
1078 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001079 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001080}
1081
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001082static void android_media_MediaDrm_removeKeys(
1083 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1084 sp<IDrm> drm = GetDrm(env, thiz);
1085
Jeff Tinker55d26242018-10-10 16:10:43 -07001086 if (!CheckDrm(env, drm)) {
1087 return;
1088 }
1089
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001090 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001091 jniThrowException(env, "java/lang/IllegalArgumentException",
1092 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001093 return;
1094 }
1095
1096 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1097
1098 status_t err = drm->removeKeys(keySetId);
1099
1100 throwExceptionAsNecessary(env, err, "Failed to remove keys");
1101}
1102
1103static void android_media_MediaDrm_restoreKeys(
1104 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1105 jbyteArray jkeysetId) {
1106
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001107 sp<IDrm> drm = GetDrm(env, thiz);
1108
1109 if (!CheckSession(env, drm, jsessionId)) {
1110 return;
1111 }
1112
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001113 if (jkeysetId == NULL) {
1114 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1115 return;
1116 }
1117
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001118 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001119 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001120
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001121 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001122
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001123 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001124}
1125
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001126static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001127 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1128 sp<IDrm> drm = GetDrm(env, thiz);
1129
1130 if (!CheckSession(env, drm, jsessionId)) {
1131 return NULL;
1132 }
1133 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1134
1135 KeyedVector<String8, String8> infoMap;
1136
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001137 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001138
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001139 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001140 return NULL;
1141 }
1142
1143 return KeyedVectorToHashMap(env, infoMap);
1144}
1145
Jeff Tinkere4095a82014-03-04 13:17:11 -08001146static jobject android_media_MediaDrm_getProvisionRequestNative(
1147 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001148 sp<IDrm> drm = GetDrm(env, thiz);
1149
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001150 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001151 return NULL;
1152 }
1153
1154 Vector<uint8_t> request;
1155 String8 defaultUrl;
1156
Jeff Tinkere4095a82014-03-04 13:17:11 -08001157 String8 certType;
1158 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1159 certType = "X.509";
1160 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1161 certType = "none";
1162 } else {
1163 certType = "invalid";
1164 }
1165
1166 String8 certAuthority = JStringToString8(env, jcertAuthority);
1167 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001168
1169 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
1170 return NULL;
1171 }
1172
1173 // Fill out return obj
1174 jclass clazz;
1175 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1176
1177 jobject provisionObj = NULL;
1178
1179 if (clazz) {
1180 provisionObj = env->AllocObject(clazz);
1181 jbyteArray jrequest = VectorToJByteArray(env, request);
1182 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1183
1184 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1185 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1186 }
1187
1188 return provisionObj;
1189}
1190
Jeff Tinkere4095a82014-03-04 13:17:11 -08001191static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001192 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1193 sp<IDrm> drm = GetDrm(env, thiz);
1194
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001195 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001196 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001197 }
1198
1199 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001200 jniThrowException(env, "java/lang/IllegalArgumentException",
1201 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001202 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001203 }
1204
1205 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001206 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001207
Jeff Tinkere4095a82014-03-04 13:17:11 -08001208 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1209
1210 // Fill out return obj
1211 jclass clazz = gFields.certificateClassId;
1212
1213 jobject certificateObj = NULL;
1214
1215 if (clazz && certificate.size() && wrappedKey.size()) {
1216 certificateObj = env->AllocObject(clazz);
1217 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1218 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1219
1220 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1221 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1222 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001223
1224 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001225 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001226}
1227
1228static jobject android_media_MediaDrm_getSecureStops(
1229 JNIEnv *env, jobject thiz) {
1230 sp<IDrm> drm = GetDrm(env, thiz);
1231
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001232 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001233 return NULL;
1234 }
1235
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001236 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001237
1238 status_t err = drm->getSecureStops(secureStops);
1239
1240 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1241 return NULL;
1242 }
1243
1244 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1245}
1246
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001247static jobject android_media_MediaDrm_getSecureStopIds(
1248 JNIEnv *env, jobject thiz) {
1249 sp<IDrm> drm = GetDrm(env, thiz);
1250
Jeff Tinker55d26242018-10-10 16:10:43 -07001251 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001252 return NULL;
1253 }
1254
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001255 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001256
1257 status_t err = drm->getSecureStopIds(secureStopIds);
1258
1259 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop Ids")) {
1260 return NULL;
1261 }
1262
1263 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1264}
1265
Jeff Tinker1b51c722014-10-31 00:54:26 -07001266static jbyteArray android_media_MediaDrm_getSecureStop(
1267 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1268 sp<IDrm> drm = GetDrm(env, thiz);
1269
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001270 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001271 return NULL;
1272 }
1273
1274 Vector<uint8_t> secureStop;
1275
1276 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1277
1278 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1279 return NULL;
1280 }
1281
1282 return VectorToJByteArray(env, secureStop);
1283}
1284
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001285static void android_media_MediaDrm_releaseSecureStops(
1286 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1287 sp<IDrm> drm = GetDrm(env, thiz);
1288
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001289 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001290 return;
1291 }
1292
1293 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1294
1295 status_t err = drm->releaseSecureStops(ssRelease);
1296
1297 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1298}
1299
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001300static void android_media_MediaDrm_removeSecureStop(
1301 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1302 sp<IDrm> drm = GetDrm(env, thiz);
1303
Jeff Tinker55d26242018-10-10 16:10:43 -07001304 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001305 return;
1306 }
1307
1308 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1309
1310 throwExceptionAsNecessary(env, err, "Failed to remove secure stop");
1311}
1312
1313static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001314 JNIEnv *env, jobject thiz) {
1315 sp<IDrm> drm = GetDrm(env, thiz);
1316
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001317 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001318 return;
1319 }
1320
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001321 status_t err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001322
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001323 throwExceptionAsNecessary(env, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001324}
1325
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001326
1327static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1328 switch(level) {
1329 case DrmPlugin::kHdcpLevelUnknown:
1330 return gHdcpLevels.kHdcpLevelUnknown;
1331 case DrmPlugin::kHdcpNone:
1332 return gHdcpLevels.kHdcpNone;
1333 case DrmPlugin::kHdcpV1:
1334 return gHdcpLevels.kHdcpV1;
1335 case DrmPlugin::kHdcpV2:
1336 return gHdcpLevels.kHdcpV2;
1337 case DrmPlugin::kHdcpV2_1:
1338 return gHdcpLevels.kHdcpV2_1;
1339 case DrmPlugin::kHdcpV2_2:
1340 return gHdcpLevels.kHdcpV2_2;
1341 case DrmPlugin::kHdcpNoOutput:
1342 return gHdcpLevels.kHdcpNoOutput;
1343 }
1344 return gHdcpLevels.kHdcpNone;
1345}
1346
1347static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1348 jobject thiz) {
1349 sp<IDrm> drm = GetDrm(env, thiz);
1350
1351 if (!CheckDrm(env, drm)) {
1352 return gHdcpLevels.kHdcpNone;
1353 }
1354
1355 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1356 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1357
1358 status_t err = drm->getHdcpLevels(&connected, &max);
1359
1360 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1361 return gHdcpLevels.kHdcpLevelUnknown;
1362 }
1363 return HdcpLevelTojint(connected);
1364}
1365
1366static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1367 jobject thiz) {
1368 sp<IDrm> drm = GetDrm(env, thiz);
1369
1370 if (!CheckDrm(env, drm)) {
1371 return gHdcpLevels.kHdcpLevelUnknown;
1372 }
1373
1374 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1375 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1376
1377 status_t err = drm->getHdcpLevels(&connected, &max);
1378
1379 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1380 return gHdcpLevels.kHdcpLevelUnknown;
1381 }
1382 return HdcpLevelTojint(max);
1383}
1384
1385static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1386 jobject thiz) {
1387 sp<IDrm> drm = GetDrm(env, thiz);
1388
1389 if (!CheckDrm(env, drm)) {
1390 return 0;
1391 }
1392
1393 uint32_t open = 0, max = 0;
1394 status_t err = drm->getNumberOfSessions(&open, &max);
1395
1396 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1397 return 0;
1398 }
1399 return open;
1400}
1401
1402static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1403 jobject thiz) {
1404 sp<IDrm> drm = GetDrm(env, thiz);
1405
1406 if (!CheckDrm(env, drm)) {
1407 return 0;
1408 }
1409
1410 uint32_t open = 0, max = 0;
1411 status_t err = drm->getNumberOfSessions(&open, &max);
1412
1413 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1414 return 0;
1415 }
1416 return max;
1417}
1418
1419static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1420 jobject thiz, jbyteArray jsessionId) {
1421 sp<IDrm> drm = GetDrm(env, thiz);
1422
1423 if (!CheckSession(env, drm, jsessionId)) {
1424 return gSecurityLevels.kSecurityLevelUnknown;
1425 }
1426
1427 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1428
1429 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1430
1431 status_t err = drm->getSecurityLevel(sessionId, &level);
1432
1433 if (throwExceptionAsNecessary(env, err, "Failed to get security level")) {
1434 return gSecurityLevels.kSecurityLevelUnknown;
1435 }
1436
1437 switch(level) {
1438 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1439 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1440 case DrmPlugin::kSecurityLevelSwSecureDecode:
1441 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1442 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1443 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1444 case DrmPlugin::kSecurityLevelHwSecureDecode:
1445 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1446 case DrmPlugin::kSecurityLevelHwSecureAll:
1447 return gSecurityLevels.kSecurityLevelHwSecureAll;
1448 default:
1449 return gSecurityLevels.kSecurityLevelUnknown;
1450 }
1451}
1452
Jeff Tinker55d26242018-10-10 16:10:43 -07001453static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1454 JNIEnv *env, jobject thiz) {
1455 sp<IDrm> drm = GetDrm(env, thiz);
1456
1457 if (!CheckDrm(env, drm)) {
1458 return NULL;
1459 }
1460
1461 List<Vector<uint8_t> > keySetIds;
1462
1463 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1464
1465 if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) {
1466 return NULL;
1467 }
1468
1469 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1470}
1471
1472static void android_media_MediaDrm_removeOfflineLicense(
1473 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1474 sp<IDrm> drm = GetDrm(env, thiz);
1475
1476 if (!CheckDrm(env, drm)) {
1477 return;
1478 }
1479
1480 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1481
1482 throwExceptionAsNecessary(env, err, "Failed to remove offline license");
1483}
1484
1485static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1486 jobject thiz, jbyteArray jkeySetId) {
1487 sp<IDrm> drm = GetDrm(env, thiz);
1488
1489 if (!CheckDrm(env, drm)) {
1490 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1491 }
1492
1493 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1494
1495 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1496
1497 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1498
1499 if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) {
1500 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1501 }
1502
1503 switch(state) {
1504 case DrmPlugin::kOfflineLicenseStateUsable:
1505 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
1506 case DrmPlugin::kOfflineLicenseStateInactive:
1507 return gOfflineLicenseStates.kOfflineLicenseStateInactive;
1508 default:
1509 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1510 }
1511}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001512
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001513static jstring android_media_MediaDrm_getPropertyString(
1514 JNIEnv *env, jobject thiz, jstring jname) {
1515 sp<IDrm> drm = GetDrm(env, thiz);
1516
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001517 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001518 return NULL;
1519 }
1520
1521 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001522 jniThrowException(env, "java/lang/IllegalArgumentException",
1523 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001524 return NULL;
1525 }
1526
1527 String8 name = JStringToString8(env, jname);
1528 String8 value;
1529
1530 status_t err = drm->getPropertyString(name, value);
1531
1532 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1533 return NULL;
1534 }
1535
1536 return env->NewStringUTF(value.string());
1537}
1538
1539static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1540 JNIEnv *env, jobject thiz, jstring jname) {
1541 sp<IDrm> drm = GetDrm(env, thiz);
1542
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001543 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001544 return NULL;
1545 }
1546
1547 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001548 jniThrowException(env, "java/lang/IllegalArgumentException",
1549 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001550 return NULL;
1551 }
1552
1553 String8 name = JStringToString8(env, jname);
1554 Vector<uint8_t> value;
1555
1556 status_t err = drm->getPropertyByteArray(name, value);
1557
1558 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1559 return NULL;
1560 }
1561
1562 return VectorToJByteArray(env, value);
1563}
1564
1565static void android_media_MediaDrm_setPropertyString(
1566 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1567 sp<IDrm> drm = GetDrm(env, thiz);
1568
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001569 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001570 return;
1571 }
1572
Jeff Tinkereada5372013-05-21 12:48:14 -07001573 if (jname == NULL) {
1574 jniThrowException(env, "java/lang/IllegalArgumentException",
1575 "property name String is null");
1576 return;
1577 }
1578
1579 if (jvalue == NULL) {
1580 jniThrowException(env, "java/lang/IllegalArgumentException",
1581 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001582 return;
1583 }
1584
1585 String8 name = JStringToString8(env, jname);
1586 String8 value = JStringToString8(env, jvalue);
1587
1588 status_t err = drm->setPropertyString(name, value);
1589
1590 throwExceptionAsNecessary(env, err, "Failed to set property");
1591}
1592
1593static void android_media_MediaDrm_setPropertyByteArray(
1594 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1595 sp<IDrm> drm = GetDrm(env, thiz);
1596
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001597 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001598 return;
1599 }
1600
Jeff Tinkereada5372013-05-21 12:48:14 -07001601 if (jname == NULL) {
1602 jniThrowException(env, "java/lang/IllegalArgumentException",
1603 "property name String is null");
1604 return;
1605 }
1606
1607 if (jvalue == NULL) {
1608 jniThrowException(env, "java/lang/IllegalArgumentException",
1609 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001610 return;
1611 }
1612
1613 String8 name = JStringToString8(env, jname);
1614 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1615
1616 status_t err = drm->setPropertyByteArray(name, value);
1617
1618 throwExceptionAsNecessary(env, err, "Failed to set property");
1619}
1620
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001621static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001622 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001623 jstring jalgorithm) {
1624
1625 sp<IDrm> drm = GetDrm(env, jdrm);
1626
1627 if (!CheckSession(env, drm, jsessionId)) {
1628 return;
1629 }
1630
1631 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001632 jniThrowException(env, "java/lang/IllegalArgumentException",
1633 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001634 return;
1635 }
1636
1637 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1638 String8 algorithm = JStringToString8(env, jalgorithm);
1639
1640 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1641
1642 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1643}
1644
1645static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001646 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001647 jstring jalgorithm) {
1648
1649 sp<IDrm> drm = GetDrm(env, jdrm);
1650
1651 if (!CheckSession(env, drm, jsessionId)) {
1652 return;
1653 }
1654
1655 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001656 jniThrowException(env, "java/lang/IllegalArgumentException",
1657 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001658 return;
1659 }
1660
1661 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1662 String8 algorithm = JStringToString8(env, jalgorithm);
1663
1664 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1665
1666 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1667}
1668
1669
1670static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001671 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001672 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1673
1674 sp<IDrm> drm = GetDrm(env, jdrm);
1675
1676 if (!CheckSession(env, drm, jsessionId)) {
1677 return NULL;
1678 }
1679
1680 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001681 jniThrowException(env, "java/lang/IllegalArgumentException",
1682 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001683 return NULL;
1684 }
1685
1686 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1687 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1688 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1689 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1690 Vector<uint8_t> output;
1691
1692 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1693
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001694 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1695 return NULL;
1696 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001697
1698 return VectorToJByteArray(env, output);
1699}
1700
1701static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001702 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001703 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1704
1705 sp<IDrm> drm = GetDrm(env, jdrm);
1706
1707 if (!CheckSession(env, drm, jsessionId)) {
1708 return NULL;
1709 }
1710
1711 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001712 jniThrowException(env, "java/lang/IllegalArgumentException",
1713 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001714 return NULL;
1715 }
1716
1717 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1718 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1719 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1720 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1721 Vector<uint8_t> output;
1722
1723 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001724 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1725 return NULL;
1726 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001727
1728 return VectorToJByteArray(env, output);
1729}
1730
1731static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001732 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001733 jbyteArray jkeyId, jbyteArray jmessage) {
1734
1735 sp<IDrm> drm = GetDrm(env, jdrm);
1736
1737 if (!CheckSession(env, drm, jsessionId)) {
1738 return NULL;
1739 }
1740
1741 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001742 jniThrowException(env, "java/lang/IllegalArgumentException",
1743 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001744 return NULL;
1745 }
1746
1747 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1748 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1749 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1750 Vector<uint8_t> signature;
1751
1752 status_t err = drm->sign(sessionId, keyId, message, signature);
1753
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001754 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1755 return NULL;
1756 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001757
1758 return VectorToJByteArray(env, signature);
1759}
1760
1761static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001762 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001763 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1764
1765 sp<IDrm> drm = GetDrm(env, jdrm);
1766
1767 if (!CheckSession(env, drm, jsessionId)) {
1768 return false;
1769 }
1770
1771 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001772 jniThrowException(env, "java/lang/IllegalArgumentException",
1773 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001774 return false;
1775 }
1776
1777 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1778 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1779 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1780 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1781 bool match;
1782
1783 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1784
1785 throwExceptionAsNecessary(env, err, "Failed to verify");
1786 return match;
1787}
1788
Adam Stonec06e10e2017-12-19 12:54:33 -08001789static jobject
1790android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1791{
1792 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001793
1794 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001795 return NULL;
1796 }
1797
1798 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001799 PersistableBundle metrics;
1800 status_t err = drm->getMetrics(&metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001801 if (err != OK) {
1802 ALOGE("getMetrics failed: %d", (int)err);
1803 return (jobject) NULL;
1804 }
1805
Adam Stone94395c92018-01-30 12:07:00 -08001806 return nativeToJavaPersistableBundle(env, thiz, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001807}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001808
Jeff Tinkere4095a82014-03-04 13:17:11 -08001809static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001810 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001811 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1812
1813 sp<IDrm> drm = GetDrm(env, jdrm);
1814
1815 if (!CheckSession(env, drm, jsessionId)) {
1816 return NULL;
1817 }
1818
1819 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1820 jniThrowException(env, "java/lang/IllegalArgumentException",
1821 "required argument is null");
1822 return NULL;
1823 }
1824
1825 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1826 String8 algorithm = JStringToString8(env, jalgorithm);
1827 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1828 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1829 Vector<uint8_t> signature;
1830
1831 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1832
1833 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1834 return NULL;
1835 }
1836
1837 return VectorToJByteArray(env, signature);
1838}
1839
1840
Daniel Micay76f6a862015-09-19 17:31:01 -04001841static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001842 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
1843
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001844 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1845
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001846 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001847 (void *)android_media_MediaDrm_native_setup },
1848
Jeff Tinker7cda4912013-08-21 11:52:34 -07001849 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001850 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1851
Jeff Tinker2bca5252018-02-11 18:59:14 +00001852 { "openSession", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001853 (void *)android_media_MediaDrm_openSession },
1854
1855 { "closeSession", "([B)V",
1856 (void *)android_media_MediaDrm_closeSession },
1857
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001858 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1859 "Landroid/media/MediaDrm$KeyRequest;",
1860 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001861
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001862 { "provideKeyResponse", "([B[B)[B",
1863 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001864
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001865 { "removeKeys", "([B)V",
1866 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001867
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001868 { "restoreKeys", "([B[B)V",
1869 (void *)android_media_MediaDrm_restoreKeys },
1870
1871 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1872 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001873
Jeff Tinkere4095a82014-03-04 13:17:11 -08001874 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1875 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001876
Jeff Tinkere4095a82014-03-04 13:17:11 -08001877 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1878 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001879
1880 { "getSecureStops", "()Ljava/util/List;",
1881 (void *)android_media_MediaDrm_getSecureStops },
1882
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001883 { "getSecureStopIds", "()Ljava/util/List;",
1884 (void *)android_media_MediaDrm_getSecureStopIds },
1885
Jeff Tinker1b51c722014-10-31 00:54:26 -07001886 { "getSecureStop", "([B)[B",
1887 (void *)android_media_MediaDrm_getSecureStop },
1888
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001889 { "releaseSecureStops", "([B)V",
1890 (void *)android_media_MediaDrm_releaseSecureStops },
1891
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001892 { "removeSecureStop", "([B)V",
1893 (void *)android_media_MediaDrm_removeSecureStop },
1894
1895 { "removeAllSecureStops", "()V",
1896 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07001897
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001898 { "getConnectedHdcpLevel", "()I",
1899 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
1900
1901 { "getMaxHdcpLevel", "()I",
1902 (void *)android_media_MediaDrm_getMaxHdcpLevel },
1903
1904 { "getOpenSessionCount", "()I",
1905 (void *)android_media_MediaDrm_getOpenSessionCount },
1906
1907 { "getMaxSessionCount", "()I",
1908 (void *)android_media_MediaDrm_getMaxSessionCount },
1909
1910 { "getSecurityLevel", "([B)I",
1911 (void *)android_media_MediaDrm_getSecurityLevel },
1912
Jeff Tinker55d26242018-10-10 16:10:43 -07001913 { "removeOfflineLicense", "([B)V",
1914 (void *)android_media_MediaDrm_removeOfflineLicense },
1915
1916 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
1917 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
1918
1919 { "getOfflineLicenseState", "([B)I",
1920 (void *)android_media_MediaDrm_getOfflineLicenseState },
1921
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001922 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1923 (void *)android_media_MediaDrm_getPropertyString },
1924
1925 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1926 (void *)android_media_MediaDrm_getPropertyByteArray },
1927
1928 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1929 (void *)android_media_MediaDrm_setPropertyString },
1930
1931 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1932 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001933
1934 { "setCipherAlgorithmNative",
1935 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1936 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1937
1938 { "setMacAlgorithmNative",
1939 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1940 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1941
1942 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1943 (void *)android_media_MediaDrm_encryptNative },
1944
1945 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1946 (void *)android_media_MediaDrm_decryptNative },
1947
1948 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1949 (void *)android_media_MediaDrm_signNative },
1950
1951 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1952 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08001953
1954 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1955 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08001956
1957 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
1958 (void *)android_media_MediaDrm_native_getMetrics },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001959};
1960
1961int register_android_media_Drm(JNIEnv *env) {
1962 return AndroidRuntime::registerNativeMethods(env,
1963 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1964}