blob: 83364590039de2c1a8ffd62252dddb2bbe1b74c1 [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 {
152 jint kResourceContention;
153} gSessionExceptionErrorCodes;
154
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800155struct HDCPLevels {
156 jint kHdcpLevelUnknown;
157 jint kHdcpNone;
158 jint kHdcpV1;
159 jint kHdcpV2;
160 jint kHdcpV2_1;
161 jint kHdcpV2_2;
162 jint kHdcpNoOutput;
163} gHdcpLevels;
164
165struct SecurityLevels {
166 jint kSecurityLevelUnknown;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000167 jint kSecurityLevelMax;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800168 jint kSecurityLevelSwSecureCrypto;
169 jint kSecurityLevelSwSecureDecode;
170 jint kSecurityLevelHwSecureCrypto;
171 jint kSecurityLevelHwSecureDecode;
172 jint kSecurityLevelHwSecureAll;
173} gSecurityLevels;
174
Jeff Tinker55d26242018-10-10 16:10:43 -0700175struct OfflineLicenseState {
176 jint kOfflineLicenseStateUsable;
177 jint kOfflineLicenseStateInactive;
178 jint kOfflineLicenseStateUnknown;
179} gOfflineLicenseStates;
180
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800181
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800182struct fields_t {
183 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700184 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700185 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800186 RequestFields provisionRequest;
187 ArrayListFields arraylist;
188 HashmapFields hashmap;
189 SetFields set;
190 IteratorFields iterator;
191 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800192 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700193 StateExceptionFields stateException;
Jeff Tinker20594d82018-12-12 08:31:22 -0800194 SessionExceptionFields sessionException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800195 jclass certificateClassId;
196 jclass hashmapClassId;
197 jclass arraylistClassId;
198 jclass stringClassId;
Adam Stone94395c92018-01-30 12:07:00 -0800199 jobject bundleCreator;
200 jmethodID createFromParcelId;
201 jclass parcelCreatorClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800202};
203
204static fields_t gFields;
205
Adam Stone94395c92018-01-30 12:07:00 -0800206namespace {
207
208// Helper function to convert a native PersistableBundle to a Java
209// PersistableBundle.
210jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
211 PersistableBundle* nativeBundle) {
212 if (env == NULL || thiz == NULL || nativeBundle == NULL) {
213 ALOGE("Unexpected NULL parmeter");
214 return NULL;
215 }
216
217 // Create a Java parcel with the native parcel data.
218 // Then create a new PersistableBundle with that parcel as a parameter.
219 jobject jParcel = android::createJavaParcelObject(env);
220 if (jParcel == NULL) {
221 ALOGE("Failed to create a Java Parcel.");
222 return NULL;
223 }
224
225 android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
226 if (nativeParcel == NULL) {
227 ALOGE("Failed to get the native Parcel.");
228 return NULL;
229 }
230
231 android::status_t result = nativeBundle->writeToParcel(nativeParcel);
232 nativeParcel->setDataPosition(0);
233 if (result != android::OK) {
234 ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
235 return NULL;
236 }
237
238 jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
239 gFields.createFromParcelId,
240 jParcel);
241 if (newBundle == NULL) {
242 ALOGE("Failed to create a new PersistableBundle "
243 "from the createFromParcel call.");
244 }
245
246 return newBundle;
247}
248
249} // namespace anonymous
250
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700251// ----------------------------------------------------------------------------
252// ref-counted object for callbacks
253class JNIDrmListener: public DrmListener
254{
255public:
256 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
257 ~JNIDrmListener();
258 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
259private:
260 JNIDrmListener();
261 jclass mClass; // Reference to MediaDrm class
262 jobject mObject; // Weak ref to MediaDrm Java object to call on
263};
264
265JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
266{
267 // Hold onto the MediaDrm class for use in calling the static method
268 // that posts events to the application thread.
269 jclass clazz = env->GetObjectClass(thiz);
270 if (clazz == NULL) {
271 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700272 jniThrowException(env, "java/lang/Exception",
273 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700274 return;
275 }
276 mClass = (jclass)env->NewGlobalRef(clazz);
277
278 // We use a weak reference so the MediaDrm object can be garbage collected.
279 // The reference is only used as a proxy for callbacks.
280 mObject = env->NewGlobalRef(weak_thiz);
281}
282
283JNIDrmListener::~JNIDrmListener()
284{
285 // remove global references
286 JNIEnv *env = AndroidRuntime::getJNIEnv();
287 env->DeleteGlobalRef(mObject);
288 env->DeleteGlobalRef(mClass);
289}
290
291void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
292 const Parcel *obj)
293{
Jeff Tinker74797f82015-03-31 15:44:34 -0700294 jint jwhat;
295 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700296
297 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700298 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700299 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700300 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700301 jeventType = gEventTypes.kEventProvisionRequired;
302 break;
303 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700304 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700305 jeventType = gEventTypes.kEventKeyRequired;
306 break;
307 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700308 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700309 jeventType = gEventTypes.kEventKeyExpired;
310 break;
311 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700312 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700313 jeventType = gEventTypes.kEventVendorDefined;
314 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800315 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700316 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800317 jeventType = gEventTypes.kEventSessionReclaimed;
318 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700319 case DrmPlugin::kDrmPluginEventExpirationUpdate:
320 jwhat = gEventWhat.kWhatExpirationUpdate;
321 break;
322 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700323 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700324 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800325 case DrmPlugin::kDrmPluginEventSessionLostState:
326 jwhat = gEventWhat.kWhatSessionLostState;
327 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700328 default:
329 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
330 return;
331 }
332
333 JNIEnv *env = AndroidRuntime::getJNIEnv();
334 if (obj && obj->dataSize() > 0) {
335 jobject jParcel = createJavaParcelObject(env);
336 if (jParcel != NULL) {
337 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
338 nativeParcel->setData(obj->data(), obj->dataSize());
339 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
Jeff Tinker74797f82015-03-31 15:44:34 -0700340 jwhat, jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100341 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700342 }
343 }
344
345 if (env->ExceptionCheck()) {
346 ALOGW("An exception occurred while notifying an event.");
347 LOGW_EX(env);
348 env->ExceptionClear();
349 }
350}
351
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700352static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
353 ALOGE("Illegal state exception: %s (%d)", msg, err);
354
355 jobject exception = env->NewObject(gFields.stateException.classId,
356 gFields.stateException.init, static_cast<int>(err),
357 env->NewStringUTF(msg));
358 env->Throw(static_cast<jthrowable>(exception));
359}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700360
Jeff Tinker20594d82018-12-12 08:31:22 -0800361static void throwSessionException(JNIEnv *env, const char *msg, status_t err) {
362 ALOGE("Session exception: %s (%d)", msg, err);
363
364 jint jErrorCode = 0;
365 switch(err) {
366 case ERROR_DRM_RESOURCE_CONTENTION:
367 jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
368 break;
369 default:
370 break;
371 }
372
373 jobject exception = env->NewObject(gFields.sessionException.classId,
374 gFields.sessionException.init, static_cast<int>(err),
375 env->NewStringUTF(msg));
376
377 env->SetIntField(exception, gFields.sessionException.errorCode, jErrorCode);
378 env->Throw(static_cast<jthrowable>(exception));
379}
380
381static bool isSessionException(status_t err) {
382 return err == ERROR_DRM_RESOURCE_CONTENTION;
383}
384
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800385static bool throwExceptionAsNecessary(
386 JNIEnv *env, status_t err, const char *msg = NULL) {
387
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700388 const char *drmMessage = NULL;
389
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700390 switch (err) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700391 case ERROR_DRM_UNKNOWN:
392 drmMessage = "General DRM error";
393 break;
394 case ERROR_DRM_NO_LICENSE:
395 drmMessage = "No license";
396 break;
397 case ERROR_DRM_LICENSE_EXPIRED:
398 drmMessage = "License expired";
399 break;
400 case ERROR_DRM_SESSION_NOT_OPENED:
401 drmMessage = "Session not opened";
402 break;
403 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
404 drmMessage = "Not initialized";
405 break;
406 case ERROR_DRM_DECRYPT:
407 drmMessage = "Decrypt error";
408 break;
409 case ERROR_DRM_CANNOT_HANDLE:
Jeff Tinkereb13c762017-11-01 15:29:38 -0700410 drmMessage = "Invalid parameter or data format";
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700411 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800412 case ERROR_DRM_INVALID_STATE:
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700413 drmMessage = "Invalid state";
414 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700415 default:
416 break;
417 }
418
419 String8 vendorMessage;
420 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
Jeff Tinker29799862014-08-27 11:05:13 -0700421 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700422 drmMessage = vendorMessage.string();
423 }
424
Jeff Tinkereb13c762017-11-01 15:29:38 -0700425 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800426 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
427 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700428 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
429 jniThrowException(env, "android/media/NotProvisionedException", msg);
430 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700431 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
432 jniThrowException(env, "android/media/ResourceBusyException", msg);
433 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700434 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
435 jniThrowException(env, "android/media/DeniedByServerException", msg);
436 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700437 } else if (err == DEAD_OBJECT) {
438 jniThrowException(env, "android/media/MediaDrmResetException",
439 "mediaserver died");
440 return true;
Jeff Tinker20594d82018-12-12 08:31:22 -0800441 } else if (isSessionException(err)) {
442 throwSessionException(env, msg, err);
443 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800444 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700445 String8 errbuf;
446 if (drmMessage != NULL) {
447 if (msg == NULL) {
448 msg = drmMessage;
449 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700450 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700451 msg = errbuf.string();
452 }
453 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700454 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800455 return true;
456 }
457 return false;
458}
459
460static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000461 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800462 return jdrm ? jdrm->getDrm() : NULL;
463}
464
465JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800466 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
467 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800468 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800469 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700470 if (mDrm != NULL) {
471 mDrm->setListener(this);
472 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800473}
474
475JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800476 JNIEnv *env = AndroidRuntime::getJNIEnv();
477
478 env->DeleteWeakGlobalRef(mObject);
479 mObject = NULL;
480}
481
482// static
483sp<IDrm> JDrm::MakeDrm() {
484 sp<IServiceManager> sm = defaultServiceManager();
485
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700486 sp<IBinder> binder = sm->getService(String16("media.drm"));
487 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
488 if (service == NULL) {
489 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800490 }
491
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700492 sp<IDrm> drm = service->makeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800493 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
494 return NULL;
495 }
496
497 return drm;
498}
499
500// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800501sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800502 sp<IDrm> drm = MakeDrm();
503
504 if (drm == NULL) {
505 return NULL;
506 }
507
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800508 status_t err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800509
510 if (err != OK) {
511 return NULL;
512 }
513
514 return drm;
515}
516
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700517status_t JDrm::setListener(const sp<DrmListener>& listener) {
518 Mutex::Autolock lock(mLock);
519 mListener = listener;
520 return OK;
521}
522
523void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
524 sp<DrmListener> listener;
525 mLock.lock();
526 listener = mListener;
527 mLock.unlock();
528
529 if (listener != NULL) {
530 Mutex::Autolock lock(mNotifyLock);
531 listener->notify(eventType, extra, obj);
532 }
533}
534
Jeff Tinker600071c2014-04-11 16:11:15 -0700535void JDrm::disconnect() {
536 if (mDrm != NULL) {
537 mDrm->destroyPlugin();
538 mDrm.clear();
539 }
540}
541
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700542
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800543// static
Jeff Tinker7cda4912013-08-21 11:52:34 -0700544bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800545 sp<IDrm> drm = MakeDrm();
546
547 if (drm == NULL) {
548 return false;
549 }
550
Jeff Tinker7cda4912013-08-21 11:52:34 -0700551 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800552}
553
554status_t JDrm::initCheck() const {
555 return mDrm == NULL ? NO_INIT : OK;
556}
557
558// JNI conversion utilities
559static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
560 Vector<uint8_t> vector;
561 size_t length = env->GetArrayLength(byteArray);
562 vector.insertAt((size_t)0, length);
563 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
564 return vector;
565}
566
567static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
568 size_t length = vector.size();
569 jbyteArray result = env->NewByteArray(length);
570 if (result != NULL) {
571 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
572 }
573 return result;
574}
575
576static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800577 String8 result;
578
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700579 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800580 if (s) {
581 result = s;
582 env->ReleaseStringUTFChars(jstr, s);
583 }
584 return result;
585}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700586
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800587/*
588 import java.util.HashMap;
589 import java.util.Set;
590 import java.Map.Entry;
591 import jav.util.Iterator;
592
593 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800594 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800595 Iterator i = s.iterator();
596 Entry e = s.next();
597*/
598
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200599static KeyedVector<String8, String8> HashMapToKeyedVector(
600 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800601 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800602 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200603 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800604
605 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
606 if (entrySet) {
607 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
608 if (iterator) {
609 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
610 while (hasNext) {
611 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
612 if (entry) {
613 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200614 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700615 jniThrowException(env, "java/lang/IllegalArgumentException",
616 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200617 env->DeleteLocalRef(entry);
618 *pIsOK = false;
619 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800620 }
621 jstring jkey = static_cast<jstring>(obj);
622
623 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200624 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700625 jniThrowException(env, "java/lang/IllegalArgumentException",
626 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200627 env->DeleteLocalRef(entry);
628 *pIsOK = false;
629 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800630 }
631 jstring jvalue = static_cast<jstring>(obj);
632
633 String8 key = JStringToString8(env, jkey);
634 String8 value = JStringToString8(env, jvalue);
635 keyedVector.add(key, value);
636
637 env->DeleteLocalRef(jkey);
638 env->DeleteLocalRef(jvalue);
639 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
640 }
641 env->DeleteLocalRef(entry);
642 }
643 env->DeleteLocalRef(iterator);
644 }
645 env->DeleteLocalRef(entrySet);
646 }
647 return keyedVector;
648}
649
650static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800651 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800652 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
653 for (size_t i = 0; i < map.size(); ++i) {
654 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
655 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
656 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
657 env->DeleteLocalRef(jkey);
658 env->DeleteLocalRef(jvalue);
659 }
660 return hashMap;
661}
662
663static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800664 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800665 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800666 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800667 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800668 while (iter != list.end()) {
669 jbyteArray byteArray = VectorToJByteArray(env, *iter);
670 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
671 env->DeleteLocalRef(byteArray);
672 iter++;
673 }
674
675 return arrayList;
676}
677
678} // namespace android
679
680using namespace android;
681
682static sp<JDrm> setDrm(
683 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000684 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800685 if (drm != NULL) {
686 drm->incStrong(thiz);
687 }
688 if (old != NULL) {
689 old->decStrong(thiz);
690 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000691 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800692
693 return old;
694}
695
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800696static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800697 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700698 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800699 return false;
700 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800701 return true;
702}
703
704static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
705{
706 if (!CheckDrm(env, drm)) {
707 return false;
708 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800709
710 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700711 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800712 return false;
713 }
714 return true;
715}
716
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800717static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700718 sp<JDrm> drm = setDrm(env, thiz, NULL);
719 if (drm != NULL) {
720 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700721 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700722 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800723}
724
725static void android_media_MediaDrm_native_init(JNIEnv *env) {
726 jclass clazz;
727 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000728 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700729 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700730 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700731
732 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700733 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700734 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700735 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700736 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700737 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700738 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700739 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700740 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800741 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
742 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800743
Jeff Tinker74797f82015-03-31 15:44:34 -0700744 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
745 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
746 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
747 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700748 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
749 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800750 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
751 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700752
Jeff Tinker17b89222013-05-21 12:35:06 -0700753 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
754 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
755 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
756 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
757 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
758 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
759
Jeff Tinkere4095a82014-03-04 13:17:11 -0800760 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
761 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
762 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
763 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
764
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800765 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
766 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
767 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
768 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
769 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
770 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
771 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
772 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
773 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
774 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
775 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
776 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
777 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
778 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
779
780 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
781 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700782 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800783 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700784 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800785 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700786 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800787 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700788 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800789 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700790 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800791 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
792
Jeff Tinker55d26242018-10-10 16:10:43 -0700793 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_USABLE", "I");
794 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
795 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_INACTIVE", "I");
796 gOfflineLicenseStates.kOfflineLicenseStateInactive = env->GetStaticIntField(clazz, field);
797 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
798 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
799
800 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
801
Jeff Tinker2bca5252018-02-11 18:59:14 +0000802 jmethodID getMaxSecurityLevel;
803 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
804 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
805
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700806 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700807 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
808 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700809 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800810
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700811 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
812 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
813 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
814 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
815 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
816 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800817 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
818 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
819 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
820 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700821
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800822 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700823 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
824 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800825
Jeff Tinkere4095a82014-03-04 13:17:11 -0800826 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
827 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
828 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700829 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800830
Adam Stone94395c92018-01-30 12:07:00 -0800831 // Metrics-related fields and classes.
832 FIND_CLASS(clazz, "android/os/PersistableBundle");
833 jfieldID bundleCreatorId;
834 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
835 "Landroid/os/Parcelable$Creator;");
836 jobject bundleCreator;
837 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
838 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
839 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
840 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
841 "(Landroid/os/Parcel;)Ljava/lang/Object;");
842 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
843
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800844 FIND_CLASS(clazz, "java/util/ArrayList");
845 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
846 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
847
848 FIND_CLASS(clazz, "java/util/HashMap");
849 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
850 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
851 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
852 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
853 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
854
855 FIND_CLASS(clazz, "java/util/Set");
856 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
857
858 FIND_CLASS(clazz, "java/util/Iterator");
859 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
860 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
861
862 FIND_CLASS(clazz, "java/util/Map$Entry");
863 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
864 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800865
866 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700867 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800868
869 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700870 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800871
872 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700873 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700874
875 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
876 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
877 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800878
879 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
880 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
881 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
882 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
883
884 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
885 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800886}
887
888static void android_media_MediaDrm_native_setup(
889 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800890 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800891
892 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700893 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800894 return;
895 }
896
897 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
898
899 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700900 jniThrowException(env, "java/lang/IllegalArgumentException",
901 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800902 return;
903 }
904
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800905 String8 packageName;
906 if (jappPackageName == NULL) {
907 jniThrowException(env, "java/lang/IllegalArgumentException",
908 "application package name cannot be null");
909 return;
910 }
911
912 packageName = JStringToString8(env, jappPackageName);
913 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800914
915 status_t err = drm->initCheck();
916
917 if (err != OK) {
918 jniThrowException(
919 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700920 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800921 "Failed to instantiate drm object.");
922 return;
923 }
924
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700925 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
926 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800927 setDrm(env, thiz, drm);
928}
929
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800930static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800931 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800932
933 if (uuidObj == NULL) {
934 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
935 return false;
936 }
937
938 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
939
940 if (uuid.size() != 16) {
941 jniThrowException(
942 env,
943 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700944 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800945 return false;
946 }
947
Jeff Tinker7cda4912013-08-21 11:52:34 -0700948 String8 mimeType;
949 if (jmimeType != NULL) {
950 mimeType = JStringToString8(env, jmimeType);
951 }
952
953 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800954}
955
956static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +0000957 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800958 sp<IDrm> drm = GetDrm(env, thiz);
959
Jeff Tinker55d26242018-10-10 16:10:43 -0700960 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800961 return NULL;
962 }
963
964 Vector<uint8_t> sessionId;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000965 DrmPlugin::SecurityLevel level;
966
967 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
968 level = DrmPlugin::kSecurityLevelMax;
969 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
970 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
971 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
972 level = DrmPlugin::kSecurityLevelSwSecureDecode;
973 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
974 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
975 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
976 level = DrmPlugin::kSecurityLevelHwSecureDecode;
977 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
978 level = DrmPlugin::kSecurityLevelHwSecureAll;
979 } else {
980 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
981 return NULL;
982 }
983
984 status_t err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800985
986 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
987 return NULL;
988 }
989
990 return VectorToJByteArray(env, sessionId);
991}
992
993static void android_media_MediaDrm_closeSession(
994 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
995 sp<IDrm> drm = GetDrm(env, thiz);
996
997 if (!CheckSession(env, drm, jsessionId)) {
998 return;
999 }
1000
1001 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1002
1003 status_t err = drm->closeSession(sessionId);
1004
1005 throwExceptionAsNecessary(env, err, "Failed to close session");
1006}
1007
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001008static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001009 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001010 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001011 sp<IDrm> drm = GetDrm(env, thiz);
1012
1013 if (!CheckSession(env, drm, jsessionId)) {
1014 return NULL;
1015 }
1016
1017 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1018
1019 Vector<uint8_t> initData;
1020 if (jinitData != NULL) {
1021 initData = JByteArrayToVector(env, jinitData);
1022 }
1023
1024 String8 mimeType;
1025 if (jmimeType != NULL) {
1026 mimeType = JStringToString8(env, jmimeType);
1027 }
1028
Jeff Tinker17b89222013-05-21 12:35:06 -07001029 DrmPlugin::KeyType keyType;
1030 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1031 keyType = DrmPlugin::kKeyType_Streaming;
1032 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1033 keyType = DrmPlugin::kKeyType_Offline;
1034 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1035 keyType = DrmPlugin::kKeyType_Release;
1036 } else {
1037 jniThrowException(env, "java/lang/IllegalArgumentException",
1038 "invalid keyType");
1039 return NULL;
1040 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001041
1042 KeyedVector<String8, String8> optParams;
1043 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001044 bool isOK;
1045 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1046 if (!isOK) {
1047 return NULL;
1048 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001049 }
1050
1051 Vector<uint8_t> request;
1052 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001053 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001054
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001055 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001056 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001057
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001058 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001059 return NULL;
1060 }
1061
1062 // Fill out return obj
1063 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001064 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001065
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001066 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001067
1068 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001069 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001070 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001071 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001072
1073 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001074 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001075
1076 switch (keyRequestType) {
1077 case DrmPlugin::kKeyRequestType_Initial:
1078 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1079 gKeyRequestTypes.kKeyRequestTypeInitial);
1080 break;
1081 case DrmPlugin::kKeyRequestType_Renewal:
1082 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1083 gKeyRequestTypes.kKeyRequestTypeRenewal);
1084 break;
1085 case DrmPlugin::kKeyRequestType_Release:
1086 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1087 gKeyRequestTypes.kKeyRequestTypeRelease);
1088 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001089 case DrmPlugin::kKeyRequestType_None:
1090 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1091 gKeyRequestTypes.kKeyRequestTypeNone);
1092 break;
1093 case DrmPlugin::kKeyRequestType_Update:
1094 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1095 gKeyRequestTypes.kKeyRequestTypeUpdate);
1096 break;
1097
Jeff Tinker74797f82015-03-31 15:44:34 -07001098 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001099 throwStateException(env, "DRM plugin failure: unknown key request type",
1100 ERROR_DRM_UNKNOWN);
1101 break;
1102 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001103 }
1104
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001105 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001106}
1107
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001108static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001109 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1110 sp<IDrm> drm = GetDrm(env, thiz);
1111
1112 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001113 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001114 }
1115
1116 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1117
1118 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001119 jniThrowException(env, "java/lang/IllegalArgumentException",
1120 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001121 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001122 }
1123 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001124 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001125
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001126 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001127
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001128 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
1129 return NULL;
1130 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001131 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001132}
1133
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001134static void android_media_MediaDrm_removeKeys(
1135 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1136 sp<IDrm> drm = GetDrm(env, thiz);
1137
Jeff Tinker55d26242018-10-10 16:10:43 -07001138 if (!CheckDrm(env, drm)) {
1139 return;
1140 }
1141
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001142 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001143 jniThrowException(env, "java/lang/IllegalArgumentException",
1144 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001145 return;
1146 }
1147
1148 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1149
1150 status_t err = drm->removeKeys(keySetId);
1151
1152 throwExceptionAsNecessary(env, err, "Failed to remove keys");
1153}
1154
1155static void android_media_MediaDrm_restoreKeys(
1156 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1157 jbyteArray jkeysetId) {
1158
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001159 sp<IDrm> drm = GetDrm(env, thiz);
1160
1161 if (!CheckSession(env, drm, jsessionId)) {
1162 return;
1163 }
1164
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001165 if (jkeysetId == NULL) {
1166 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1167 return;
1168 }
1169
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001170 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001171 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001172
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001173 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001174
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001175 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001176}
1177
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001178static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001179 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1180 sp<IDrm> drm = GetDrm(env, thiz);
1181
1182 if (!CheckSession(env, drm, jsessionId)) {
1183 return NULL;
1184 }
1185 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1186
1187 KeyedVector<String8, String8> infoMap;
1188
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001189 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001190
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001191 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001192 return NULL;
1193 }
1194
1195 return KeyedVectorToHashMap(env, infoMap);
1196}
1197
Jeff Tinkere4095a82014-03-04 13:17:11 -08001198static jobject android_media_MediaDrm_getProvisionRequestNative(
1199 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001200 sp<IDrm> drm = GetDrm(env, thiz);
1201
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001202 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001203 return NULL;
1204 }
1205
1206 Vector<uint8_t> request;
1207 String8 defaultUrl;
1208
Jeff Tinkere4095a82014-03-04 13:17:11 -08001209 String8 certType;
1210 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1211 certType = "X.509";
1212 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1213 certType = "none";
1214 } else {
1215 certType = "invalid";
1216 }
1217
1218 String8 certAuthority = JStringToString8(env, jcertAuthority);
1219 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001220
1221 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
1222 return NULL;
1223 }
1224
1225 // Fill out return obj
1226 jclass clazz;
1227 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1228
1229 jobject provisionObj = NULL;
1230
1231 if (clazz) {
1232 provisionObj = env->AllocObject(clazz);
1233 jbyteArray jrequest = VectorToJByteArray(env, request);
1234 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1235
1236 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1237 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1238 }
1239
1240 return provisionObj;
1241}
1242
Jeff Tinkere4095a82014-03-04 13:17:11 -08001243static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001244 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1245 sp<IDrm> drm = GetDrm(env, thiz);
1246
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001247 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001248 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001249 }
1250
1251 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001252 jniThrowException(env, "java/lang/IllegalArgumentException",
1253 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001254 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001255 }
1256
1257 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001258 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001259
Jeff Tinkere4095a82014-03-04 13:17:11 -08001260 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1261
1262 // Fill out return obj
1263 jclass clazz = gFields.certificateClassId;
1264
1265 jobject certificateObj = NULL;
1266
1267 if (clazz && certificate.size() && wrappedKey.size()) {
1268 certificateObj = env->AllocObject(clazz);
1269 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1270 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1271
1272 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1273 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1274 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001275
1276 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001277 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001278}
1279
1280static jobject android_media_MediaDrm_getSecureStops(
1281 JNIEnv *env, jobject thiz) {
1282 sp<IDrm> drm = GetDrm(env, thiz);
1283
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001284 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001285 return NULL;
1286 }
1287
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001288 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001289
1290 status_t err = drm->getSecureStops(secureStops);
1291
1292 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1293 return NULL;
1294 }
1295
1296 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1297}
1298
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001299static jobject android_media_MediaDrm_getSecureStopIds(
1300 JNIEnv *env, jobject thiz) {
1301 sp<IDrm> drm = GetDrm(env, thiz);
1302
Jeff Tinker55d26242018-10-10 16:10:43 -07001303 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001304 return NULL;
1305 }
1306
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001307 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001308
1309 status_t err = drm->getSecureStopIds(secureStopIds);
1310
1311 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop Ids")) {
1312 return NULL;
1313 }
1314
1315 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1316}
1317
Jeff Tinker1b51c722014-10-31 00:54:26 -07001318static jbyteArray android_media_MediaDrm_getSecureStop(
1319 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1320 sp<IDrm> drm = GetDrm(env, thiz);
1321
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001322 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001323 return NULL;
1324 }
1325
1326 Vector<uint8_t> secureStop;
1327
1328 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1329
1330 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1331 return NULL;
1332 }
1333
1334 return VectorToJByteArray(env, secureStop);
1335}
1336
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001337static void android_media_MediaDrm_releaseSecureStops(
1338 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1339 sp<IDrm> drm = GetDrm(env, thiz);
1340
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001341 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001342 return;
1343 }
1344
1345 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1346
1347 status_t err = drm->releaseSecureStops(ssRelease);
1348
1349 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1350}
1351
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001352static void android_media_MediaDrm_removeSecureStop(
1353 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1354 sp<IDrm> drm = GetDrm(env, thiz);
1355
Jeff Tinker55d26242018-10-10 16:10:43 -07001356 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001357 return;
1358 }
1359
1360 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1361
1362 throwExceptionAsNecessary(env, err, "Failed to remove secure stop");
1363}
1364
1365static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001366 JNIEnv *env, jobject thiz) {
1367 sp<IDrm> drm = GetDrm(env, thiz);
1368
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001369 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001370 return;
1371 }
1372
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001373 status_t err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001374
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001375 throwExceptionAsNecessary(env, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001376}
1377
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001378
1379static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1380 switch(level) {
1381 case DrmPlugin::kHdcpLevelUnknown:
1382 return gHdcpLevels.kHdcpLevelUnknown;
1383 case DrmPlugin::kHdcpNone:
1384 return gHdcpLevels.kHdcpNone;
1385 case DrmPlugin::kHdcpV1:
1386 return gHdcpLevels.kHdcpV1;
1387 case DrmPlugin::kHdcpV2:
1388 return gHdcpLevels.kHdcpV2;
1389 case DrmPlugin::kHdcpV2_1:
1390 return gHdcpLevels.kHdcpV2_1;
1391 case DrmPlugin::kHdcpV2_2:
1392 return gHdcpLevels.kHdcpV2_2;
1393 case DrmPlugin::kHdcpNoOutput:
1394 return gHdcpLevels.kHdcpNoOutput;
1395 }
1396 return gHdcpLevels.kHdcpNone;
1397}
1398
1399static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1400 jobject thiz) {
1401 sp<IDrm> drm = GetDrm(env, thiz);
1402
1403 if (!CheckDrm(env, drm)) {
1404 return gHdcpLevels.kHdcpNone;
1405 }
1406
1407 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1408 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1409
1410 status_t err = drm->getHdcpLevels(&connected, &max);
1411
1412 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1413 return gHdcpLevels.kHdcpLevelUnknown;
1414 }
1415 return HdcpLevelTojint(connected);
1416}
1417
1418static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1419 jobject thiz) {
1420 sp<IDrm> drm = GetDrm(env, thiz);
1421
1422 if (!CheckDrm(env, drm)) {
1423 return gHdcpLevels.kHdcpLevelUnknown;
1424 }
1425
1426 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1427 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1428
1429 status_t err = drm->getHdcpLevels(&connected, &max);
1430
1431 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1432 return gHdcpLevels.kHdcpLevelUnknown;
1433 }
1434 return HdcpLevelTojint(max);
1435}
1436
1437static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1438 jobject thiz) {
1439 sp<IDrm> drm = GetDrm(env, thiz);
1440
1441 if (!CheckDrm(env, drm)) {
1442 return 0;
1443 }
1444
1445 uint32_t open = 0, max = 0;
1446 status_t err = drm->getNumberOfSessions(&open, &max);
1447
1448 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1449 return 0;
1450 }
1451 return open;
1452}
1453
1454static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1455 jobject thiz) {
1456 sp<IDrm> drm = GetDrm(env, thiz);
1457
1458 if (!CheckDrm(env, drm)) {
1459 return 0;
1460 }
1461
1462 uint32_t open = 0, max = 0;
1463 status_t err = drm->getNumberOfSessions(&open, &max);
1464
1465 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1466 return 0;
1467 }
1468 return max;
1469}
1470
1471static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1472 jobject thiz, jbyteArray jsessionId) {
1473 sp<IDrm> drm = GetDrm(env, thiz);
1474
1475 if (!CheckSession(env, drm, jsessionId)) {
1476 return gSecurityLevels.kSecurityLevelUnknown;
1477 }
1478
1479 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1480
1481 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1482
1483 status_t err = drm->getSecurityLevel(sessionId, &level);
1484
1485 if (throwExceptionAsNecessary(env, err, "Failed to get security level")) {
1486 return gSecurityLevels.kSecurityLevelUnknown;
1487 }
1488
1489 switch(level) {
1490 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1491 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1492 case DrmPlugin::kSecurityLevelSwSecureDecode:
1493 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1494 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1495 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1496 case DrmPlugin::kSecurityLevelHwSecureDecode:
1497 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1498 case DrmPlugin::kSecurityLevelHwSecureAll:
1499 return gSecurityLevels.kSecurityLevelHwSecureAll;
1500 default:
1501 return gSecurityLevels.kSecurityLevelUnknown;
1502 }
1503}
1504
Jeff Tinker55d26242018-10-10 16:10:43 -07001505static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1506 JNIEnv *env, jobject thiz) {
1507 sp<IDrm> drm = GetDrm(env, thiz);
1508
1509 if (!CheckDrm(env, drm)) {
1510 return NULL;
1511 }
1512
1513 List<Vector<uint8_t> > keySetIds;
1514
1515 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1516
1517 if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) {
1518 return NULL;
1519 }
1520
1521 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1522}
1523
1524static void android_media_MediaDrm_removeOfflineLicense(
1525 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1526 sp<IDrm> drm = GetDrm(env, thiz);
1527
1528 if (!CheckDrm(env, drm)) {
1529 return;
1530 }
1531
1532 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1533
1534 throwExceptionAsNecessary(env, err, "Failed to remove offline license");
1535}
1536
1537static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1538 jobject thiz, jbyteArray jkeySetId) {
1539 sp<IDrm> drm = GetDrm(env, thiz);
1540
1541 if (!CheckDrm(env, drm)) {
1542 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1543 }
1544
1545 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1546
1547 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1548
1549 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1550
1551 if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) {
1552 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1553 }
1554
1555 switch(state) {
1556 case DrmPlugin::kOfflineLicenseStateUsable:
1557 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
1558 case DrmPlugin::kOfflineLicenseStateInactive:
1559 return gOfflineLicenseStates.kOfflineLicenseStateInactive;
1560 default:
1561 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1562 }
1563}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001564
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001565static jstring android_media_MediaDrm_getPropertyString(
1566 JNIEnv *env, jobject thiz, jstring jname) {
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 NULL;
1571 }
1572
1573 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001574 jniThrowException(env, "java/lang/IllegalArgumentException",
1575 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001576 return NULL;
1577 }
1578
1579 String8 name = JStringToString8(env, jname);
1580 String8 value;
1581
1582 status_t err = drm->getPropertyString(name, value);
1583
1584 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1585 return NULL;
1586 }
1587
1588 return env->NewStringUTF(value.string());
1589}
1590
1591static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1592 JNIEnv *env, jobject thiz, jstring jname) {
1593 sp<IDrm> drm = GetDrm(env, thiz);
1594
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001595 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001596 return NULL;
1597 }
1598
1599 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001600 jniThrowException(env, "java/lang/IllegalArgumentException",
1601 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001602 return NULL;
1603 }
1604
1605 String8 name = JStringToString8(env, jname);
1606 Vector<uint8_t> value;
1607
1608 status_t err = drm->getPropertyByteArray(name, value);
1609
1610 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1611 return NULL;
1612 }
1613
1614 return VectorToJByteArray(env, value);
1615}
1616
1617static void android_media_MediaDrm_setPropertyString(
1618 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1619 sp<IDrm> drm = GetDrm(env, thiz);
1620
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001621 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001622 return;
1623 }
1624
Jeff Tinkereada5372013-05-21 12:48:14 -07001625 if (jname == NULL) {
1626 jniThrowException(env, "java/lang/IllegalArgumentException",
1627 "property name String is null");
1628 return;
1629 }
1630
1631 if (jvalue == NULL) {
1632 jniThrowException(env, "java/lang/IllegalArgumentException",
1633 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001634 return;
1635 }
1636
1637 String8 name = JStringToString8(env, jname);
1638 String8 value = JStringToString8(env, jvalue);
1639
1640 status_t err = drm->setPropertyString(name, value);
1641
1642 throwExceptionAsNecessary(env, err, "Failed to set property");
1643}
1644
1645static void android_media_MediaDrm_setPropertyByteArray(
1646 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1647 sp<IDrm> drm = GetDrm(env, thiz);
1648
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001649 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001650 return;
1651 }
1652
Jeff Tinkereada5372013-05-21 12:48:14 -07001653 if (jname == NULL) {
1654 jniThrowException(env, "java/lang/IllegalArgumentException",
1655 "property name String is null");
1656 return;
1657 }
1658
1659 if (jvalue == NULL) {
1660 jniThrowException(env, "java/lang/IllegalArgumentException",
1661 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001662 return;
1663 }
1664
1665 String8 name = JStringToString8(env, jname);
1666 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1667
1668 status_t err = drm->setPropertyByteArray(name, value);
1669
1670 throwExceptionAsNecessary(env, err, "Failed to set property");
1671}
1672
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001673static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001674 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001675 jstring jalgorithm) {
1676
1677 sp<IDrm> drm = GetDrm(env, jdrm);
1678
1679 if (!CheckSession(env, drm, jsessionId)) {
1680 return;
1681 }
1682
1683 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001684 jniThrowException(env, "java/lang/IllegalArgumentException",
1685 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001686 return;
1687 }
1688
1689 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1690 String8 algorithm = JStringToString8(env, jalgorithm);
1691
1692 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1693
1694 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1695}
1696
1697static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001698 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001699 jstring jalgorithm) {
1700
1701 sp<IDrm> drm = GetDrm(env, jdrm);
1702
1703 if (!CheckSession(env, drm, jsessionId)) {
1704 return;
1705 }
1706
1707 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001708 jniThrowException(env, "java/lang/IllegalArgumentException",
1709 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001710 return;
1711 }
1712
1713 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1714 String8 algorithm = JStringToString8(env, jalgorithm);
1715
1716 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1717
1718 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1719}
1720
1721
1722static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001723 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001724 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1725
1726 sp<IDrm> drm = GetDrm(env, jdrm);
1727
1728 if (!CheckSession(env, drm, jsessionId)) {
1729 return NULL;
1730 }
1731
1732 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001733 jniThrowException(env, "java/lang/IllegalArgumentException",
1734 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001735 return NULL;
1736 }
1737
1738 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1739 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1740 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1741 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1742 Vector<uint8_t> output;
1743
1744 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1745
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001746 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1747 return NULL;
1748 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001749
1750 return VectorToJByteArray(env, output);
1751}
1752
1753static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001754 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001755 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1756
1757 sp<IDrm> drm = GetDrm(env, jdrm);
1758
1759 if (!CheckSession(env, drm, jsessionId)) {
1760 return NULL;
1761 }
1762
1763 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001764 jniThrowException(env, "java/lang/IllegalArgumentException",
1765 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001766 return NULL;
1767 }
1768
1769 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1770 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1771 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1772 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1773 Vector<uint8_t> output;
1774
1775 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001776 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1777 return NULL;
1778 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001779
1780 return VectorToJByteArray(env, output);
1781}
1782
1783static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001784 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001785 jbyteArray jkeyId, jbyteArray jmessage) {
1786
1787 sp<IDrm> drm = GetDrm(env, jdrm);
1788
1789 if (!CheckSession(env, drm, jsessionId)) {
1790 return NULL;
1791 }
1792
1793 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001794 jniThrowException(env, "java/lang/IllegalArgumentException",
1795 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001796 return NULL;
1797 }
1798
1799 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1800 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1801 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1802 Vector<uint8_t> signature;
1803
1804 status_t err = drm->sign(sessionId, keyId, message, signature);
1805
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001806 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1807 return NULL;
1808 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001809
1810 return VectorToJByteArray(env, signature);
1811}
1812
1813static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001814 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001815 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1816
1817 sp<IDrm> drm = GetDrm(env, jdrm);
1818
1819 if (!CheckSession(env, drm, jsessionId)) {
1820 return false;
1821 }
1822
1823 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001824 jniThrowException(env, "java/lang/IllegalArgumentException",
1825 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001826 return false;
1827 }
1828
1829 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1830 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1831 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1832 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1833 bool match;
1834
1835 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1836
1837 throwExceptionAsNecessary(env, err, "Failed to verify");
1838 return match;
1839}
1840
Adam Stonec06e10e2017-12-19 12:54:33 -08001841static jobject
1842android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1843{
1844 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001845
1846 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001847 return NULL;
1848 }
1849
1850 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001851 PersistableBundle metrics;
1852 status_t err = drm->getMetrics(&metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001853 if (err != OK) {
1854 ALOGE("getMetrics failed: %d", (int)err);
1855 return (jobject) NULL;
1856 }
1857
Adam Stone94395c92018-01-30 12:07:00 -08001858 return nativeToJavaPersistableBundle(env, thiz, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001859}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001860
Jeff Tinkere4095a82014-03-04 13:17:11 -08001861static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001862 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001863 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1864
1865 sp<IDrm> drm = GetDrm(env, jdrm);
1866
1867 if (!CheckSession(env, drm, jsessionId)) {
1868 return NULL;
1869 }
1870
1871 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1872 jniThrowException(env, "java/lang/IllegalArgumentException",
1873 "required argument is null");
1874 return NULL;
1875 }
1876
1877 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1878 String8 algorithm = JStringToString8(env, jalgorithm);
1879 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1880 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1881 Vector<uint8_t> signature;
1882
1883 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1884
1885 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1886 return NULL;
1887 }
1888
1889 return VectorToJByteArray(env, signature);
1890}
1891
1892
Daniel Micay76f6a862015-09-19 17:31:01 -04001893static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001894 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
1895
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001896 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1897
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001898 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001899 (void *)android_media_MediaDrm_native_setup },
1900
Jeff Tinker7cda4912013-08-21 11:52:34 -07001901 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001902 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1903
Jeff Tinker2bca5252018-02-11 18:59:14 +00001904 { "openSession", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001905 (void *)android_media_MediaDrm_openSession },
1906
1907 { "closeSession", "([B)V",
1908 (void *)android_media_MediaDrm_closeSession },
1909
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001910 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1911 "Landroid/media/MediaDrm$KeyRequest;",
1912 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001913
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001914 { "provideKeyResponse", "([B[B)[B",
1915 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001916
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001917 { "removeKeys", "([B)V",
1918 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001919
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001920 { "restoreKeys", "([B[B)V",
1921 (void *)android_media_MediaDrm_restoreKeys },
1922
1923 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1924 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001925
Jeff Tinkere4095a82014-03-04 13:17:11 -08001926 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1927 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001928
Jeff Tinkere4095a82014-03-04 13:17:11 -08001929 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1930 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001931
1932 { "getSecureStops", "()Ljava/util/List;",
1933 (void *)android_media_MediaDrm_getSecureStops },
1934
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001935 { "getSecureStopIds", "()Ljava/util/List;",
1936 (void *)android_media_MediaDrm_getSecureStopIds },
1937
Jeff Tinker1b51c722014-10-31 00:54:26 -07001938 { "getSecureStop", "([B)[B",
1939 (void *)android_media_MediaDrm_getSecureStop },
1940
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001941 { "releaseSecureStops", "([B)V",
1942 (void *)android_media_MediaDrm_releaseSecureStops },
1943
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001944 { "removeSecureStop", "([B)V",
1945 (void *)android_media_MediaDrm_removeSecureStop },
1946
1947 { "removeAllSecureStops", "()V",
1948 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07001949
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001950 { "getConnectedHdcpLevel", "()I",
1951 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
1952
1953 { "getMaxHdcpLevel", "()I",
1954 (void *)android_media_MediaDrm_getMaxHdcpLevel },
1955
1956 { "getOpenSessionCount", "()I",
1957 (void *)android_media_MediaDrm_getOpenSessionCount },
1958
1959 { "getMaxSessionCount", "()I",
1960 (void *)android_media_MediaDrm_getMaxSessionCount },
1961
1962 { "getSecurityLevel", "([B)I",
1963 (void *)android_media_MediaDrm_getSecurityLevel },
1964
Jeff Tinker55d26242018-10-10 16:10:43 -07001965 { "removeOfflineLicense", "([B)V",
1966 (void *)android_media_MediaDrm_removeOfflineLicense },
1967
1968 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
1969 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
1970
1971 { "getOfflineLicenseState", "([B)I",
1972 (void *)android_media_MediaDrm_getOfflineLicenseState },
1973
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001974 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1975 (void *)android_media_MediaDrm_getPropertyString },
1976
1977 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1978 (void *)android_media_MediaDrm_getPropertyByteArray },
1979
1980 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1981 (void *)android_media_MediaDrm_setPropertyString },
1982
1983 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1984 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001985
1986 { "setCipherAlgorithmNative",
1987 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1988 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1989
1990 { "setMacAlgorithmNative",
1991 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1992 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1993
1994 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1995 (void *)android_media_MediaDrm_encryptNative },
1996
1997 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1998 (void *)android_media_MediaDrm_decryptNative },
1999
2000 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2001 (void *)android_media_MediaDrm_signNative },
2002
2003 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2004 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002005
2006 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2007 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002008
2009 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2010 (void *)android_media_MediaDrm_native_getMetrics },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002011};
2012
2013int register_android_media_Drm(JNIEnv *env) {
2014 return AndroidRuntime::registerNativeMethods(env,
2015 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2016}