blob: f412161f418a2b9d338ead514f380ac9892bcf6b [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 Tinker20594d82018-12-12 08:31:22 -0800113 jint kWhatSessionLostState;
Jeff Tinker74797f82015-03-31 15:44:34 -0700114} gEventWhat;
115
Jeff Tinker17b89222013-05-21 12:35:06 -0700116struct KeyTypes {
117 jint kKeyTypeStreaming;
118 jint kKeyTypeOffline;
119 jint kKeyTypeRelease;
120} gKeyTypes;
121
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700122struct KeyRequestTypes {
123 jint kKeyRequestTypeInitial;
124 jint kKeyRequestTypeRenewal;
125 jint kKeyRequestTypeRelease;
Rahul Frias8f761ba2018-01-22 23:43:54 -0800126 jint kKeyRequestTypeNone;
127 jint kKeyRequestTypeUpdate;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700128} gKeyRequestTypes;
129
Jeff Tinkere4095a82014-03-04 13:17:11 -0800130struct CertificateTypes {
131 jint kCertificateTypeNone;
132 jint kCertificateTypeX509;
133} gCertificateTypes;
134
135struct CertificateFields {
136 jfieldID wrappedPrivateKey;
137 jfieldID certificateData;
138};
139
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700140struct StateExceptionFields {
141 jmethodID init;
142 jclass classId;
143};
144
Jeff Tinker20594d82018-12-12 08:31:22 -0800145struct SessionExceptionFields {
146 jmethodID init;
147 jclass classId;
148 jfieldID errorCode;
149};
150
151struct SessionExceptionErrorCodes {
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800152 jint kErrorUnknown;
Jeff Tinker20594d82018-12-12 08:31:22 -0800153 jint kResourceContention;
154} gSessionExceptionErrorCodes;
155
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800156struct HDCPLevels {
157 jint kHdcpLevelUnknown;
158 jint kHdcpNone;
159 jint kHdcpV1;
160 jint kHdcpV2;
161 jint kHdcpV2_1;
162 jint kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800163 jint kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800164 jint kHdcpNoOutput;
165} gHdcpLevels;
166
167struct SecurityLevels {
168 jint kSecurityLevelUnknown;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000169 jint kSecurityLevelMax;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800170 jint kSecurityLevelSwSecureCrypto;
171 jint kSecurityLevelSwSecureDecode;
172 jint kSecurityLevelHwSecureCrypto;
173 jint kSecurityLevelHwSecureDecode;
174 jint kSecurityLevelHwSecureAll;
175} gSecurityLevels;
176
Jeff Tinker55d26242018-10-10 16:10:43 -0700177struct OfflineLicenseState {
178 jint kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800179 jint kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -0700180 jint kOfflineLicenseStateUnknown;
181} gOfflineLicenseStates;
182
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800183
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800184struct fields_t {
185 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700186 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700187 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800188 RequestFields provisionRequest;
189 ArrayListFields arraylist;
190 HashmapFields hashmap;
191 SetFields set;
192 IteratorFields iterator;
193 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800194 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700195 StateExceptionFields stateException;
Jeff Tinker20594d82018-12-12 08:31:22 -0800196 SessionExceptionFields sessionException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800197 jclass certificateClassId;
198 jclass hashmapClassId;
199 jclass arraylistClassId;
200 jclass stringClassId;
Adam Stone94395c92018-01-30 12:07:00 -0800201 jobject bundleCreator;
202 jmethodID createFromParcelId;
203 jclass parcelCreatorClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800204};
205
206static fields_t gFields;
207
Adam Stone94395c92018-01-30 12:07:00 -0800208namespace {
209
210// Helper function to convert a native PersistableBundle to a Java
211// PersistableBundle.
212jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
213 PersistableBundle* nativeBundle) {
214 if (env == NULL || thiz == NULL || nativeBundle == NULL) {
215 ALOGE("Unexpected NULL parmeter");
216 return NULL;
217 }
218
219 // Create a Java parcel with the native parcel data.
220 // Then create a new PersistableBundle with that parcel as a parameter.
221 jobject jParcel = android::createJavaParcelObject(env);
222 if (jParcel == NULL) {
223 ALOGE("Failed to create a Java Parcel.");
224 return NULL;
225 }
226
227 android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
228 if (nativeParcel == NULL) {
229 ALOGE("Failed to get the native Parcel.");
230 return NULL;
231 }
232
233 android::status_t result = nativeBundle->writeToParcel(nativeParcel);
234 nativeParcel->setDataPosition(0);
235 if (result != android::OK) {
236 ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
237 return NULL;
238 }
239
240 jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
241 gFields.createFromParcelId,
242 jParcel);
243 if (newBundle == NULL) {
244 ALOGE("Failed to create a new PersistableBundle "
245 "from the createFromParcel call.");
246 }
247
248 return newBundle;
249}
250
251} // namespace anonymous
252
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700253// ----------------------------------------------------------------------------
254// ref-counted object for callbacks
255class JNIDrmListener: public DrmListener
256{
257public:
258 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
259 ~JNIDrmListener();
260 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
261private:
262 JNIDrmListener();
263 jclass mClass; // Reference to MediaDrm class
264 jobject mObject; // Weak ref to MediaDrm Java object to call on
265};
266
267JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
268{
269 // Hold onto the MediaDrm class for use in calling the static method
270 // that posts events to the application thread.
271 jclass clazz = env->GetObjectClass(thiz);
272 if (clazz == NULL) {
273 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700274 jniThrowException(env, "java/lang/Exception",
275 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700276 return;
277 }
278 mClass = (jclass)env->NewGlobalRef(clazz);
279
280 // We use a weak reference so the MediaDrm object can be garbage collected.
281 // The reference is only used as a proxy for callbacks.
282 mObject = env->NewGlobalRef(weak_thiz);
283}
284
285JNIDrmListener::~JNIDrmListener()
286{
287 // remove global references
288 JNIEnv *env = AndroidRuntime::getJNIEnv();
289 env->DeleteGlobalRef(mObject);
290 env->DeleteGlobalRef(mClass);
291}
292
293void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
294 const Parcel *obj)
295{
Jeff Tinker74797f82015-03-31 15:44:34 -0700296 jint jwhat;
297 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700298
299 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700300 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700301 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700302 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700303 jeventType = gEventTypes.kEventProvisionRequired;
304 break;
305 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700306 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700307 jeventType = gEventTypes.kEventKeyRequired;
308 break;
309 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700310 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700311 jeventType = gEventTypes.kEventKeyExpired;
312 break;
313 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700314 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700315 jeventType = gEventTypes.kEventVendorDefined;
316 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800317 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700318 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800319 jeventType = gEventTypes.kEventSessionReclaimed;
320 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700321 case DrmPlugin::kDrmPluginEventExpirationUpdate:
322 jwhat = gEventWhat.kWhatExpirationUpdate;
323 break;
324 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700325 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700326 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800327 case DrmPlugin::kDrmPluginEventSessionLostState:
328 jwhat = gEventWhat.kWhatSessionLostState;
329 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700330 default:
331 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
332 return;
333 }
334
335 JNIEnv *env = AndroidRuntime::getJNIEnv();
336 if (obj && obj->dataSize() > 0) {
337 jobject jParcel = createJavaParcelObject(env);
338 if (jParcel != NULL) {
339 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
340 nativeParcel->setData(obj->data(), obj->dataSize());
341 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
Jeff Tinker74797f82015-03-31 15:44:34 -0700342 jwhat, jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100343 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700344 }
345 }
346
347 if (env->ExceptionCheck()) {
348 ALOGW("An exception occurred while notifying an event.");
349 LOGW_EX(env);
350 env->ExceptionClear();
351 }
352}
353
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700354static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
355 ALOGE("Illegal state exception: %s (%d)", msg, err);
356
357 jobject exception = env->NewObject(gFields.stateException.classId,
358 gFields.stateException.init, static_cast<int>(err),
359 env->NewStringUTF(msg));
360 env->Throw(static_cast<jthrowable>(exception));
361}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700362
Jeff Tinker20594d82018-12-12 08:31:22 -0800363static void throwSessionException(JNIEnv *env, const char *msg, status_t err) {
364 ALOGE("Session exception: %s (%d)", msg, err);
365
366 jint jErrorCode = 0;
367 switch(err) {
368 case ERROR_DRM_RESOURCE_CONTENTION:
369 jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
370 break;
371 default:
372 break;
373 }
374
375 jobject exception = env->NewObject(gFields.sessionException.classId,
376 gFields.sessionException.init, static_cast<int>(err),
377 env->NewStringUTF(msg));
378
379 env->SetIntField(exception, gFields.sessionException.errorCode, jErrorCode);
380 env->Throw(static_cast<jthrowable>(exception));
381}
382
383static bool isSessionException(status_t err) {
384 return err == ERROR_DRM_RESOURCE_CONTENTION;
385}
386
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800387static bool throwExceptionAsNecessary(
388 JNIEnv *env, status_t err, const char *msg = NULL) {
389
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700390 const char *drmMessage = NULL;
391
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700392 switch (err) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700393 case ERROR_DRM_UNKNOWN:
394 drmMessage = "General DRM error";
395 break;
396 case ERROR_DRM_NO_LICENSE:
397 drmMessage = "No license";
398 break;
399 case ERROR_DRM_LICENSE_EXPIRED:
400 drmMessage = "License expired";
401 break;
402 case ERROR_DRM_SESSION_NOT_OPENED:
403 drmMessage = "Session not opened";
404 break;
405 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
406 drmMessage = "Not initialized";
407 break;
408 case ERROR_DRM_DECRYPT:
409 drmMessage = "Decrypt error";
410 break;
411 case ERROR_DRM_CANNOT_HANDLE:
Jeff Tinkereb13c762017-11-01 15:29:38 -0700412 drmMessage = "Invalid parameter or data format";
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700413 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800414 case ERROR_DRM_INVALID_STATE:
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700415 drmMessage = "Invalid state";
416 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700417 default:
418 break;
419 }
420
421 String8 vendorMessage;
422 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
Jeff Tinker29799862014-08-27 11:05:13 -0700423 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700424 drmMessage = vendorMessage.string();
425 }
426
Jeff Tinkereb13c762017-11-01 15:29:38 -0700427 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800428 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
429 return true;
Jeff Tinker5de2e902019-01-25 23:09:36 -0800430 } else if (err == ERROR_UNSUPPORTED) {
431 jniThrowException(env, "java/lang/UnsupportedOperationException", msg);
432 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700433 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
434 jniThrowException(env, "android/media/NotProvisionedException", msg);
435 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700436 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
437 jniThrowException(env, "android/media/ResourceBusyException", msg);
438 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700439 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
440 jniThrowException(env, "android/media/DeniedByServerException", msg);
441 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700442 } else if (err == DEAD_OBJECT) {
443 jniThrowException(env, "android/media/MediaDrmResetException",
444 "mediaserver died");
445 return true;
Jeff Tinker20594d82018-12-12 08:31:22 -0800446 } else if (isSessionException(err)) {
447 throwSessionException(env, msg, err);
448 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800449 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700450 String8 errbuf;
451 if (drmMessage != NULL) {
452 if (msg == NULL) {
453 msg = drmMessage;
454 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700455 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700456 msg = errbuf.string();
457 }
458 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700459 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800460 return true;
461 }
462 return false;
463}
464
465static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000466 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800467 return jdrm ? jdrm->getDrm() : NULL;
468}
469
470JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800471 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
472 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800473 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800474 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700475 if (mDrm != NULL) {
476 mDrm->setListener(this);
477 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800478}
479
480JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800481 JNIEnv *env = AndroidRuntime::getJNIEnv();
482
483 env->DeleteWeakGlobalRef(mObject);
484 mObject = NULL;
485}
486
487// static
488sp<IDrm> JDrm::MakeDrm() {
489 sp<IServiceManager> sm = defaultServiceManager();
490
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700491 sp<IBinder> binder = sm->getService(String16("media.drm"));
492 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
493 if (service == NULL) {
494 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800495 }
496
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700497 sp<IDrm> drm = service->makeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800498 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
499 return NULL;
500 }
501
502 return drm;
503}
504
505// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800506sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800507 sp<IDrm> drm = MakeDrm();
508
509 if (drm == NULL) {
510 return NULL;
511 }
512
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800513 status_t err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800514
515 if (err != OK) {
516 return NULL;
517 }
518
519 return drm;
520}
521
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700522status_t JDrm::setListener(const sp<DrmListener>& listener) {
523 Mutex::Autolock lock(mLock);
524 mListener = listener;
525 return OK;
526}
527
528void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
529 sp<DrmListener> listener;
530 mLock.lock();
531 listener = mListener;
532 mLock.unlock();
533
534 if (listener != NULL) {
535 Mutex::Autolock lock(mNotifyLock);
536 listener->notify(eventType, extra, obj);
537 }
538}
539
Jeff Tinker600071c2014-04-11 16:11:15 -0700540void JDrm::disconnect() {
541 if (mDrm != NULL) {
542 mDrm->destroyPlugin();
543 mDrm.clear();
544 }
545}
546
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700547
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800548// static
Jeff Tinker5de2e902019-01-25 23:09:36 -0800549status_t JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
550 DrmPlugin::SecurityLevel securityLevel, bool *isSupported) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800551 sp<IDrm> drm = MakeDrm();
552
553 if (drm == NULL) {
Jeff Tinker5de2e902019-01-25 23:09:36 -0800554 return BAD_VALUE;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800555 }
556
Jeff Tinker5de2e902019-01-25 23:09:36 -0800557 return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel, isSupported);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800558}
559
560status_t JDrm::initCheck() const {
561 return mDrm == NULL ? NO_INIT : OK;
562}
563
564// JNI conversion utilities
565static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
566 Vector<uint8_t> vector;
567 size_t length = env->GetArrayLength(byteArray);
568 vector.insertAt((size_t)0, length);
569 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
570 return vector;
571}
572
573static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
574 size_t length = vector.size();
575 jbyteArray result = env->NewByteArray(length);
576 if (result != NULL) {
577 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
578 }
579 return result;
580}
581
582static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800583 String8 result;
584
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700585 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800586 if (s) {
587 result = s;
588 env->ReleaseStringUTFChars(jstr, s);
589 }
590 return result;
591}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700592
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800593/*
594 import java.util.HashMap;
595 import java.util.Set;
596 import java.Map.Entry;
597 import jav.util.Iterator;
598
599 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800600 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800601 Iterator i = s.iterator();
602 Entry e = s.next();
603*/
604
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200605static KeyedVector<String8, String8> HashMapToKeyedVector(
606 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800607 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800608 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200609 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800610
611 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
612 if (entrySet) {
613 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
614 if (iterator) {
615 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
616 while (hasNext) {
617 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
618 if (entry) {
619 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200620 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700621 jniThrowException(env, "java/lang/IllegalArgumentException",
622 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200623 env->DeleteLocalRef(entry);
624 *pIsOK = false;
625 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800626 }
627 jstring jkey = static_cast<jstring>(obj);
628
629 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200630 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700631 jniThrowException(env, "java/lang/IllegalArgumentException",
632 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200633 env->DeleteLocalRef(entry);
634 *pIsOK = false;
635 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800636 }
637 jstring jvalue = static_cast<jstring>(obj);
638
639 String8 key = JStringToString8(env, jkey);
640 String8 value = JStringToString8(env, jvalue);
641 keyedVector.add(key, value);
642
643 env->DeleteLocalRef(jkey);
644 env->DeleteLocalRef(jvalue);
645 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
646 }
647 env->DeleteLocalRef(entry);
648 }
649 env->DeleteLocalRef(iterator);
650 }
651 env->DeleteLocalRef(entrySet);
652 }
653 return keyedVector;
654}
655
656static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800657 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800658 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
659 for (size_t i = 0; i < map.size(); ++i) {
660 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
661 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
662 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
663 env->DeleteLocalRef(jkey);
664 env->DeleteLocalRef(jvalue);
665 }
666 return hashMap;
667}
668
669static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800670 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800671 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800672 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800673 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800674 while (iter != list.end()) {
675 jbyteArray byteArray = VectorToJByteArray(env, *iter);
676 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
677 env->DeleteLocalRef(byteArray);
678 iter++;
679 }
680
681 return arrayList;
682}
683
684} // namespace android
685
686using namespace android;
687
688static sp<JDrm> setDrm(
689 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000690 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800691 if (drm != NULL) {
692 drm->incStrong(thiz);
693 }
694 if (old != NULL) {
695 old->decStrong(thiz);
696 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000697 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800698
699 return old;
700}
701
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800702static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800703 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700704 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800705 return false;
706 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800707 return true;
708}
709
710static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
711{
712 if (!CheckDrm(env, drm)) {
713 return false;
714 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800715
716 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700717 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800718 return false;
719 }
720 return true;
721}
722
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800723static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700724 sp<JDrm> drm = setDrm(env, thiz, NULL);
725 if (drm != NULL) {
726 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700727 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700728 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800729}
730
731static void android_media_MediaDrm_native_init(JNIEnv *env) {
732 jclass clazz;
733 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000734 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700735 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700736 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700737
738 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700739 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700740 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700741 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700742 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700743 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700744 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700745 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700746 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800747 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
748 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800749
Jeff Tinker74797f82015-03-31 15:44:34 -0700750 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
751 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
752 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
753 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700754 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
755 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800756 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
757 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700758
Jeff Tinker17b89222013-05-21 12:35:06 -0700759 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
760 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
761 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
762 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
763 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
764 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
765
Jeff Tinkere4095a82014-03-04 13:17:11 -0800766 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
767 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
768 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
769 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
770
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800771 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
772 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
773 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
774 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
775 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
776 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
777 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
778 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
779 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
780 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
781 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
782 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800783 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
784 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800785 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
786 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
787
788 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
789 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700790 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800791 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700792 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800793 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700794 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800795 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700796 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800797 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700798 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800799 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
800
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800801 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_USABLE", "I");
Jeff Tinker55d26242018-10-10 16:10:43 -0700802 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800803 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_RELEASED", "I");
804 gOfflineLicenseStates.kOfflineLicenseStateReleased = env->GetStaticIntField(clazz, field);
Jeff Tinker55d26242018-10-10 16:10:43 -0700805 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
806 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
807
808 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
809
Jeff Tinker2bca5252018-02-11 18:59:14 +0000810 jmethodID getMaxSecurityLevel;
811 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
812 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
813
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700814 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700815 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
816 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700817 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800818
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700819 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
820 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
821 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
822 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
823 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
824 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800825 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
826 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
827 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
828 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700829
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800830 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700831 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
832 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800833
Jeff Tinkere4095a82014-03-04 13:17:11 -0800834 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
835 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
836 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700837 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800838
Adam Stone94395c92018-01-30 12:07:00 -0800839 // Metrics-related fields and classes.
840 FIND_CLASS(clazz, "android/os/PersistableBundle");
841 jfieldID bundleCreatorId;
842 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
843 "Landroid/os/Parcelable$Creator;");
844 jobject bundleCreator;
845 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
846 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
847 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
848 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
849 "(Landroid/os/Parcel;)Ljava/lang/Object;");
850 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
851
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800852 FIND_CLASS(clazz, "java/util/ArrayList");
853 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
854 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
855
856 FIND_CLASS(clazz, "java/util/HashMap");
857 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
858 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
859 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
860 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
861 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
862
863 FIND_CLASS(clazz, "java/util/Set");
864 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
865
866 FIND_CLASS(clazz, "java/util/Iterator");
867 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
868 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
869
870 FIND_CLASS(clazz, "java/util/Map$Entry");
871 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
872 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800873
874 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700875 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800876
877 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700878 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800879
880 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700881 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700882
883 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
884 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
885 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800886
887 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
888 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
889 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
890 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
891
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800892 GET_STATIC_FIELD_ID(field, clazz, "ERROR_UNKNOWN", "I");
893 gSessionExceptionErrorCodes.kErrorUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800894 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
895 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800896}
897
898static void android_media_MediaDrm_native_setup(
899 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800900 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800901
902 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700903 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800904 return;
905 }
906
907 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
908
909 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700910 jniThrowException(env, "java/lang/IllegalArgumentException",
911 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800912 return;
913 }
914
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800915 String8 packageName;
916 if (jappPackageName == NULL) {
917 jniThrowException(env, "java/lang/IllegalArgumentException",
918 "application package name cannot be null");
919 return;
920 }
921
922 packageName = JStringToString8(env, jappPackageName);
923 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800924
925 status_t err = drm->initCheck();
926
927 if (err != OK) {
928 jniThrowException(
929 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700930 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800931 "Failed to instantiate drm object.");
932 return;
933 }
934
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700935 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
936 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800937 setDrm(env, thiz, drm);
938}
939
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800940DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
941 DrmPlugin::SecurityLevel level;
942
943 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
944 level = DrmPlugin::kSecurityLevelMax;
945 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
946 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
947 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
948 level = DrmPlugin::kSecurityLevelSwSecureDecode;
949 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
950 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
951 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
952 level = DrmPlugin::kSecurityLevelHwSecureDecode;
953 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
954 level = DrmPlugin::kSecurityLevelHwSecureAll;
955 } else {
956 level = DrmPlugin::kSecurityLevelUnknown;
957 }
958 return level;
959}
960
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800961static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800962 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
963 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800964
965 if (uuidObj == NULL) {
966 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
967 return false;
968 }
969
970 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
971
972 if (uuid.size() != 16) {
973 jniThrowException(
974 env,
975 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700976 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800977 return false;
978 }
979
Jeff Tinker7cda4912013-08-21 11:52:34 -0700980 String8 mimeType;
981 if (jmimeType != NULL) {
982 mimeType = JStringToString8(env, jmimeType);
983 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800984 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -0700985
Jeff Tinker5de2e902019-01-25 23:09:36 -0800986 bool isSupported;
987 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
988 securityLevel, &isSupported);
989
990 if (throwExceptionAsNecessary(env, err, "Failed to query crypto scheme support")) {
991 return false;
992 }
993 return isSupported;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800994}
995
996static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +0000997 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800998 sp<IDrm> drm = GetDrm(env, thiz);
999
Jeff Tinker55d26242018-10-10 16:10:43 -07001000 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001001 return NULL;
1002 }
1003
1004 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001005 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1006 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +00001007 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1008 return NULL;
1009 }
1010
1011 status_t err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001012
1013 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
1014 return NULL;
1015 }
1016
1017 return VectorToJByteArray(env, sessionId);
1018}
1019
1020static void android_media_MediaDrm_closeSession(
1021 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1022 sp<IDrm> drm = GetDrm(env, thiz);
1023
1024 if (!CheckSession(env, drm, jsessionId)) {
1025 return;
1026 }
1027
1028 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1029
1030 status_t err = drm->closeSession(sessionId);
1031
1032 throwExceptionAsNecessary(env, err, "Failed to close session");
1033}
1034
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001035static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001036 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001037 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001038 sp<IDrm> drm = GetDrm(env, thiz);
1039
1040 if (!CheckSession(env, drm, jsessionId)) {
1041 return NULL;
1042 }
1043
1044 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1045
1046 Vector<uint8_t> initData;
1047 if (jinitData != NULL) {
1048 initData = JByteArrayToVector(env, jinitData);
1049 }
1050
1051 String8 mimeType;
1052 if (jmimeType != NULL) {
1053 mimeType = JStringToString8(env, jmimeType);
1054 }
1055
Jeff Tinker17b89222013-05-21 12:35:06 -07001056 DrmPlugin::KeyType keyType;
1057 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1058 keyType = DrmPlugin::kKeyType_Streaming;
1059 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1060 keyType = DrmPlugin::kKeyType_Offline;
1061 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1062 keyType = DrmPlugin::kKeyType_Release;
1063 } else {
1064 jniThrowException(env, "java/lang/IllegalArgumentException",
1065 "invalid keyType");
1066 return NULL;
1067 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001068
1069 KeyedVector<String8, String8> optParams;
1070 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001071 bool isOK;
1072 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1073 if (!isOK) {
1074 return NULL;
1075 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001076 }
1077
1078 Vector<uint8_t> request;
1079 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001080 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001081
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001082 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001083 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001084
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001085 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001086 return NULL;
1087 }
1088
1089 // Fill out return obj
1090 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001091 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001092
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001093 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001094
1095 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001096 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001097 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001098 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001099
1100 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001101 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001102
1103 switch (keyRequestType) {
1104 case DrmPlugin::kKeyRequestType_Initial:
1105 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1106 gKeyRequestTypes.kKeyRequestTypeInitial);
1107 break;
1108 case DrmPlugin::kKeyRequestType_Renewal:
1109 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1110 gKeyRequestTypes.kKeyRequestTypeRenewal);
1111 break;
1112 case DrmPlugin::kKeyRequestType_Release:
1113 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1114 gKeyRequestTypes.kKeyRequestTypeRelease);
1115 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001116 case DrmPlugin::kKeyRequestType_None:
1117 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1118 gKeyRequestTypes.kKeyRequestTypeNone);
1119 break;
1120 case DrmPlugin::kKeyRequestType_Update:
1121 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1122 gKeyRequestTypes.kKeyRequestTypeUpdate);
1123 break;
1124
Jeff Tinker74797f82015-03-31 15:44:34 -07001125 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001126 throwStateException(env, "DRM plugin failure: unknown key request type",
1127 ERROR_DRM_UNKNOWN);
1128 break;
1129 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001130 }
1131
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001132 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001133}
1134
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001135static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001136 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1137 sp<IDrm> drm = GetDrm(env, thiz);
1138
1139 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001140 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001141 }
1142
1143 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1144
1145 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001146 jniThrowException(env, "java/lang/IllegalArgumentException",
1147 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001148 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001149 }
1150 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001151 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001152
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001153 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001154
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001155 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
1156 return NULL;
1157 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001158 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001159}
1160
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001161static void android_media_MediaDrm_removeKeys(
1162 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1163 sp<IDrm> drm = GetDrm(env, thiz);
1164
Jeff Tinker55d26242018-10-10 16:10:43 -07001165 if (!CheckDrm(env, drm)) {
1166 return;
1167 }
1168
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001169 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001170 jniThrowException(env, "java/lang/IllegalArgumentException",
1171 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001172 return;
1173 }
1174
1175 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1176
1177 status_t err = drm->removeKeys(keySetId);
1178
1179 throwExceptionAsNecessary(env, err, "Failed to remove keys");
1180}
1181
1182static void android_media_MediaDrm_restoreKeys(
1183 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1184 jbyteArray jkeysetId) {
1185
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001186 sp<IDrm> drm = GetDrm(env, thiz);
1187
1188 if (!CheckSession(env, drm, jsessionId)) {
1189 return;
1190 }
1191
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001192 if (jkeysetId == NULL) {
1193 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1194 return;
1195 }
1196
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001197 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001198 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001199
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001200 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001201
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001202 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001203}
1204
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001205static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001206 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1207 sp<IDrm> drm = GetDrm(env, thiz);
1208
1209 if (!CheckSession(env, drm, jsessionId)) {
1210 return NULL;
1211 }
1212 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1213
1214 KeyedVector<String8, String8> infoMap;
1215
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001216 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001217
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001218 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001219 return NULL;
1220 }
1221
1222 return KeyedVectorToHashMap(env, infoMap);
1223}
1224
Jeff Tinkere4095a82014-03-04 13:17:11 -08001225static jobject android_media_MediaDrm_getProvisionRequestNative(
1226 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001227 sp<IDrm> drm = GetDrm(env, thiz);
1228
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001229 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001230 return NULL;
1231 }
1232
1233 Vector<uint8_t> request;
1234 String8 defaultUrl;
1235
Jeff Tinkere4095a82014-03-04 13:17:11 -08001236 String8 certType;
1237 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1238 certType = "X.509";
1239 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1240 certType = "none";
1241 } else {
1242 certType = "invalid";
1243 }
1244
1245 String8 certAuthority = JStringToString8(env, jcertAuthority);
1246 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001247
1248 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
1249 return NULL;
1250 }
1251
1252 // Fill out return obj
1253 jclass clazz;
1254 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1255
1256 jobject provisionObj = NULL;
1257
1258 if (clazz) {
1259 provisionObj = env->AllocObject(clazz);
1260 jbyteArray jrequest = VectorToJByteArray(env, request);
1261 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1262
1263 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1264 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1265 }
1266
1267 return provisionObj;
1268}
1269
Jeff Tinkere4095a82014-03-04 13:17:11 -08001270static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001271 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1272 sp<IDrm> drm = GetDrm(env, thiz);
1273
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001274 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001275 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001276 }
1277
1278 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001279 jniThrowException(env, "java/lang/IllegalArgumentException",
1280 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001281 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001282 }
1283
1284 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001285 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001286
Jeff Tinkere4095a82014-03-04 13:17:11 -08001287 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1288
1289 // Fill out return obj
1290 jclass clazz = gFields.certificateClassId;
1291
1292 jobject certificateObj = NULL;
1293
1294 if (clazz && certificate.size() && wrappedKey.size()) {
1295 certificateObj = env->AllocObject(clazz);
1296 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1297 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1298
1299 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1300 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1301 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001302
1303 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001304 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001305}
1306
1307static jobject android_media_MediaDrm_getSecureStops(
1308 JNIEnv *env, jobject thiz) {
1309 sp<IDrm> drm = GetDrm(env, thiz);
1310
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001311 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001312 return NULL;
1313 }
1314
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001315 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001316
1317 status_t err = drm->getSecureStops(secureStops);
1318
1319 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1320 return NULL;
1321 }
1322
1323 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1324}
1325
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001326static jobject android_media_MediaDrm_getSecureStopIds(
1327 JNIEnv *env, jobject thiz) {
1328 sp<IDrm> drm = GetDrm(env, thiz);
1329
Jeff Tinker55d26242018-10-10 16:10:43 -07001330 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001331 return NULL;
1332 }
1333
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001334 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001335
1336 status_t err = drm->getSecureStopIds(secureStopIds);
1337
1338 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop Ids")) {
1339 return NULL;
1340 }
1341
1342 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1343}
1344
Jeff Tinker1b51c722014-10-31 00:54:26 -07001345static jbyteArray android_media_MediaDrm_getSecureStop(
1346 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1347 sp<IDrm> drm = GetDrm(env, thiz);
1348
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001349 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001350 return NULL;
1351 }
1352
1353 Vector<uint8_t> secureStop;
1354
1355 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1356
1357 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1358 return NULL;
1359 }
1360
1361 return VectorToJByteArray(env, secureStop);
1362}
1363
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001364static void android_media_MediaDrm_releaseSecureStops(
1365 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1366 sp<IDrm> drm = GetDrm(env, thiz);
1367
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001368 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001369 return;
1370 }
1371
1372 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1373
1374 status_t err = drm->releaseSecureStops(ssRelease);
1375
1376 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1377}
1378
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001379static void android_media_MediaDrm_removeSecureStop(
1380 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1381 sp<IDrm> drm = GetDrm(env, thiz);
1382
Jeff Tinker55d26242018-10-10 16:10:43 -07001383 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001384 return;
1385 }
1386
1387 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1388
1389 throwExceptionAsNecessary(env, err, "Failed to remove secure stop");
1390}
1391
1392static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001393 JNIEnv *env, jobject thiz) {
1394 sp<IDrm> drm = GetDrm(env, thiz);
1395
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001396 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001397 return;
1398 }
1399
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001400 status_t err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001401
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001402 throwExceptionAsNecessary(env, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001403}
1404
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001405
1406static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1407 switch(level) {
1408 case DrmPlugin::kHdcpLevelUnknown:
1409 return gHdcpLevels.kHdcpLevelUnknown;
1410 case DrmPlugin::kHdcpNone:
1411 return gHdcpLevels.kHdcpNone;
1412 case DrmPlugin::kHdcpV1:
1413 return gHdcpLevels.kHdcpV1;
1414 case DrmPlugin::kHdcpV2:
1415 return gHdcpLevels.kHdcpV2;
1416 case DrmPlugin::kHdcpV2_1:
1417 return gHdcpLevels.kHdcpV2_1;
1418 case DrmPlugin::kHdcpV2_2:
1419 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001420 case DrmPlugin::kHdcpV2_3:
1421 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001422 case DrmPlugin::kHdcpNoOutput:
1423 return gHdcpLevels.kHdcpNoOutput;
1424 }
1425 return gHdcpLevels.kHdcpNone;
1426}
1427
1428static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1429 jobject thiz) {
1430 sp<IDrm> drm = GetDrm(env, thiz);
1431
1432 if (!CheckDrm(env, drm)) {
1433 return gHdcpLevels.kHdcpNone;
1434 }
1435
1436 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1437 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1438
1439 status_t err = drm->getHdcpLevels(&connected, &max);
1440
1441 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1442 return gHdcpLevels.kHdcpLevelUnknown;
1443 }
1444 return HdcpLevelTojint(connected);
1445}
1446
1447static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1448 jobject thiz) {
1449 sp<IDrm> drm = GetDrm(env, thiz);
1450
1451 if (!CheckDrm(env, drm)) {
1452 return gHdcpLevels.kHdcpLevelUnknown;
1453 }
1454
1455 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1456 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1457
1458 status_t err = drm->getHdcpLevels(&connected, &max);
1459
1460 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1461 return gHdcpLevels.kHdcpLevelUnknown;
1462 }
1463 return HdcpLevelTojint(max);
1464}
1465
1466static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1467 jobject thiz) {
1468 sp<IDrm> drm = GetDrm(env, thiz);
1469
1470 if (!CheckDrm(env, drm)) {
1471 return 0;
1472 }
1473
1474 uint32_t open = 0, max = 0;
1475 status_t err = drm->getNumberOfSessions(&open, &max);
1476
1477 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1478 return 0;
1479 }
1480 return open;
1481}
1482
1483static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1484 jobject thiz) {
1485 sp<IDrm> drm = GetDrm(env, thiz);
1486
1487 if (!CheckDrm(env, drm)) {
1488 return 0;
1489 }
1490
1491 uint32_t open = 0, max = 0;
1492 status_t err = drm->getNumberOfSessions(&open, &max);
1493
1494 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1495 return 0;
1496 }
1497 return max;
1498}
1499
1500static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1501 jobject thiz, jbyteArray jsessionId) {
1502 sp<IDrm> drm = GetDrm(env, thiz);
1503
1504 if (!CheckSession(env, drm, jsessionId)) {
1505 return gSecurityLevels.kSecurityLevelUnknown;
1506 }
1507
1508 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1509
1510 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1511
1512 status_t err = drm->getSecurityLevel(sessionId, &level);
1513
1514 if (throwExceptionAsNecessary(env, err, "Failed to get security level")) {
1515 return gSecurityLevels.kSecurityLevelUnknown;
1516 }
1517
1518 switch(level) {
1519 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1520 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1521 case DrmPlugin::kSecurityLevelSwSecureDecode:
1522 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1523 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1524 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1525 case DrmPlugin::kSecurityLevelHwSecureDecode:
1526 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1527 case DrmPlugin::kSecurityLevelHwSecureAll:
1528 return gSecurityLevels.kSecurityLevelHwSecureAll;
1529 default:
1530 return gSecurityLevels.kSecurityLevelUnknown;
1531 }
1532}
1533
Jeff Tinker55d26242018-10-10 16:10:43 -07001534static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1535 JNIEnv *env, jobject thiz) {
1536 sp<IDrm> drm = GetDrm(env, thiz);
1537
1538 if (!CheckDrm(env, drm)) {
1539 return NULL;
1540 }
1541
1542 List<Vector<uint8_t> > keySetIds;
1543
1544 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1545
1546 if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) {
1547 return NULL;
1548 }
1549
1550 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1551}
1552
1553static void android_media_MediaDrm_removeOfflineLicense(
1554 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1555 sp<IDrm> drm = GetDrm(env, thiz);
1556
1557 if (!CheckDrm(env, drm)) {
1558 return;
1559 }
1560
1561 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1562
1563 throwExceptionAsNecessary(env, err, "Failed to remove offline license");
1564}
1565
1566static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1567 jobject thiz, jbyteArray jkeySetId) {
1568 sp<IDrm> drm = GetDrm(env, thiz);
1569
1570 if (!CheckDrm(env, drm)) {
1571 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1572 }
1573
1574 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1575
1576 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1577
1578 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1579
1580 if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) {
1581 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1582 }
1583
1584 switch(state) {
1585 case DrmPlugin::kOfflineLicenseStateUsable:
1586 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -08001587 case DrmPlugin::kOfflineLicenseStateReleased:
1588 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -07001589 default:
1590 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1591 }
1592}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001593
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001594static jstring android_media_MediaDrm_getPropertyString(
1595 JNIEnv *env, jobject thiz, jstring jname) {
1596 sp<IDrm> drm = GetDrm(env, thiz);
1597
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001598 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001599 return NULL;
1600 }
1601
1602 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001603 jniThrowException(env, "java/lang/IllegalArgumentException",
1604 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001605 return NULL;
1606 }
1607
1608 String8 name = JStringToString8(env, jname);
1609 String8 value;
1610
1611 status_t err = drm->getPropertyString(name, value);
1612
1613 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1614 return NULL;
1615 }
1616
1617 return env->NewStringUTF(value.string());
1618}
1619
1620static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1621 JNIEnv *env, jobject thiz, jstring jname) {
1622 sp<IDrm> drm = GetDrm(env, thiz);
1623
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001624 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001625 return NULL;
1626 }
1627
1628 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001629 jniThrowException(env, "java/lang/IllegalArgumentException",
1630 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001631 return NULL;
1632 }
1633
1634 String8 name = JStringToString8(env, jname);
1635 Vector<uint8_t> value;
1636
1637 status_t err = drm->getPropertyByteArray(name, value);
1638
1639 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1640 return NULL;
1641 }
1642
1643 return VectorToJByteArray(env, value);
1644}
1645
1646static void android_media_MediaDrm_setPropertyString(
1647 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1648 sp<IDrm> drm = GetDrm(env, thiz);
1649
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001650 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001651 return;
1652 }
1653
Jeff Tinkereada5372013-05-21 12:48:14 -07001654 if (jname == NULL) {
1655 jniThrowException(env, "java/lang/IllegalArgumentException",
1656 "property name String is null");
1657 return;
1658 }
1659
1660 if (jvalue == NULL) {
1661 jniThrowException(env, "java/lang/IllegalArgumentException",
1662 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001663 return;
1664 }
1665
1666 String8 name = JStringToString8(env, jname);
1667 String8 value = JStringToString8(env, jvalue);
1668
1669 status_t err = drm->setPropertyString(name, value);
1670
1671 throwExceptionAsNecessary(env, err, "Failed to set property");
1672}
1673
1674static void android_media_MediaDrm_setPropertyByteArray(
1675 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1676 sp<IDrm> drm = GetDrm(env, thiz);
1677
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001678 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001679 return;
1680 }
1681
Jeff Tinkereada5372013-05-21 12:48:14 -07001682 if (jname == NULL) {
1683 jniThrowException(env, "java/lang/IllegalArgumentException",
1684 "property name String is null");
1685 return;
1686 }
1687
1688 if (jvalue == NULL) {
1689 jniThrowException(env, "java/lang/IllegalArgumentException",
1690 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001691 return;
1692 }
1693
1694 String8 name = JStringToString8(env, jname);
1695 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1696
1697 status_t err = drm->setPropertyByteArray(name, value);
1698
1699 throwExceptionAsNecessary(env, err, "Failed to set property");
1700}
1701
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001702static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001703 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001704 jstring jalgorithm) {
1705
1706 sp<IDrm> drm = GetDrm(env, jdrm);
1707
1708 if (!CheckSession(env, drm, jsessionId)) {
1709 return;
1710 }
1711
1712 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001713 jniThrowException(env, "java/lang/IllegalArgumentException",
1714 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001715 return;
1716 }
1717
1718 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1719 String8 algorithm = JStringToString8(env, jalgorithm);
1720
1721 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1722
1723 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1724}
1725
1726static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001727 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001728 jstring jalgorithm) {
1729
1730 sp<IDrm> drm = GetDrm(env, jdrm);
1731
1732 if (!CheckSession(env, drm, jsessionId)) {
1733 return;
1734 }
1735
1736 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001737 jniThrowException(env, "java/lang/IllegalArgumentException",
1738 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001739 return;
1740 }
1741
1742 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1743 String8 algorithm = JStringToString8(env, jalgorithm);
1744
1745 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1746
1747 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1748}
1749
1750
1751static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001752 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001753 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1754
1755 sp<IDrm> drm = GetDrm(env, jdrm);
1756
1757 if (!CheckSession(env, drm, jsessionId)) {
1758 return NULL;
1759 }
1760
1761 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001762 jniThrowException(env, "java/lang/IllegalArgumentException",
1763 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001764 return NULL;
1765 }
1766
1767 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1768 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1769 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1770 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1771 Vector<uint8_t> output;
1772
1773 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1774
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001775 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1776 return NULL;
1777 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001778
1779 return VectorToJByteArray(env, output);
1780}
1781
1782static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001783 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001784 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1785
1786 sp<IDrm> drm = GetDrm(env, jdrm);
1787
1788 if (!CheckSession(env, drm, jsessionId)) {
1789 return NULL;
1790 }
1791
1792 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001793 jniThrowException(env, "java/lang/IllegalArgumentException",
1794 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001795 return NULL;
1796 }
1797
1798 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1799 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1800 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1801 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1802 Vector<uint8_t> output;
1803
1804 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001805 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1806 return NULL;
1807 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001808
1809 return VectorToJByteArray(env, output);
1810}
1811
1812static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001813 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001814 jbyteArray jkeyId, jbyteArray jmessage) {
1815
1816 sp<IDrm> drm = GetDrm(env, jdrm);
1817
1818 if (!CheckSession(env, drm, jsessionId)) {
1819 return NULL;
1820 }
1821
1822 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001823 jniThrowException(env, "java/lang/IllegalArgumentException",
1824 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001825 return NULL;
1826 }
1827
1828 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1829 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1830 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1831 Vector<uint8_t> signature;
1832
1833 status_t err = drm->sign(sessionId, keyId, message, signature);
1834
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001835 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1836 return NULL;
1837 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001838
1839 return VectorToJByteArray(env, signature);
1840}
1841
1842static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001843 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001844 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1845
1846 sp<IDrm> drm = GetDrm(env, jdrm);
1847
1848 if (!CheckSession(env, drm, jsessionId)) {
1849 return false;
1850 }
1851
1852 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001853 jniThrowException(env, "java/lang/IllegalArgumentException",
1854 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001855 return false;
1856 }
1857
1858 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1859 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1860 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1861 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1862 bool match;
1863
1864 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1865
1866 throwExceptionAsNecessary(env, err, "Failed to verify");
1867 return match;
1868}
1869
Adam Stonec06e10e2017-12-19 12:54:33 -08001870static jobject
1871android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1872{
1873 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001874
1875 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001876 return NULL;
1877 }
1878
1879 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001880 PersistableBundle metrics;
1881 status_t err = drm->getMetrics(&metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001882 if (err != OK) {
1883 ALOGE("getMetrics failed: %d", (int)err);
1884 return (jobject) NULL;
1885 }
1886
Adam Stone94395c92018-01-30 12:07:00 -08001887 return nativeToJavaPersistableBundle(env, thiz, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001888}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001889
Jeff Tinkere4095a82014-03-04 13:17:11 -08001890static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001891 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001892 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1893
1894 sp<IDrm> drm = GetDrm(env, jdrm);
1895
1896 if (!CheckSession(env, drm, jsessionId)) {
1897 return NULL;
1898 }
1899
1900 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1901 jniThrowException(env, "java/lang/IllegalArgumentException",
1902 "required argument is null");
1903 return NULL;
1904 }
1905
1906 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1907 String8 algorithm = JStringToString8(env, jalgorithm);
1908 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1909 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1910 Vector<uint8_t> signature;
1911
1912 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1913
1914 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1915 return NULL;
1916 }
1917
1918 return VectorToJByteArray(env, signature);
1919}
1920
1921
Daniel Micay76f6a862015-09-19 17:31:01 -04001922static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001923 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
1924
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001925 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1926
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001927 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001928 (void *)android_media_MediaDrm_native_setup },
1929
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001930 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001931 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1932
Jeff Tinker2bca5252018-02-11 18:59:14 +00001933 { "openSession", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001934 (void *)android_media_MediaDrm_openSession },
1935
1936 { "closeSession", "([B)V",
1937 (void *)android_media_MediaDrm_closeSession },
1938
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001939 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1940 "Landroid/media/MediaDrm$KeyRequest;",
1941 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001942
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001943 { "provideKeyResponse", "([B[B)[B",
1944 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001945
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001946 { "removeKeys", "([B)V",
1947 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001948
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001949 { "restoreKeys", "([B[B)V",
1950 (void *)android_media_MediaDrm_restoreKeys },
1951
1952 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1953 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001954
Jeff Tinkere4095a82014-03-04 13:17:11 -08001955 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1956 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001957
Jeff Tinkere4095a82014-03-04 13:17:11 -08001958 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1959 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001960
1961 { "getSecureStops", "()Ljava/util/List;",
1962 (void *)android_media_MediaDrm_getSecureStops },
1963
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001964 { "getSecureStopIds", "()Ljava/util/List;",
1965 (void *)android_media_MediaDrm_getSecureStopIds },
1966
Jeff Tinker1b51c722014-10-31 00:54:26 -07001967 { "getSecureStop", "([B)[B",
1968 (void *)android_media_MediaDrm_getSecureStop },
1969
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001970 { "releaseSecureStops", "([B)V",
1971 (void *)android_media_MediaDrm_releaseSecureStops },
1972
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001973 { "removeSecureStop", "([B)V",
1974 (void *)android_media_MediaDrm_removeSecureStop },
1975
1976 { "removeAllSecureStops", "()V",
1977 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07001978
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001979 { "getConnectedHdcpLevel", "()I",
1980 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
1981
1982 { "getMaxHdcpLevel", "()I",
1983 (void *)android_media_MediaDrm_getMaxHdcpLevel },
1984
1985 { "getOpenSessionCount", "()I",
1986 (void *)android_media_MediaDrm_getOpenSessionCount },
1987
1988 { "getMaxSessionCount", "()I",
1989 (void *)android_media_MediaDrm_getMaxSessionCount },
1990
1991 { "getSecurityLevel", "([B)I",
1992 (void *)android_media_MediaDrm_getSecurityLevel },
1993
Jeff Tinker55d26242018-10-10 16:10:43 -07001994 { "removeOfflineLicense", "([B)V",
1995 (void *)android_media_MediaDrm_removeOfflineLicense },
1996
1997 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
1998 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
1999
2000 { "getOfflineLicenseState", "([B)I",
2001 (void *)android_media_MediaDrm_getOfflineLicenseState },
2002
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002003 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2004 (void *)android_media_MediaDrm_getPropertyString },
2005
2006 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2007 (void *)android_media_MediaDrm_getPropertyByteArray },
2008
2009 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2010 (void *)android_media_MediaDrm_setPropertyString },
2011
2012 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2013 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002014
2015 { "setCipherAlgorithmNative",
2016 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2017 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2018
2019 { "setMacAlgorithmNative",
2020 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2021 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2022
2023 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2024 (void *)android_media_MediaDrm_encryptNative },
2025
2026 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2027 (void *)android_media_MediaDrm_decryptNative },
2028
2029 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2030 (void *)android_media_MediaDrm_signNative },
2031
2032 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2033 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002034
2035 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2036 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002037
2038 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2039 (void *)android_media_MediaDrm_native_getMetrics },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002040};
2041
2042int register_android_media_Drm(JNIEnv *env) {
2043 return AndroidRuntime::registerNativeMethods(env,
2044 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2045}