blob: 81fce8a8044be58a083a776b3c50bd0190b08451 [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;
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800162 jint kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800163 jint kHdcpNoOutput;
164} gHdcpLevels;
165
166struct SecurityLevels {
167 jint kSecurityLevelUnknown;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000168 jint kSecurityLevelMax;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800169 jint kSecurityLevelSwSecureCrypto;
170 jint kSecurityLevelSwSecureDecode;
171 jint kSecurityLevelHwSecureCrypto;
172 jint kSecurityLevelHwSecureDecode;
173 jint kSecurityLevelHwSecureAll;
174} gSecurityLevels;
175
Jeff Tinker55d26242018-10-10 16:10:43 -0700176struct OfflineLicenseState {
177 jint kOfflineLicenseStateUsable;
178 jint kOfflineLicenseStateInactive;
179 jint kOfflineLicenseStateUnknown;
180} gOfflineLicenseStates;
181
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800182
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800183struct fields_t {
184 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700185 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700186 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800187 RequestFields provisionRequest;
188 ArrayListFields arraylist;
189 HashmapFields hashmap;
190 SetFields set;
191 IteratorFields iterator;
192 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800193 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700194 StateExceptionFields stateException;
Jeff Tinker20594d82018-12-12 08:31:22 -0800195 SessionExceptionFields sessionException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800196 jclass certificateClassId;
197 jclass hashmapClassId;
198 jclass arraylistClassId;
199 jclass stringClassId;
Adam Stone94395c92018-01-30 12:07:00 -0800200 jobject bundleCreator;
201 jmethodID createFromParcelId;
202 jclass parcelCreatorClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800203};
204
205static fields_t gFields;
206
Adam Stone94395c92018-01-30 12:07:00 -0800207namespace {
208
209// Helper function to convert a native PersistableBundle to a Java
210// PersistableBundle.
211jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
212 PersistableBundle* nativeBundle) {
213 if (env == NULL || thiz == NULL || nativeBundle == NULL) {
214 ALOGE("Unexpected NULL parmeter");
215 return NULL;
216 }
217
218 // Create a Java parcel with the native parcel data.
219 // Then create a new PersistableBundle with that parcel as a parameter.
220 jobject jParcel = android::createJavaParcelObject(env);
221 if (jParcel == NULL) {
222 ALOGE("Failed to create a Java Parcel.");
223 return NULL;
224 }
225
226 android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
227 if (nativeParcel == NULL) {
228 ALOGE("Failed to get the native Parcel.");
229 return NULL;
230 }
231
232 android::status_t result = nativeBundle->writeToParcel(nativeParcel);
233 nativeParcel->setDataPosition(0);
234 if (result != android::OK) {
235 ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
236 return NULL;
237 }
238
239 jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
240 gFields.createFromParcelId,
241 jParcel);
242 if (newBundle == NULL) {
243 ALOGE("Failed to create a new PersistableBundle "
244 "from the createFromParcel call.");
245 }
246
247 return newBundle;
248}
249
250} // namespace anonymous
251
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700252// ----------------------------------------------------------------------------
253// ref-counted object for callbacks
254class JNIDrmListener: public DrmListener
255{
256public:
257 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
258 ~JNIDrmListener();
259 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
260private:
261 JNIDrmListener();
262 jclass mClass; // Reference to MediaDrm class
263 jobject mObject; // Weak ref to MediaDrm Java object to call on
264};
265
266JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
267{
268 // Hold onto the MediaDrm class for use in calling the static method
269 // that posts events to the application thread.
270 jclass clazz = env->GetObjectClass(thiz);
271 if (clazz == NULL) {
272 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700273 jniThrowException(env, "java/lang/Exception",
274 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700275 return;
276 }
277 mClass = (jclass)env->NewGlobalRef(clazz);
278
279 // We use a weak reference so the MediaDrm object can be garbage collected.
280 // The reference is only used as a proxy for callbacks.
281 mObject = env->NewGlobalRef(weak_thiz);
282}
283
284JNIDrmListener::~JNIDrmListener()
285{
286 // remove global references
287 JNIEnv *env = AndroidRuntime::getJNIEnv();
288 env->DeleteGlobalRef(mObject);
289 env->DeleteGlobalRef(mClass);
290}
291
292void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
293 const Parcel *obj)
294{
Jeff Tinker74797f82015-03-31 15:44:34 -0700295 jint jwhat;
296 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700297
298 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700299 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700300 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700301 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700302 jeventType = gEventTypes.kEventProvisionRequired;
303 break;
304 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700305 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700306 jeventType = gEventTypes.kEventKeyRequired;
307 break;
308 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700309 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700310 jeventType = gEventTypes.kEventKeyExpired;
311 break;
312 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700313 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700314 jeventType = gEventTypes.kEventVendorDefined;
315 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800316 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700317 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800318 jeventType = gEventTypes.kEventSessionReclaimed;
319 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700320 case DrmPlugin::kDrmPluginEventExpirationUpdate:
321 jwhat = gEventWhat.kWhatExpirationUpdate;
322 break;
323 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700324 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700325 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800326 case DrmPlugin::kDrmPluginEventSessionLostState:
327 jwhat = gEventWhat.kWhatSessionLostState;
328 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700329 default:
330 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
331 return;
332 }
333
334 JNIEnv *env = AndroidRuntime::getJNIEnv();
335 if (obj && obj->dataSize() > 0) {
336 jobject jParcel = createJavaParcelObject(env);
337 if (jParcel != NULL) {
338 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
339 nativeParcel->setData(obj->data(), obj->dataSize());
340 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
Jeff Tinker74797f82015-03-31 15:44:34 -0700341 jwhat, jeventType, extra, jParcel);
Patrik2 Carlsson265551a2013-12-10 14:52:43 +0100342 env->DeleteLocalRef(jParcel);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700343 }
344 }
345
346 if (env->ExceptionCheck()) {
347 ALOGW("An exception occurred while notifying an event.");
348 LOGW_EX(env);
349 env->ExceptionClear();
350 }
351}
352
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700353static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
354 ALOGE("Illegal state exception: %s (%d)", msg, err);
355
356 jobject exception = env->NewObject(gFields.stateException.classId,
357 gFields.stateException.init, static_cast<int>(err),
358 env->NewStringUTF(msg));
359 env->Throw(static_cast<jthrowable>(exception));
360}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700361
Jeff Tinker20594d82018-12-12 08:31:22 -0800362static void throwSessionException(JNIEnv *env, const char *msg, status_t err) {
363 ALOGE("Session exception: %s (%d)", msg, err);
364
365 jint jErrorCode = 0;
366 switch(err) {
367 case ERROR_DRM_RESOURCE_CONTENTION:
368 jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
369 break;
370 default:
371 break;
372 }
373
374 jobject exception = env->NewObject(gFields.sessionException.classId,
375 gFields.sessionException.init, static_cast<int>(err),
376 env->NewStringUTF(msg));
377
378 env->SetIntField(exception, gFields.sessionException.errorCode, jErrorCode);
379 env->Throw(static_cast<jthrowable>(exception));
380}
381
382static bool isSessionException(status_t err) {
383 return err == ERROR_DRM_RESOURCE_CONTENTION;
384}
385
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800386static bool throwExceptionAsNecessary(
387 JNIEnv *env, status_t err, const char *msg = NULL) {
388
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700389 const char *drmMessage = NULL;
390
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700391 switch (err) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700392 case ERROR_DRM_UNKNOWN:
393 drmMessage = "General DRM error";
394 break;
395 case ERROR_DRM_NO_LICENSE:
396 drmMessage = "No license";
397 break;
398 case ERROR_DRM_LICENSE_EXPIRED:
399 drmMessage = "License expired";
400 break;
401 case ERROR_DRM_SESSION_NOT_OPENED:
402 drmMessage = "Session not opened";
403 break;
404 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
405 drmMessage = "Not initialized";
406 break;
407 case ERROR_DRM_DECRYPT:
408 drmMessage = "Decrypt error";
409 break;
410 case ERROR_DRM_CANNOT_HANDLE:
Jeff Tinkereb13c762017-11-01 15:29:38 -0700411 drmMessage = "Invalid parameter or data format";
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700412 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800413 case ERROR_DRM_INVALID_STATE:
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700414 drmMessage = "Invalid state";
415 break;
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700416 default:
417 break;
418 }
419
420 String8 vendorMessage;
421 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
Jeff Tinker29799862014-08-27 11:05:13 -0700422 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700423 drmMessage = vendorMessage.string();
424 }
425
Jeff Tinkereb13c762017-11-01 15:29:38 -0700426 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800427 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
428 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700429 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
430 jniThrowException(env, "android/media/NotProvisionedException", msg);
431 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700432 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
433 jniThrowException(env, "android/media/ResourceBusyException", msg);
434 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700435 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
436 jniThrowException(env, "android/media/DeniedByServerException", msg);
437 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700438 } else if (err == DEAD_OBJECT) {
439 jniThrowException(env, "android/media/MediaDrmResetException",
440 "mediaserver died");
441 return true;
Jeff Tinker20594d82018-12-12 08:31:22 -0800442 } else if (isSessionException(err)) {
443 throwSessionException(env, msg, err);
444 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800445 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700446 String8 errbuf;
447 if (drmMessage != NULL) {
448 if (msg == NULL) {
449 msg = drmMessage;
450 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700451 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700452 msg = errbuf.string();
453 }
454 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700455 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800456 return true;
457 }
458 return false;
459}
460
461static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000462 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800463 return jdrm ? jdrm->getDrm() : NULL;
464}
465
466JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800467 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
468 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800469 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800470 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700471 if (mDrm != NULL) {
472 mDrm->setListener(this);
473 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800474}
475
476JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800477 JNIEnv *env = AndroidRuntime::getJNIEnv();
478
479 env->DeleteWeakGlobalRef(mObject);
480 mObject = NULL;
481}
482
483// static
484sp<IDrm> JDrm::MakeDrm() {
485 sp<IServiceManager> sm = defaultServiceManager();
486
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700487 sp<IBinder> binder = sm->getService(String16("media.drm"));
488 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
489 if (service == NULL) {
490 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800491 }
492
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700493 sp<IDrm> drm = service->makeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800494 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
495 return NULL;
496 }
497
498 return drm;
499}
500
501// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800502sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800503 sp<IDrm> drm = MakeDrm();
504
505 if (drm == NULL) {
506 return NULL;
507 }
508
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800509 status_t err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800510
511 if (err != OK) {
512 return NULL;
513 }
514
515 return drm;
516}
517
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700518status_t JDrm::setListener(const sp<DrmListener>& listener) {
519 Mutex::Autolock lock(mLock);
520 mListener = listener;
521 return OK;
522}
523
524void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
525 sp<DrmListener> listener;
526 mLock.lock();
527 listener = mListener;
528 mLock.unlock();
529
530 if (listener != NULL) {
531 Mutex::Autolock lock(mNotifyLock);
532 listener->notify(eventType, extra, obj);
533 }
534}
535
Jeff Tinker600071c2014-04-11 16:11:15 -0700536void JDrm::disconnect() {
537 if (mDrm != NULL) {
538 mDrm->destroyPlugin();
539 mDrm.clear();
540 }
541}
542
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700543
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800544// static
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800545bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
546 DrmPlugin::SecurityLevel securityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800547 sp<IDrm> drm = MakeDrm();
548
549 if (drm == NULL) {
550 return false;
551 }
552
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800553 return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800554}
555
556status_t JDrm::initCheck() const {
557 return mDrm == NULL ? NO_INIT : OK;
558}
559
560// JNI conversion utilities
561static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
562 Vector<uint8_t> vector;
563 size_t length = env->GetArrayLength(byteArray);
564 vector.insertAt((size_t)0, length);
565 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
566 return vector;
567}
568
569static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
570 size_t length = vector.size();
571 jbyteArray result = env->NewByteArray(length);
572 if (result != NULL) {
573 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
574 }
575 return result;
576}
577
578static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800579 String8 result;
580
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700581 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800582 if (s) {
583 result = s;
584 env->ReleaseStringUTFChars(jstr, s);
585 }
586 return result;
587}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700588
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800589/*
590 import java.util.HashMap;
591 import java.util.Set;
592 import java.Map.Entry;
593 import jav.util.Iterator;
594
595 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800596 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800597 Iterator i = s.iterator();
598 Entry e = s.next();
599*/
600
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200601static KeyedVector<String8, String8> HashMapToKeyedVector(
602 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800603 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800604 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200605 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800606
607 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
608 if (entrySet) {
609 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
610 if (iterator) {
611 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
612 while (hasNext) {
613 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
614 if (entry) {
615 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200616 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700617 jniThrowException(env, "java/lang/IllegalArgumentException",
618 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200619 env->DeleteLocalRef(entry);
620 *pIsOK = false;
621 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800622 }
623 jstring jkey = static_cast<jstring>(obj);
624
625 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200626 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700627 jniThrowException(env, "java/lang/IllegalArgumentException",
628 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200629 env->DeleteLocalRef(entry);
630 *pIsOK = false;
631 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800632 }
633 jstring jvalue = static_cast<jstring>(obj);
634
635 String8 key = JStringToString8(env, jkey);
636 String8 value = JStringToString8(env, jvalue);
637 keyedVector.add(key, value);
638
639 env->DeleteLocalRef(jkey);
640 env->DeleteLocalRef(jvalue);
641 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
642 }
643 env->DeleteLocalRef(entry);
644 }
645 env->DeleteLocalRef(iterator);
646 }
647 env->DeleteLocalRef(entrySet);
648 }
649 return keyedVector;
650}
651
652static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800653 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800654 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
655 for (size_t i = 0; i < map.size(); ++i) {
656 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
657 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
658 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
659 env->DeleteLocalRef(jkey);
660 env->DeleteLocalRef(jvalue);
661 }
662 return hashMap;
663}
664
665static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800666 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800667 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800668 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800669 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800670 while (iter != list.end()) {
671 jbyteArray byteArray = VectorToJByteArray(env, *iter);
672 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
673 env->DeleteLocalRef(byteArray);
674 iter++;
675 }
676
677 return arrayList;
678}
679
680} // namespace android
681
682using namespace android;
683
684static sp<JDrm> setDrm(
685 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000686 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800687 if (drm != NULL) {
688 drm->incStrong(thiz);
689 }
690 if (old != NULL) {
691 old->decStrong(thiz);
692 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000693 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800694
695 return old;
696}
697
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800698static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800699 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700700 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800701 return false;
702 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800703 return true;
704}
705
706static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
707{
708 if (!CheckDrm(env, drm)) {
709 return false;
710 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800711
712 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700713 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800714 return false;
715 }
716 return true;
717}
718
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800719static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700720 sp<JDrm> drm = setDrm(env, thiz, NULL);
721 if (drm != NULL) {
722 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700723 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700724 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800725}
726
727static void android_media_MediaDrm_native_init(JNIEnv *env) {
728 jclass clazz;
729 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000730 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700731 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700732 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700733
734 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700735 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700736 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700737 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700738 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700739 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700740 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700741 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700742 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800743 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
744 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800745
Jeff Tinker74797f82015-03-31 15:44:34 -0700746 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
747 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
748 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
749 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700750 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
751 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800752 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
753 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700754
Jeff Tinker17b89222013-05-21 12:35:06 -0700755 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
756 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
757 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
758 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
759 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
760 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
761
Jeff Tinkere4095a82014-03-04 13:17:11 -0800762 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
763 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
764 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
765 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
766
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800767 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
768 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
769 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
770 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
771 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
772 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
773 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
774 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
775 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
776 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
777 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
778 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800779 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
780 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800781 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
782 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
783
784 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
785 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700786 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800787 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700788 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800789 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700790 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800791 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700792 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800793 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700794 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800795 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
796
Jeff Tinker55d26242018-10-10 16:10:43 -0700797 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_USABLE", "I");
798 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
799 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_INACTIVE", "I");
800 gOfflineLicenseStates.kOfflineLicenseStateInactive = env->GetStaticIntField(clazz, field);
801 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
802 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
803
804 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
805
Jeff Tinker2bca5252018-02-11 18:59:14 +0000806 jmethodID getMaxSecurityLevel;
807 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
808 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
809
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700810 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700811 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
812 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700813 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800814
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700815 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
816 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
817 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
818 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
819 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
820 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800821 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
822 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
823 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
824 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700825
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800826 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700827 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
828 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800829
Jeff Tinkere4095a82014-03-04 13:17:11 -0800830 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
831 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
832 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700833 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800834
Adam Stone94395c92018-01-30 12:07:00 -0800835 // Metrics-related fields and classes.
836 FIND_CLASS(clazz, "android/os/PersistableBundle");
837 jfieldID bundleCreatorId;
838 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
839 "Landroid/os/Parcelable$Creator;");
840 jobject bundleCreator;
841 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
842 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
843 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
844 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
845 "(Landroid/os/Parcel;)Ljava/lang/Object;");
846 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
847
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800848 FIND_CLASS(clazz, "java/util/ArrayList");
849 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
850 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
851
852 FIND_CLASS(clazz, "java/util/HashMap");
853 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
854 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
855 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
856 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
857 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
858
859 FIND_CLASS(clazz, "java/util/Set");
860 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
861
862 FIND_CLASS(clazz, "java/util/Iterator");
863 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
864 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
865
866 FIND_CLASS(clazz, "java/util/Map$Entry");
867 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
868 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800869
870 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700871 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800872
873 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700874 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800875
876 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700877 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700878
879 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
880 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
881 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800882
883 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
884 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
885 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
886 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
887
888 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
889 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800890}
891
892static void android_media_MediaDrm_native_setup(
893 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800894 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800895
896 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700897 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800898 return;
899 }
900
901 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
902
903 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700904 jniThrowException(env, "java/lang/IllegalArgumentException",
905 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800906 return;
907 }
908
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800909 String8 packageName;
910 if (jappPackageName == NULL) {
911 jniThrowException(env, "java/lang/IllegalArgumentException",
912 "application package name cannot be null");
913 return;
914 }
915
916 packageName = JStringToString8(env, jappPackageName);
917 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800918
919 status_t err = drm->initCheck();
920
921 if (err != OK) {
922 jniThrowException(
923 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700924 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800925 "Failed to instantiate drm object.");
926 return;
927 }
928
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700929 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
930 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800931 setDrm(env, thiz, drm);
932}
933
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800934DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
935 DrmPlugin::SecurityLevel level;
936
937 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
938 level = DrmPlugin::kSecurityLevelMax;
939 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
940 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
941 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
942 level = DrmPlugin::kSecurityLevelSwSecureDecode;
943 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
944 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
945 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
946 level = DrmPlugin::kSecurityLevelHwSecureDecode;
947 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
948 level = DrmPlugin::kSecurityLevelHwSecureAll;
949 } else {
950 level = DrmPlugin::kSecurityLevelUnknown;
951 }
952 return level;
953}
954
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800955static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800956 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
957 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800958
959 if (uuidObj == NULL) {
960 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
961 return false;
962 }
963
964 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
965
966 if (uuid.size() != 16) {
967 jniThrowException(
968 env,
969 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700970 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800971 return false;
972 }
973
Jeff Tinker7cda4912013-08-21 11:52:34 -0700974 String8 mimeType;
975 if (jmimeType != NULL) {
976 mimeType = JStringToString8(env, jmimeType);
977 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800978 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -0700979
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800980 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType, securityLevel);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800981}
982
983static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +0000984 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800985 sp<IDrm> drm = GetDrm(env, thiz);
986
Jeff Tinker55d26242018-10-10 16:10:43 -0700987 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800988 return NULL;
989 }
990
991 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800992 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
993 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +0000994 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
995 return NULL;
996 }
997
998 status_t err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800999
1000 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
1001 return NULL;
1002 }
1003
1004 return VectorToJByteArray(env, sessionId);
1005}
1006
1007static void android_media_MediaDrm_closeSession(
1008 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1009 sp<IDrm> drm = GetDrm(env, thiz);
1010
1011 if (!CheckSession(env, drm, jsessionId)) {
1012 return;
1013 }
1014
1015 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1016
1017 status_t err = drm->closeSession(sessionId);
1018
1019 throwExceptionAsNecessary(env, err, "Failed to close session");
1020}
1021
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001022static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001023 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001024 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001025 sp<IDrm> drm = GetDrm(env, thiz);
1026
1027 if (!CheckSession(env, drm, jsessionId)) {
1028 return NULL;
1029 }
1030
1031 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1032
1033 Vector<uint8_t> initData;
1034 if (jinitData != NULL) {
1035 initData = JByteArrayToVector(env, jinitData);
1036 }
1037
1038 String8 mimeType;
1039 if (jmimeType != NULL) {
1040 mimeType = JStringToString8(env, jmimeType);
1041 }
1042
Jeff Tinker17b89222013-05-21 12:35:06 -07001043 DrmPlugin::KeyType keyType;
1044 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1045 keyType = DrmPlugin::kKeyType_Streaming;
1046 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1047 keyType = DrmPlugin::kKeyType_Offline;
1048 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1049 keyType = DrmPlugin::kKeyType_Release;
1050 } else {
1051 jniThrowException(env, "java/lang/IllegalArgumentException",
1052 "invalid keyType");
1053 return NULL;
1054 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001055
1056 KeyedVector<String8, String8> optParams;
1057 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001058 bool isOK;
1059 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1060 if (!isOK) {
1061 return NULL;
1062 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001063 }
1064
1065 Vector<uint8_t> request;
1066 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001067 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001068
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001069 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001070 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001071
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001072 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001073 return NULL;
1074 }
1075
1076 // Fill out return obj
1077 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001078 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001079
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001080 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001081
1082 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001083 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001084 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001085 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001086
1087 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001088 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001089
1090 switch (keyRequestType) {
1091 case DrmPlugin::kKeyRequestType_Initial:
1092 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1093 gKeyRequestTypes.kKeyRequestTypeInitial);
1094 break;
1095 case DrmPlugin::kKeyRequestType_Renewal:
1096 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1097 gKeyRequestTypes.kKeyRequestTypeRenewal);
1098 break;
1099 case DrmPlugin::kKeyRequestType_Release:
1100 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1101 gKeyRequestTypes.kKeyRequestTypeRelease);
1102 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001103 case DrmPlugin::kKeyRequestType_None:
1104 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1105 gKeyRequestTypes.kKeyRequestTypeNone);
1106 break;
1107 case DrmPlugin::kKeyRequestType_Update:
1108 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1109 gKeyRequestTypes.kKeyRequestTypeUpdate);
1110 break;
1111
Jeff Tinker74797f82015-03-31 15:44:34 -07001112 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001113 throwStateException(env, "DRM plugin failure: unknown key request type",
1114 ERROR_DRM_UNKNOWN);
1115 break;
1116 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001117 }
1118
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001119 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001120}
1121
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001122static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001123 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1124 sp<IDrm> drm = GetDrm(env, thiz);
1125
1126 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001127 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001128 }
1129
1130 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1131
1132 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001133 jniThrowException(env, "java/lang/IllegalArgumentException",
1134 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001135 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001136 }
1137 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001138 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001139
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001140 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001141
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001142 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
1143 return NULL;
1144 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001145 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001146}
1147
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001148static void android_media_MediaDrm_removeKeys(
1149 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1150 sp<IDrm> drm = GetDrm(env, thiz);
1151
Jeff Tinker55d26242018-10-10 16:10:43 -07001152 if (!CheckDrm(env, drm)) {
1153 return;
1154 }
1155
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001156 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001157 jniThrowException(env, "java/lang/IllegalArgumentException",
1158 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001159 return;
1160 }
1161
1162 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1163
1164 status_t err = drm->removeKeys(keySetId);
1165
1166 throwExceptionAsNecessary(env, err, "Failed to remove keys");
1167}
1168
1169static void android_media_MediaDrm_restoreKeys(
1170 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1171 jbyteArray jkeysetId) {
1172
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001173 sp<IDrm> drm = GetDrm(env, thiz);
1174
1175 if (!CheckSession(env, drm, jsessionId)) {
1176 return;
1177 }
1178
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001179 if (jkeysetId == NULL) {
1180 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1181 return;
1182 }
1183
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001184 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001185 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001186
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001187 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001188
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001189 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001190}
1191
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001192static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001193 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1194 sp<IDrm> drm = GetDrm(env, thiz);
1195
1196 if (!CheckSession(env, drm, jsessionId)) {
1197 return NULL;
1198 }
1199 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1200
1201 KeyedVector<String8, String8> infoMap;
1202
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001203 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001204
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001205 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001206 return NULL;
1207 }
1208
1209 return KeyedVectorToHashMap(env, infoMap);
1210}
1211
Jeff Tinkere4095a82014-03-04 13:17:11 -08001212static jobject android_media_MediaDrm_getProvisionRequestNative(
1213 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001214 sp<IDrm> drm = GetDrm(env, thiz);
1215
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001216 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001217 return NULL;
1218 }
1219
1220 Vector<uint8_t> request;
1221 String8 defaultUrl;
1222
Jeff Tinkere4095a82014-03-04 13:17:11 -08001223 String8 certType;
1224 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1225 certType = "X.509";
1226 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1227 certType = "none";
1228 } else {
1229 certType = "invalid";
1230 }
1231
1232 String8 certAuthority = JStringToString8(env, jcertAuthority);
1233 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001234
1235 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
1236 return NULL;
1237 }
1238
1239 // Fill out return obj
1240 jclass clazz;
1241 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1242
1243 jobject provisionObj = NULL;
1244
1245 if (clazz) {
1246 provisionObj = env->AllocObject(clazz);
1247 jbyteArray jrequest = VectorToJByteArray(env, request);
1248 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1249
1250 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1251 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1252 }
1253
1254 return provisionObj;
1255}
1256
Jeff Tinkere4095a82014-03-04 13:17:11 -08001257static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001258 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1259 sp<IDrm> drm = GetDrm(env, thiz);
1260
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001261 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001262 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001263 }
1264
1265 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001266 jniThrowException(env, "java/lang/IllegalArgumentException",
1267 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001268 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001269 }
1270
1271 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001272 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001273
Jeff Tinkere4095a82014-03-04 13:17:11 -08001274 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1275
1276 // Fill out return obj
1277 jclass clazz = gFields.certificateClassId;
1278
1279 jobject certificateObj = NULL;
1280
1281 if (clazz && certificate.size() && wrappedKey.size()) {
1282 certificateObj = env->AllocObject(clazz);
1283 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1284 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1285
1286 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1287 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1288 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001289
1290 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001291 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001292}
1293
1294static jobject android_media_MediaDrm_getSecureStops(
1295 JNIEnv *env, jobject thiz) {
1296 sp<IDrm> drm = GetDrm(env, thiz);
1297
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001298 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001299 return NULL;
1300 }
1301
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001302 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001303
1304 status_t err = drm->getSecureStops(secureStops);
1305
1306 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1307 return NULL;
1308 }
1309
1310 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1311}
1312
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001313static jobject android_media_MediaDrm_getSecureStopIds(
1314 JNIEnv *env, jobject thiz) {
1315 sp<IDrm> drm = GetDrm(env, thiz);
1316
Jeff Tinker55d26242018-10-10 16:10:43 -07001317 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001318 return NULL;
1319 }
1320
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001321 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001322
1323 status_t err = drm->getSecureStopIds(secureStopIds);
1324
1325 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop Ids")) {
1326 return NULL;
1327 }
1328
1329 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1330}
1331
Jeff Tinker1b51c722014-10-31 00:54:26 -07001332static jbyteArray android_media_MediaDrm_getSecureStop(
1333 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1334 sp<IDrm> drm = GetDrm(env, thiz);
1335
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001336 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001337 return NULL;
1338 }
1339
1340 Vector<uint8_t> secureStop;
1341
1342 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1343
1344 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1345 return NULL;
1346 }
1347
1348 return VectorToJByteArray(env, secureStop);
1349}
1350
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001351static void android_media_MediaDrm_releaseSecureStops(
1352 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1353 sp<IDrm> drm = GetDrm(env, thiz);
1354
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001355 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001356 return;
1357 }
1358
1359 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1360
1361 status_t err = drm->releaseSecureStops(ssRelease);
1362
1363 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1364}
1365
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001366static void android_media_MediaDrm_removeSecureStop(
1367 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1368 sp<IDrm> drm = GetDrm(env, thiz);
1369
Jeff Tinker55d26242018-10-10 16:10:43 -07001370 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001371 return;
1372 }
1373
1374 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1375
1376 throwExceptionAsNecessary(env, err, "Failed to remove secure stop");
1377}
1378
1379static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001380 JNIEnv *env, jobject thiz) {
1381 sp<IDrm> drm = GetDrm(env, thiz);
1382
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001383 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001384 return;
1385 }
1386
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001387 status_t err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001388
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001389 throwExceptionAsNecessary(env, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001390}
1391
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001392
1393static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1394 switch(level) {
1395 case DrmPlugin::kHdcpLevelUnknown:
1396 return gHdcpLevels.kHdcpLevelUnknown;
1397 case DrmPlugin::kHdcpNone:
1398 return gHdcpLevels.kHdcpNone;
1399 case DrmPlugin::kHdcpV1:
1400 return gHdcpLevels.kHdcpV1;
1401 case DrmPlugin::kHdcpV2:
1402 return gHdcpLevels.kHdcpV2;
1403 case DrmPlugin::kHdcpV2_1:
1404 return gHdcpLevels.kHdcpV2_1;
1405 case DrmPlugin::kHdcpV2_2:
1406 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001407 case DrmPlugin::kHdcpV2_3:
1408 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001409 case DrmPlugin::kHdcpNoOutput:
1410 return gHdcpLevels.kHdcpNoOutput;
1411 }
1412 return gHdcpLevels.kHdcpNone;
1413}
1414
1415static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1416 jobject thiz) {
1417 sp<IDrm> drm = GetDrm(env, thiz);
1418
1419 if (!CheckDrm(env, drm)) {
1420 return gHdcpLevels.kHdcpNone;
1421 }
1422
1423 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1424 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1425
1426 status_t err = drm->getHdcpLevels(&connected, &max);
1427
1428 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1429 return gHdcpLevels.kHdcpLevelUnknown;
1430 }
1431 return HdcpLevelTojint(connected);
1432}
1433
1434static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1435 jobject thiz) {
1436 sp<IDrm> drm = GetDrm(env, thiz);
1437
1438 if (!CheckDrm(env, drm)) {
1439 return gHdcpLevels.kHdcpLevelUnknown;
1440 }
1441
1442 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1443 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1444
1445 status_t err = drm->getHdcpLevels(&connected, &max);
1446
1447 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1448 return gHdcpLevels.kHdcpLevelUnknown;
1449 }
1450 return HdcpLevelTojint(max);
1451}
1452
1453static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1454 jobject thiz) {
1455 sp<IDrm> drm = GetDrm(env, thiz);
1456
1457 if (!CheckDrm(env, drm)) {
1458 return 0;
1459 }
1460
1461 uint32_t open = 0, max = 0;
1462 status_t err = drm->getNumberOfSessions(&open, &max);
1463
1464 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1465 return 0;
1466 }
1467 return open;
1468}
1469
1470static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1471 jobject thiz) {
1472 sp<IDrm> drm = GetDrm(env, thiz);
1473
1474 if (!CheckDrm(env, drm)) {
1475 return 0;
1476 }
1477
1478 uint32_t open = 0, max = 0;
1479 status_t err = drm->getNumberOfSessions(&open, &max);
1480
1481 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1482 return 0;
1483 }
1484 return max;
1485}
1486
1487static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1488 jobject thiz, jbyteArray jsessionId) {
1489 sp<IDrm> drm = GetDrm(env, thiz);
1490
1491 if (!CheckSession(env, drm, jsessionId)) {
1492 return gSecurityLevels.kSecurityLevelUnknown;
1493 }
1494
1495 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1496
1497 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1498
1499 status_t err = drm->getSecurityLevel(sessionId, &level);
1500
1501 if (throwExceptionAsNecessary(env, err, "Failed to get security level")) {
1502 return gSecurityLevels.kSecurityLevelUnknown;
1503 }
1504
1505 switch(level) {
1506 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1507 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1508 case DrmPlugin::kSecurityLevelSwSecureDecode:
1509 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1510 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1511 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1512 case DrmPlugin::kSecurityLevelHwSecureDecode:
1513 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1514 case DrmPlugin::kSecurityLevelHwSecureAll:
1515 return gSecurityLevels.kSecurityLevelHwSecureAll;
1516 default:
1517 return gSecurityLevels.kSecurityLevelUnknown;
1518 }
1519}
1520
Jeff Tinker55d26242018-10-10 16:10:43 -07001521static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1522 JNIEnv *env, jobject thiz) {
1523 sp<IDrm> drm = GetDrm(env, thiz);
1524
1525 if (!CheckDrm(env, drm)) {
1526 return NULL;
1527 }
1528
1529 List<Vector<uint8_t> > keySetIds;
1530
1531 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1532
1533 if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) {
1534 return NULL;
1535 }
1536
1537 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1538}
1539
1540static void android_media_MediaDrm_removeOfflineLicense(
1541 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1542 sp<IDrm> drm = GetDrm(env, thiz);
1543
1544 if (!CheckDrm(env, drm)) {
1545 return;
1546 }
1547
1548 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1549
1550 throwExceptionAsNecessary(env, err, "Failed to remove offline license");
1551}
1552
1553static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1554 jobject thiz, jbyteArray jkeySetId) {
1555 sp<IDrm> drm = GetDrm(env, thiz);
1556
1557 if (!CheckDrm(env, drm)) {
1558 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1559 }
1560
1561 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1562
1563 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1564
1565 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1566
1567 if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) {
1568 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1569 }
1570
1571 switch(state) {
1572 case DrmPlugin::kOfflineLicenseStateUsable:
1573 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
1574 case DrmPlugin::kOfflineLicenseStateInactive:
1575 return gOfflineLicenseStates.kOfflineLicenseStateInactive;
1576 default:
1577 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1578 }
1579}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001580
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001581static jstring android_media_MediaDrm_getPropertyString(
1582 JNIEnv *env, jobject thiz, jstring jname) {
1583 sp<IDrm> drm = GetDrm(env, thiz);
1584
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001585 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001586 return NULL;
1587 }
1588
1589 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001590 jniThrowException(env, "java/lang/IllegalArgumentException",
1591 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001592 return NULL;
1593 }
1594
1595 String8 name = JStringToString8(env, jname);
1596 String8 value;
1597
1598 status_t err = drm->getPropertyString(name, value);
1599
1600 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1601 return NULL;
1602 }
1603
1604 return env->NewStringUTF(value.string());
1605}
1606
1607static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1608 JNIEnv *env, jobject thiz, jstring jname) {
1609 sp<IDrm> drm = GetDrm(env, thiz);
1610
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001611 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001612 return NULL;
1613 }
1614
1615 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001616 jniThrowException(env, "java/lang/IllegalArgumentException",
1617 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001618 return NULL;
1619 }
1620
1621 String8 name = JStringToString8(env, jname);
1622 Vector<uint8_t> value;
1623
1624 status_t err = drm->getPropertyByteArray(name, value);
1625
1626 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1627 return NULL;
1628 }
1629
1630 return VectorToJByteArray(env, value);
1631}
1632
1633static void android_media_MediaDrm_setPropertyString(
1634 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1635 sp<IDrm> drm = GetDrm(env, thiz);
1636
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001637 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001638 return;
1639 }
1640
Jeff Tinkereada5372013-05-21 12:48:14 -07001641 if (jname == NULL) {
1642 jniThrowException(env, "java/lang/IllegalArgumentException",
1643 "property name String is null");
1644 return;
1645 }
1646
1647 if (jvalue == NULL) {
1648 jniThrowException(env, "java/lang/IllegalArgumentException",
1649 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001650 return;
1651 }
1652
1653 String8 name = JStringToString8(env, jname);
1654 String8 value = JStringToString8(env, jvalue);
1655
1656 status_t err = drm->setPropertyString(name, value);
1657
1658 throwExceptionAsNecessary(env, err, "Failed to set property");
1659}
1660
1661static void android_media_MediaDrm_setPropertyByteArray(
1662 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1663 sp<IDrm> drm = GetDrm(env, thiz);
1664
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001665 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001666 return;
1667 }
1668
Jeff Tinkereada5372013-05-21 12:48:14 -07001669 if (jname == NULL) {
1670 jniThrowException(env, "java/lang/IllegalArgumentException",
1671 "property name String is null");
1672 return;
1673 }
1674
1675 if (jvalue == NULL) {
1676 jniThrowException(env, "java/lang/IllegalArgumentException",
1677 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001678 return;
1679 }
1680
1681 String8 name = JStringToString8(env, jname);
1682 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1683
1684 status_t err = drm->setPropertyByteArray(name, value);
1685
1686 throwExceptionAsNecessary(env, err, "Failed to set property");
1687}
1688
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001689static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001690 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001691 jstring jalgorithm) {
1692
1693 sp<IDrm> drm = GetDrm(env, jdrm);
1694
1695 if (!CheckSession(env, drm, jsessionId)) {
1696 return;
1697 }
1698
1699 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001700 jniThrowException(env, "java/lang/IllegalArgumentException",
1701 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001702 return;
1703 }
1704
1705 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1706 String8 algorithm = JStringToString8(env, jalgorithm);
1707
1708 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1709
1710 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1711}
1712
1713static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001714 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001715 jstring jalgorithm) {
1716
1717 sp<IDrm> drm = GetDrm(env, jdrm);
1718
1719 if (!CheckSession(env, drm, jsessionId)) {
1720 return;
1721 }
1722
1723 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001724 jniThrowException(env, "java/lang/IllegalArgumentException",
1725 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001726 return;
1727 }
1728
1729 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1730 String8 algorithm = JStringToString8(env, jalgorithm);
1731
1732 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1733
1734 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1735}
1736
1737
1738static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001739 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001740 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1741
1742 sp<IDrm> drm = GetDrm(env, jdrm);
1743
1744 if (!CheckSession(env, drm, jsessionId)) {
1745 return NULL;
1746 }
1747
1748 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001749 jniThrowException(env, "java/lang/IllegalArgumentException",
1750 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001751 return NULL;
1752 }
1753
1754 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1755 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1756 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1757 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1758 Vector<uint8_t> output;
1759
1760 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1761
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001762 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1763 return NULL;
1764 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001765
1766 return VectorToJByteArray(env, output);
1767}
1768
1769static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001770 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001771 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1772
1773 sp<IDrm> drm = GetDrm(env, jdrm);
1774
1775 if (!CheckSession(env, drm, jsessionId)) {
1776 return NULL;
1777 }
1778
1779 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001780 jniThrowException(env, "java/lang/IllegalArgumentException",
1781 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001782 return NULL;
1783 }
1784
1785 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1786 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1787 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1788 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1789 Vector<uint8_t> output;
1790
1791 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001792 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1793 return NULL;
1794 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001795
1796 return VectorToJByteArray(env, output);
1797}
1798
1799static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001800 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001801 jbyteArray jkeyId, jbyteArray jmessage) {
1802
1803 sp<IDrm> drm = GetDrm(env, jdrm);
1804
1805 if (!CheckSession(env, drm, jsessionId)) {
1806 return NULL;
1807 }
1808
1809 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001810 jniThrowException(env, "java/lang/IllegalArgumentException",
1811 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001812 return NULL;
1813 }
1814
1815 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1816 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1817 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1818 Vector<uint8_t> signature;
1819
1820 status_t err = drm->sign(sessionId, keyId, message, signature);
1821
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001822 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1823 return NULL;
1824 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001825
1826 return VectorToJByteArray(env, signature);
1827}
1828
1829static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001830 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001831 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1832
1833 sp<IDrm> drm = GetDrm(env, jdrm);
1834
1835 if (!CheckSession(env, drm, jsessionId)) {
1836 return false;
1837 }
1838
1839 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001840 jniThrowException(env, "java/lang/IllegalArgumentException",
1841 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001842 return false;
1843 }
1844
1845 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1846 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1847 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1848 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1849 bool match;
1850
1851 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1852
1853 throwExceptionAsNecessary(env, err, "Failed to verify");
1854 return match;
1855}
1856
Adam Stonec06e10e2017-12-19 12:54:33 -08001857static jobject
1858android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1859{
1860 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001861
1862 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001863 return NULL;
1864 }
1865
1866 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001867 PersistableBundle metrics;
1868 status_t err = drm->getMetrics(&metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001869 if (err != OK) {
1870 ALOGE("getMetrics failed: %d", (int)err);
1871 return (jobject) NULL;
1872 }
1873
Adam Stone94395c92018-01-30 12:07:00 -08001874 return nativeToJavaPersistableBundle(env, thiz, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001875}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001876
Jeff Tinkere4095a82014-03-04 13:17:11 -08001877static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001878 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001879 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1880
1881 sp<IDrm> drm = GetDrm(env, jdrm);
1882
1883 if (!CheckSession(env, drm, jsessionId)) {
1884 return NULL;
1885 }
1886
1887 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1888 jniThrowException(env, "java/lang/IllegalArgumentException",
1889 "required argument is null");
1890 return NULL;
1891 }
1892
1893 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1894 String8 algorithm = JStringToString8(env, jalgorithm);
1895 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1896 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1897 Vector<uint8_t> signature;
1898
1899 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1900
1901 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1902 return NULL;
1903 }
1904
1905 return VectorToJByteArray(env, signature);
1906}
1907
1908
Daniel Micay76f6a862015-09-19 17:31:01 -04001909static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001910 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
1911
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001912 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1913
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001914 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001915 (void *)android_media_MediaDrm_native_setup },
1916
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001917 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001918 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1919
Jeff Tinker2bca5252018-02-11 18:59:14 +00001920 { "openSession", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001921 (void *)android_media_MediaDrm_openSession },
1922
1923 { "closeSession", "([B)V",
1924 (void *)android_media_MediaDrm_closeSession },
1925
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001926 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1927 "Landroid/media/MediaDrm$KeyRequest;",
1928 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001929
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001930 { "provideKeyResponse", "([B[B)[B",
1931 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001932
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001933 { "removeKeys", "([B)V",
1934 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001935
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001936 { "restoreKeys", "([B[B)V",
1937 (void *)android_media_MediaDrm_restoreKeys },
1938
1939 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1940 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001941
Jeff Tinkere4095a82014-03-04 13:17:11 -08001942 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1943 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001944
Jeff Tinkere4095a82014-03-04 13:17:11 -08001945 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1946 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001947
1948 { "getSecureStops", "()Ljava/util/List;",
1949 (void *)android_media_MediaDrm_getSecureStops },
1950
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001951 { "getSecureStopIds", "()Ljava/util/List;",
1952 (void *)android_media_MediaDrm_getSecureStopIds },
1953
Jeff Tinker1b51c722014-10-31 00:54:26 -07001954 { "getSecureStop", "([B)[B",
1955 (void *)android_media_MediaDrm_getSecureStop },
1956
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001957 { "releaseSecureStops", "([B)V",
1958 (void *)android_media_MediaDrm_releaseSecureStops },
1959
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001960 { "removeSecureStop", "([B)V",
1961 (void *)android_media_MediaDrm_removeSecureStop },
1962
1963 { "removeAllSecureStops", "()V",
1964 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07001965
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001966 { "getConnectedHdcpLevel", "()I",
1967 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
1968
1969 { "getMaxHdcpLevel", "()I",
1970 (void *)android_media_MediaDrm_getMaxHdcpLevel },
1971
1972 { "getOpenSessionCount", "()I",
1973 (void *)android_media_MediaDrm_getOpenSessionCount },
1974
1975 { "getMaxSessionCount", "()I",
1976 (void *)android_media_MediaDrm_getMaxSessionCount },
1977
1978 { "getSecurityLevel", "([B)I",
1979 (void *)android_media_MediaDrm_getSecurityLevel },
1980
Jeff Tinker55d26242018-10-10 16:10:43 -07001981 { "removeOfflineLicense", "([B)V",
1982 (void *)android_media_MediaDrm_removeOfflineLicense },
1983
1984 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
1985 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
1986
1987 { "getOfflineLicenseState", "([B)I",
1988 (void *)android_media_MediaDrm_getOfflineLicenseState },
1989
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001990 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1991 (void *)android_media_MediaDrm_getPropertyString },
1992
1993 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1994 (void *)android_media_MediaDrm_getPropertyByteArray },
1995
1996 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1997 (void *)android_media_MediaDrm_setPropertyString },
1998
1999 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2000 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002001
2002 { "setCipherAlgorithmNative",
2003 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2004 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2005
2006 { "setMacAlgorithmNative",
2007 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2008 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2009
2010 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2011 (void *)android_media_MediaDrm_encryptNative },
2012
2013 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2014 (void *)android_media_MediaDrm_decryptNative },
2015
2016 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2017 (void *)android_media_MediaDrm_signNative },
2018
2019 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2020 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002021
2022 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2023 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002024
2025 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2026 (void *)android_media_MediaDrm_native_getMetrics },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002027};
2028
2029int register_android_media_Drm(JNIEnv *env) {
2030 return AndroidRuntime::registerNativeMethods(env,
2031 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2032}