blob: 42c5b052d4aade9ccfd12cc4a39a2046b0735a9a [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 Tinker7cda4912013-08-21 11:52:34 -0700545bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800546 sp<IDrm> drm = MakeDrm();
547
548 if (drm == NULL) {
549 return false;
550 }
551
Jeff Tinker7cda4912013-08-21 11:52:34 -0700552 return drm->isCryptoSchemeSupported(uuid, mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800553}
554
555status_t JDrm::initCheck() const {
556 return mDrm == NULL ? NO_INIT : OK;
557}
558
559// JNI conversion utilities
560static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
561 Vector<uint8_t> vector;
562 size_t length = env->GetArrayLength(byteArray);
563 vector.insertAt((size_t)0, length);
564 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
565 return vector;
566}
567
568static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
569 size_t length = vector.size();
570 jbyteArray result = env->NewByteArray(length);
571 if (result != NULL) {
572 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
573 }
574 return result;
575}
576
577static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800578 String8 result;
579
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700580 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800581 if (s) {
582 result = s;
583 env->ReleaseStringUTFChars(jstr, s);
584 }
585 return result;
586}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700587
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800588/*
589 import java.util.HashMap;
590 import java.util.Set;
591 import java.Map.Entry;
592 import jav.util.Iterator;
593
594 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800595 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800596 Iterator i = s.iterator();
597 Entry e = s.next();
598*/
599
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200600static KeyedVector<String8, String8> HashMapToKeyedVector(
601 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800602 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800603 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200604 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800605
606 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
607 if (entrySet) {
608 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
609 if (iterator) {
610 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
611 while (hasNext) {
612 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
613 if (entry) {
614 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200615 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700616 jniThrowException(env, "java/lang/IllegalArgumentException",
617 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200618 env->DeleteLocalRef(entry);
619 *pIsOK = false;
620 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800621 }
622 jstring jkey = static_cast<jstring>(obj);
623
624 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200625 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700626 jniThrowException(env, "java/lang/IllegalArgumentException",
627 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200628 env->DeleteLocalRef(entry);
629 *pIsOK = false;
630 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800631 }
632 jstring jvalue = static_cast<jstring>(obj);
633
634 String8 key = JStringToString8(env, jkey);
635 String8 value = JStringToString8(env, jvalue);
636 keyedVector.add(key, value);
637
638 env->DeleteLocalRef(jkey);
639 env->DeleteLocalRef(jvalue);
640 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
641 }
642 env->DeleteLocalRef(entry);
643 }
644 env->DeleteLocalRef(iterator);
645 }
646 env->DeleteLocalRef(entrySet);
647 }
648 return keyedVector;
649}
650
651static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800652 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800653 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
654 for (size_t i = 0; i < map.size(); ++i) {
655 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
656 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
657 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
658 env->DeleteLocalRef(jkey);
659 env->DeleteLocalRef(jvalue);
660 }
661 return hashMap;
662}
663
664static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800665 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800666 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800667 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800668 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800669 while (iter != list.end()) {
670 jbyteArray byteArray = VectorToJByteArray(env, *iter);
671 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
672 env->DeleteLocalRef(byteArray);
673 iter++;
674 }
675
676 return arrayList;
677}
678
679} // namespace android
680
681using namespace android;
682
683static sp<JDrm> setDrm(
684 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000685 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800686 if (drm != NULL) {
687 drm->incStrong(thiz);
688 }
689 if (old != NULL) {
690 old->decStrong(thiz);
691 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000692 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800693
694 return old;
695}
696
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800697static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800698 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700699 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800700 return false;
701 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800702 return true;
703}
704
705static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
706{
707 if (!CheckDrm(env, drm)) {
708 return false;
709 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800710
711 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700712 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800713 return false;
714 }
715 return true;
716}
717
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800718static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700719 sp<JDrm> drm = setDrm(env, thiz, NULL);
720 if (drm != NULL) {
721 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700722 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700723 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800724}
725
726static void android_media_MediaDrm_native_init(JNIEnv *env) {
727 jclass clazz;
728 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000729 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700730 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700731 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700732
733 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700734 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700735 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700736 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700737 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700738 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700739 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700740 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700741 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800742 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
743 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800744
Jeff Tinker74797f82015-03-31 15:44:34 -0700745 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
746 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
747 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
748 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700749 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
750 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800751 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
752 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700753
Jeff Tinker17b89222013-05-21 12:35:06 -0700754 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
755 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
756 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
757 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
758 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
759 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
760
Jeff Tinkere4095a82014-03-04 13:17:11 -0800761 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
762 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
763 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
764 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
765
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800766 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
767 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
768 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
769 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
770 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
771 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
772 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
773 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
774 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
775 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
776 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
777 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800778 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
779 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800780 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
781 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
782
783 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
784 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700785 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800786 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700787 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800788 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700789 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800790 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700791 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800792 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700793 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800794 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
795
Jeff Tinker55d26242018-10-10 16:10:43 -0700796 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_USABLE", "I");
797 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
798 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_INACTIVE", "I");
799 gOfflineLicenseStates.kOfflineLicenseStateInactive = env->GetStaticIntField(clazz, field);
800 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
801 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
802
803 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
804
Jeff Tinker2bca5252018-02-11 18:59:14 +0000805 jmethodID getMaxSecurityLevel;
806 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
807 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
808
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700809 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700810 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
811 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700812 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800813
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700814 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
815 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
816 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
817 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
818 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
819 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800820 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
821 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
822 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
823 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700824
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800825 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700826 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
827 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800828
Jeff Tinkere4095a82014-03-04 13:17:11 -0800829 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
830 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
831 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700832 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800833
Adam Stone94395c92018-01-30 12:07:00 -0800834 // Metrics-related fields and classes.
835 FIND_CLASS(clazz, "android/os/PersistableBundle");
836 jfieldID bundleCreatorId;
837 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
838 "Landroid/os/Parcelable$Creator;");
839 jobject bundleCreator;
840 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
841 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
842 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
843 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
844 "(Landroid/os/Parcel;)Ljava/lang/Object;");
845 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
846
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800847 FIND_CLASS(clazz, "java/util/ArrayList");
848 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
849 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
850
851 FIND_CLASS(clazz, "java/util/HashMap");
852 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
853 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
854 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
855 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
856 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
857
858 FIND_CLASS(clazz, "java/util/Set");
859 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
860
861 FIND_CLASS(clazz, "java/util/Iterator");
862 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
863 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
864
865 FIND_CLASS(clazz, "java/util/Map$Entry");
866 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
867 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800868
869 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700870 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800871
872 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700873 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800874
875 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700876 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700877
878 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
879 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
880 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800881
882 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
883 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
884 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
885 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
886
887 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
888 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800889}
890
891static void android_media_MediaDrm_native_setup(
892 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800893 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800894
895 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700896 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800897 return;
898 }
899
900 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
901
902 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700903 jniThrowException(env, "java/lang/IllegalArgumentException",
904 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800905 return;
906 }
907
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800908 String8 packageName;
909 if (jappPackageName == NULL) {
910 jniThrowException(env, "java/lang/IllegalArgumentException",
911 "application package name cannot be null");
912 return;
913 }
914
915 packageName = JStringToString8(env, jappPackageName);
916 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800917
918 status_t err = drm->initCheck();
919
920 if (err != OK) {
921 jniThrowException(
922 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700923 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800924 "Failed to instantiate drm object.");
925 return;
926 }
927
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700928 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
929 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800930 setDrm(env, thiz, drm);
931}
932
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800933static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800934 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800935
936 if (uuidObj == NULL) {
937 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
938 return false;
939 }
940
941 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
942
943 if (uuid.size() != 16) {
944 jniThrowException(
945 env,
946 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700947 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800948 return false;
949 }
950
Jeff Tinker7cda4912013-08-21 11:52:34 -0700951 String8 mimeType;
952 if (jmimeType != NULL) {
953 mimeType = JStringToString8(env, jmimeType);
954 }
955
956 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800957}
958
959static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +0000960 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800961 sp<IDrm> drm = GetDrm(env, thiz);
962
Jeff Tinker55d26242018-10-10 16:10:43 -0700963 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800964 return NULL;
965 }
966
967 Vector<uint8_t> sessionId;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000968 DrmPlugin::SecurityLevel level;
969
970 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
971 level = DrmPlugin::kSecurityLevelMax;
972 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
973 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
974 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
975 level = DrmPlugin::kSecurityLevelSwSecureDecode;
976 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
977 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
978 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
979 level = DrmPlugin::kSecurityLevelHwSecureDecode;
980 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
981 level = DrmPlugin::kSecurityLevelHwSecureAll;
982 } else {
983 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
984 return NULL;
985 }
986
987 status_t err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800988
989 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
990 return NULL;
991 }
992
993 return VectorToJByteArray(env, sessionId);
994}
995
996static void android_media_MediaDrm_closeSession(
997 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
998 sp<IDrm> drm = GetDrm(env, thiz);
999
1000 if (!CheckSession(env, drm, jsessionId)) {
1001 return;
1002 }
1003
1004 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1005
1006 status_t err = drm->closeSession(sessionId);
1007
1008 throwExceptionAsNecessary(env, err, "Failed to close session");
1009}
1010
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001011static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001012 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001013 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001014 sp<IDrm> drm = GetDrm(env, thiz);
1015
1016 if (!CheckSession(env, drm, jsessionId)) {
1017 return NULL;
1018 }
1019
1020 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1021
1022 Vector<uint8_t> initData;
1023 if (jinitData != NULL) {
1024 initData = JByteArrayToVector(env, jinitData);
1025 }
1026
1027 String8 mimeType;
1028 if (jmimeType != NULL) {
1029 mimeType = JStringToString8(env, jmimeType);
1030 }
1031
Jeff Tinker17b89222013-05-21 12:35:06 -07001032 DrmPlugin::KeyType keyType;
1033 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1034 keyType = DrmPlugin::kKeyType_Streaming;
1035 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1036 keyType = DrmPlugin::kKeyType_Offline;
1037 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1038 keyType = DrmPlugin::kKeyType_Release;
1039 } else {
1040 jniThrowException(env, "java/lang/IllegalArgumentException",
1041 "invalid keyType");
1042 return NULL;
1043 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001044
1045 KeyedVector<String8, String8> optParams;
1046 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001047 bool isOK;
1048 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1049 if (!isOK) {
1050 return NULL;
1051 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001052 }
1053
1054 Vector<uint8_t> request;
1055 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001056 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001057
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001058 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001059 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001060
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001061 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001062 return NULL;
1063 }
1064
1065 // Fill out return obj
1066 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001067 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001068
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001069 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001070
1071 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001072 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001073 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001074 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001075
1076 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001077 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001078
1079 switch (keyRequestType) {
1080 case DrmPlugin::kKeyRequestType_Initial:
1081 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1082 gKeyRequestTypes.kKeyRequestTypeInitial);
1083 break;
1084 case DrmPlugin::kKeyRequestType_Renewal:
1085 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1086 gKeyRequestTypes.kKeyRequestTypeRenewal);
1087 break;
1088 case DrmPlugin::kKeyRequestType_Release:
1089 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1090 gKeyRequestTypes.kKeyRequestTypeRelease);
1091 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001092 case DrmPlugin::kKeyRequestType_None:
1093 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1094 gKeyRequestTypes.kKeyRequestTypeNone);
1095 break;
1096 case DrmPlugin::kKeyRequestType_Update:
1097 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1098 gKeyRequestTypes.kKeyRequestTypeUpdate);
1099 break;
1100
Jeff Tinker74797f82015-03-31 15:44:34 -07001101 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001102 throwStateException(env, "DRM plugin failure: unknown key request type",
1103 ERROR_DRM_UNKNOWN);
1104 break;
1105 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001106 }
1107
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001108 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001109}
1110
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001111static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001112 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1113 sp<IDrm> drm = GetDrm(env, thiz);
1114
1115 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001116 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001117 }
1118
1119 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1120
1121 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001122 jniThrowException(env, "java/lang/IllegalArgumentException",
1123 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001124 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001125 }
1126 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001127 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001128
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001129 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001130
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001131 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
1132 return NULL;
1133 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001134 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001135}
1136
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001137static void android_media_MediaDrm_removeKeys(
1138 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1139 sp<IDrm> drm = GetDrm(env, thiz);
1140
Jeff Tinker55d26242018-10-10 16:10:43 -07001141 if (!CheckDrm(env, drm)) {
1142 return;
1143 }
1144
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001145 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001146 jniThrowException(env, "java/lang/IllegalArgumentException",
1147 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001148 return;
1149 }
1150
1151 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1152
1153 status_t err = drm->removeKeys(keySetId);
1154
1155 throwExceptionAsNecessary(env, err, "Failed to remove keys");
1156}
1157
1158static void android_media_MediaDrm_restoreKeys(
1159 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1160 jbyteArray jkeysetId) {
1161
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001162 sp<IDrm> drm = GetDrm(env, thiz);
1163
1164 if (!CheckSession(env, drm, jsessionId)) {
1165 return;
1166 }
1167
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001168 if (jkeysetId == NULL) {
1169 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1170 return;
1171 }
1172
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001173 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001174 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001175
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001176 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001177
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001178 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001179}
1180
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001181static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001182 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1183 sp<IDrm> drm = GetDrm(env, thiz);
1184
1185 if (!CheckSession(env, drm, jsessionId)) {
1186 return NULL;
1187 }
1188 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1189
1190 KeyedVector<String8, String8> infoMap;
1191
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001192 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001193
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001194 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001195 return NULL;
1196 }
1197
1198 return KeyedVectorToHashMap(env, infoMap);
1199}
1200
Jeff Tinkere4095a82014-03-04 13:17:11 -08001201static jobject android_media_MediaDrm_getProvisionRequestNative(
1202 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001203 sp<IDrm> drm = GetDrm(env, thiz);
1204
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001205 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001206 return NULL;
1207 }
1208
1209 Vector<uint8_t> request;
1210 String8 defaultUrl;
1211
Jeff Tinkere4095a82014-03-04 13:17:11 -08001212 String8 certType;
1213 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1214 certType = "X.509";
1215 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1216 certType = "none";
1217 } else {
1218 certType = "invalid";
1219 }
1220
1221 String8 certAuthority = JStringToString8(env, jcertAuthority);
1222 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001223
1224 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
1225 return NULL;
1226 }
1227
1228 // Fill out return obj
1229 jclass clazz;
1230 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1231
1232 jobject provisionObj = NULL;
1233
1234 if (clazz) {
1235 provisionObj = env->AllocObject(clazz);
1236 jbyteArray jrequest = VectorToJByteArray(env, request);
1237 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1238
1239 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1240 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1241 }
1242
1243 return provisionObj;
1244}
1245
Jeff Tinkere4095a82014-03-04 13:17:11 -08001246static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001247 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1248 sp<IDrm> drm = GetDrm(env, thiz);
1249
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001250 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001251 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001252 }
1253
1254 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001255 jniThrowException(env, "java/lang/IllegalArgumentException",
1256 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001257 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001258 }
1259
1260 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001261 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001262
Jeff Tinkere4095a82014-03-04 13:17:11 -08001263 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1264
1265 // Fill out return obj
1266 jclass clazz = gFields.certificateClassId;
1267
1268 jobject certificateObj = NULL;
1269
1270 if (clazz && certificate.size() && wrappedKey.size()) {
1271 certificateObj = env->AllocObject(clazz);
1272 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1273 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1274
1275 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1276 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1277 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001278
1279 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001280 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001281}
1282
1283static jobject android_media_MediaDrm_getSecureStops(
1284 JNIEnv *env, jobject thiz) {
1285 sp<IDrm> drm = GetDrm(env, thiz);
1286
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001287 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001288 return NULL;
1289 }
1290
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001291 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001292
1293 status_t err = drm->getSecureStops(secureStops);
1294
1295 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1296 return NULL;
1297 }
1298
1299 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1300}
1301
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001302static jobject android_media_MediaDrm_getSecureStopIds(
1303 JNIEnv *env, jobject thiz) {
1304 sp<IDrm> drm = GetDrm(env, thiz);
1305
Jeff Tinker55d26242018-10-10 16:10:43 -07001306 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001307 return NULL;
1308 }
1309
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001310 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001311
1312 status_t err = drm->getSecureStopIds(secureStopIds);
1313
1314 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop Ids")) {
1315 return NULL;
1316 }
1317
1318 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1319}
1320
Jeff Tinker1b51c722014-10-31 00:54:26 -07001321static jbyteArray android_media_MediaDrm_getSecureStop(
1322 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1323 sp<IDrm> drm = GetDrm(env, thiz);
1324
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001325 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001326 return NULL;
1327 }
1328
1329 Vector<uint8_t> secureStop;
1330
1331 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1332
1333 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1334 return NULL;
1335 }
1336
1337 return VectorToJByteArray(env, secureStop);
1338}
1339
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001340static void android_media_MediaDrm_releaseSecureStops(
1341 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1342 sp<IDrm> drm = GetDrm(env, thiz);
1343
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001344 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001345 return;
1346 }
1347
1348 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1349
1350 status_t err = drm->releaseSecureStops(ssRelease);
1351
1352 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1353}
1354
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001355static void android_media_MediaDrm_removeSecureStop(
1356 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1357 sp<IDrm> drm = GetDrm(env, thiz);
1358
Jeff Tinker55d26242018-10-10 16:10:43 -07001359 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001360 return;
1361 }
1362
1363 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1364
1365 throwExceptionAsNecessary(env, err, "Failed to remove secure stop");
1366}
1367
1368static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001369 JNIEnv *env, jobject thiz) {
1370 sp<IDrm> drm = GetDrm(env, thiz);
1371
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001372 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001373 return;
1374 }
1375
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001376 status_t err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001377
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001378 throwExceptionAsNecessary(env, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001379}
1380
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001381
1382static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1383 switch(level) {
1384 case DrmPlugin::kHdcpLevelUnknown:
1385 return gHdcpLevels.kHdcpLevelUnknown;
1386 case DrmPlugin::kHdcpNone:
1387 return gHdcpLevels.kHdcpNone;
1388 case DrmPlugin::kHdcpV1:
1389 return gHdcpLevels.kHdcpV1;
1390 case DrmPlugin::kHdcpV2:
1391 return gHdcpLevels.kHdcpV2;
1392 case DrmPlugin::kHdcpV2_1:
1393 return gHdcpLevels.kHdcpV2_1;
1394 case DrmPlugin::kHdcpV2_2:
1395 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001396 case DrmPlugin::kHdcpV2_3:
1397 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001398 case DrmPlugin::kHdcpNoOutput:
1399 return gHdcpLevels.kHdcpNoOutput;
1400 }
1401 return gHdcpLevels.kHdcpNone;
1402}
1403
1404static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1405 jobject thiz) {
1406 sp<IDrm> drm = GetDrm(env, thiz);
1407
1408 if (!CheckDrm(env, drm)) {
1409 return gHdcpLevels.kHdcpNone;
1410 }
1411
1412 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1413 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1414
1415 status_t err = drm->getHdcpLevels(&connected, &max);
1416
1417 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1418 return gHdcpLevels.kHdcpLevelUnknown;
1419 }
1420 return HdcpLevelTojint(connected);
1421}
1422
1423static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1424 jobject thiz) {
1425 sp<IDrm> drm = GetDrm(env, thiz);
1426
1427 if (!CheckDrm(env, drm)) {
1428 return gHdcpLevels.kHdcpLevelUnknown;
1429 }
1430
1431 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1432 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1433
1434 status_t err = drm->getHdcpLevels(&connected, &max);
1435
1436 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1437 return gHdcpLevels.kHdcpLevelUnknown;
1438 }
1439 return HdcpLevelTojint(max);
1440}
1441
1442static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1443 jobject thiz) {
1444 sp<IDrm> drm = GetDrm(env, thiz);
1445
1446 if (!CheckDrm(env, drm)) {
1447 return 0;
1448 }
1449
1450 uint32_t open = 0, max = 0;
1451 status_t err = drm->getNumberOfSessions(&open, &max);
1452
1453 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1454 return 0;
1455 }
1456 return open;
1457}
1458
1459static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1460 jobject thiz) {
1461 sp<IDrm> drm = GetDrm(env, thiz);
1462
1463 if (!CheckDrm(env, drm)) {
1464 return 0;
1465 }
1466
1467 uint32_t open = 0, max = 0;
1468 status_t err = drm->getNumberOfSessions(&open, &max);
1469
1470 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1471 return 0;
1472 }
1473 return max;
1474}
1475
1476static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1477 jobject thiz, jbyteArray jsessionId) {
1478 sp<IDrm> drm = GetDrm(env, thiz);
1479
1480 if (!CheckSession(env, drm, jsessionId)) {
1481 return gSecurityLevels.kSecurityLevelUnknown;
1482 }
1483
1484 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1485
1486 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1487
1488 status_t err = drm->getSecurityLevel(sessionId, &level);
1489
1490 if (throwExceptionAsNecessary(env, err, "Failed to get security level")) {
1491 return gSecurityLevels.kSecurityLevelUnknown;
1492 }
1493
1494 switch(level) {
1495 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1496 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1497 case DrmPlugin::kSecurityLevelSwSecureDecode:
1498 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1499 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1500 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1501 case DrmPlugin::kSecurityLevelHwSecureDecode:
1502 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1503 case DrmPlugin::kSecurityLevelHwSecureAll:
1504 return gSecurityLevels.kSecurityLevelHwSecureAll;
1505 default:
1506 return gSecurityLevels.kSecurityLevelUnknown;
1507 }
1508}
1509
Jeff Tinker55d26242018-10-10 16:10:43 -07001510static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1511 JNIEnv *env, jobject thiz) {
1512 sp<IDrm> drm = GetDrm(env, thiz);
1513
1514 if (!CheckDrm(env, drm)) {
1515 return NULL;
1516 }
1517
1518 List<Vector<uint8_t> > keySetIds;
1519
1520 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1521
1522 if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) {
1523 return NULL;
1524 }
1525
1526 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1527}
1528
1529static void android_media_MediaDrm_removeOfflineLicense(
1530 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1531 sp<IDrm> drm = GetDrm(env, thiz);
1532
1533 if (!CheckDrm(env, drm)) {
1534 return;
1535 }
1536
1537 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1538
1539 throwExceptionAsNecessary(env, err, "Failed to remove offline license");
1540}
1541
1542static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1543 jobject thiz, jbyteArray jkeySetId) {
1544 sp<IDrm> drm = GetDrm(env, thiz);
1545
1546 if (!CheckDrm(env, drm)) {
1547 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1548 }
1549
1550 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1551
1552 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1553
1554 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1555
1556 if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) {
1557 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1558 }
1559
1560 switch(state) {
1561 case DrmPlugin::kOfflineLicenseStateUsable:
1562 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
1563 case DrmPlugin::kOfflineLicenseStateInactive:
1564 return gOfflineLicenseStates.kOfflineLicenseStateInactive;
1565 default:
1566 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1567 }
1568}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001569
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001570static jstring android_media_MediaDrm_getPropertyString(
1571 JNIEnv *env, jobject thiz, jstring jname) {
1572 sp<IDrm> drm = GetDrm(env, thiz);
1573
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001574 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001575 return NULL;
1576 }
1577
1578 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001579 jniThrowException(env, "java/lang/IllegalArgumentException",
1580 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001581 return NULL;
1582 }
1583
1584 String8 name = JStringToString8(env, jname);
1585 String8 value;
1586
1587 status_t err = drm->getPropertyString(name, value);
1588
1589 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1590 return NULL;
1591 }
1592
1593 return env->NewStringUTF(value.string());
1594}
1595
1596static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1597 JNIEnv *env, jobject thiz, jstring jname) {
1598 sp<IDrm> drm = GetDrm(env, thiz);
1599
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001600 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001601 return NULL;
1602 }
1603
1604 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001605 jniThrowException(env, "java/lang/IllegalArgumentException",
1606 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001607 return NULL;
1608 }
1609
1610 String8 name = JStringToString8(env, jname);
1611 Vector<uint8_t> value;
1612
1613 status_t err = drm->getPropertyByteArray(name, value);
1614
1615 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1616 return NULL;
1617 }
1618
1619 return VectorToJByteArray(env, value);
1620}
1621
1622static void android_media_MediaDrm_setPropertyString(
1623 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1624 sp<IDrm> drm = GetDrm(env, thiz);
1625
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001626 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001627 return;
1628 }
1629
Jeff Tinkereada5372013-05-21 12:48:14 -07001630 if (jname == NULL) {
1631 jniThrowException(env, "java/lang/IllegalArgumentException",
1632 "property name String is null");
1633 return;
1634 }
1635
1636 if (jvalue == NULL) {
1637 jniThrowException(env, "java/lang/IllegalArgumentException",
1638 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001639 return;
1640 }
1641
1642 String8 name = JStringToString8(env, jname);
1643 String8 value = JStringToString8(env, jvalue);
1644
1645 status_t err = drm->setPropertyString(name, value);
1646
1647 throwExceptionAsNecessary(env, err, "Failed to set property");
1648}
1649
1650static void android_media_MediaDrm_setPropertyByteArray(
1651 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1652 sp<IDrm> drm = GetDrm(env, thiz);
1653
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001654 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001655 return;
1656 }
1657
Jeff Tinkereada5372013-05-21 12:48:14 -07001658 if (jname == NULL) {
1659 jniThrowException(env, "java/lang/IllegalArgumentException",
1660 "property name String is null");
1661 return;
1662 }
1663
1664 if (jvalue == NULL) {
1665 jniThrowException(env, "java/lang/IllegalArgumentException",
1666 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001667 return;
1668 }
1669
1670 String8 name = JStringToString8(env, jname);
1671 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1672
1673 status_t err = drm->setPropertyByteArray(name, value);
1674
1675 throwExceptionAsNecessary(env, err, "Failed to set property");
1676}
1677
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001678static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001679 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001680 jstring jalgorithm) {
1681
1682 sp<IDrm> drm = GetDrm(env, jdrm);
1683
1684 if (!CheckSession(env, drm, jsessionId)) {
1685 return;
1686 }
1687
1688 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001689 jniThrowException(env, "java/lang/IllegalArgumentException",
1690 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001691 return;
1692 }
1693
1694 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1695 String8 algorithm = JStringToString8(env, jalgorithm);
1696
1697 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1698
1699 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1700}
1701
1702static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001703 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001704 jstring jalgorithm) {
1705
1706 sp<IDrm> drm = GetDrm(env, jdrm);
1707
1708 if (!CheckSession(env, drm, jsessionId)) {
1709 return;
1710 }
1711
1712 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001713 jniThrowException(env, "java/lang/IllegalArgumentException",
1714 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001715 return;
1716 }
1717
1718 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1719 String8 algorithm = JStringToString8(env, jalgorithm);
1720
1721 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1722
1723 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1724}
1725
1726
1727static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001728 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001729 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1730
1731 sp<IDrm> drm = GetDrm(env, jdrm);
1732
1733 if (!CheckSession(env, drm, jsessionId)) {
1734 return NULL;
1735 }
1736
1737 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001738 jniThrowException(env, "java/lang/IllegalArgumentException",
1739 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001740 return NULL;
1741 }
1742
1743 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1744 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1745 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1746 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1747 Vector<uint8_t> output;
1748
1749 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1750
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001751 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1752 return NULL;
1753 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001754
1755 return VectorToJByteArray(env, output);
1756}
1757
1758static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001759 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001760 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1761
1762 sp<IDrm> drm = GetDrm(env, jdrm);
1763
1764 if (!CheckSession(env, drm, jsessionId)) {
1765 return NULL;
1766 }
1767
1768 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001769 jniThrowException(env, "java/lang/IllegalArgumentException",
1770 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001771 return NULL;
1772 }
1773
1774 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1775 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1776 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1777 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1778 Vector<uint8_t> output;
1779
1780 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001781 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1782 return NULL;
1783 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001784
1785 return VectorToJByteArray(env, output);
1786}
1787
1788static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001789 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001790 jbyteArray jkeyId, jbyteArray jmessage) {
1791
1792 sp<IDrm> drm = GetDrm(env, jdrm);
1793
1794 if (!CheckSession(env, drm, jsessionId)) {
1795 return NULL;
1796 }
1797
1798 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001799 jniThrowException(env, "java/lang/IllegalArgumentException",
1800 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001801 return NULL;
1802 }
1803
1804 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1805 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1806 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1807 Vector<uint8_t> signature;
1808
1809 status_t err = drm->sign(sessionId, keyId, message, signature);
1810
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001811 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1812 return NULL;
1813 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001814
1815 return VectorToJByteArray(env, signature);
1816}
1817
1818static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001819 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001820 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1821
1822 sp<IDrm> drm = GetDrm(env, jdrm);
1823
1824 if (!CheckSession(env, drm, jsessionId)) {
1825 return false;
1826 }
1827
1828 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001829 jniThrowException(env, "java/lang/IllegalArgumentException",
1830 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001831 return false;
1832 }
1833
1834 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1835 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1836 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1837 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1838 bool match;
1839
1840 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1841
1842 throwExceptionAsNecessary(env, err, "Failed to verify");
1843 return match;
1844}
1845
Adam Stonec06e10e2017-12-19 12:54:33 -08001846static jobject
1847android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1848{
1849 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001850
1851 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001852 return NULL;
1853 }
1854
1855 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001856 PersistableBundle metrics;
1857 status_t err = drm->getMetrics(&metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001858 if (err != OK) {
1859 ALOGE("getMetrics failed: %d", (int)err);
1860 return (jobject) NULL;
1861 }
1862
Adam Stone94395c92018-01-30 12:07:00 -08001863 return nativeToJavaPersistableBundle(env, thiz, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001864}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001865
Jeff Tinkere4095a82014-03-04 13:17:11 -08001866static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001867 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001868 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1869
1870 sp<IDrm> drm = GetDrm(env, jdrm);
1871
1872 if (!CheckSession(env, drm, jsessionId)) {
1873 return NULL;
1874 }
1875
1876 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1877 jniThrowException(env, "java/lang/IllegalArgumentException",
1878 "required argument is null");
1879 return NULL;
1880 }
1881
1882 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1883 String8 algorithm = JStringToString8(env, jalgorithm);
1884 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1885 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1886 Vector<uint8_t> signature;
1887
1888 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1889
1890 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1891 return NULL;
1892 }
1893
1894 return VectorToJByteArray(env, signature);
1895}
1896
1897
Daniel Micay76f6a862015-09-19 17:31:01 -04001898static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001899 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
1900
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001901 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1902
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001903 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001904 (void *)android_media_MediaDrm_native_setup },
1905
Jeff Tinker7cda4912013-08-21 11:52:34 -07001906 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001907 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1908
Jeff Tinker2bca5252018-02-11 18:59:14 +00001909 { "openSession", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001910 (void *)android_media_MediaDrm_openSession },
1911
1912 { "closeSession", "([B)V",
1913 (void *)android_media_MediaDrm_closeSession },
1914
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001915 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1916 "Landroid/media/MediaDrm$KeyRequest;",
1917 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001918
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001919 { "provideKeyResponse", "([B[B)[B",
1920 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001921
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001922 { "removeKeys", "([B)V",
1923 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001924
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001925 { "restoreKeys", "([B[B)V",
1926 (void *)android_media_MediaDrm_restoreKeys },
1927
1928 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1929 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001930
Jeff Tinkere4095a82014-03-04 13:17:11 -08001931 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1932 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001933
Jeff Tinkere4095a82014-03-04 13:17:11 -08001934 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1935 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001936
1937 { "getSecureStops", "()Ljava/util/List;",
1938 (void *)android_media_MediaDrm_getSecureStops },
1939
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001940 { "getSecureStopIds", "()Ljava/util/List;",
1941 (void *)android_media_MediaDrm_getSecureStopIds },
1942
Jeff Tinker1b51c722014-10-31 00:54:26 -07001943 { "getSecureStop", "([B)[B",
1944 (void *)android_media_MediaDrm_getSecureStop },
1945
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001946 { "releaseSecureStops", "([B)V",
1947 (void *)android_media_MediaDrm_releaseSecureStops },
1948
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001949 { "removeSecureStop", "([B)V",
1950 (void *)android_media_MediaDrm_removeSecureStop },
1951
1952 { "removeAllSecureStops", "()V",
1953 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07001954
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001955 { "getConnectedHdcpLevel", "()I",
1956 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
1957
1958 { "getMaxHdcpLevel", "()I",
1959 (void *)android_media_MediaDrm_getMaxHdcpLevel },
1960
1961 { "getOpenSessionCount", "()I",
1962 (void *)android_media_MediaDrm_getOpenSessionCount },
1963
1964 { "getMaxSessionCount", "()I",
1965 (void *)android_media_MediaDrm_getMaxSessionCount },
1966
1967 { "getSecurityLevel", "([B)I",
1968 (void *)android_media_MediaDrm_getSecurityLevel },
1969
Jeff Tinker55d26242018-10-10 16:10:43 -07001970 { "removeOfflineLicense", "([B)V",
1971 (void *)android_media_MediaDrm_removeOfflineLicense },
1972
1973 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
1974 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
1975
1976 { "getOfflineLicenseState", "([B)I",
1977 (void *)android_media_MediaDrm_getOfflineLicenseState },
1978
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001979 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1980 (void *)android_media_MediaDrm_getPropertyString },
1981
1982 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1983 (void *)android_media_MediaDrm_getPropertyByteArray },
1984
1985 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1986 (void *)android_media_MediaDrm_setPropertyString },
1987
1988 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1989 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001990
1991 { "setCipherAlgorithmNative",
1992 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1993 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1994
1995 { "setMacAlgorithmNative",
1996 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1997 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1998
1999 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2000 (void *)android_media_MediaDrm_encryptNative },
2001
2002 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2003 (void *)android_media_MediaDrm_decryptNative },
2004
2005 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2006 (void *)android_media_MediaDrm_signNative },
2007
2008 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2009 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002010
2011 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2012 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002013
2014 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2015 (void *)android_media_MediaDrm_native_getMetrics },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002016};
2017
2018int register_android_media_Drm(JNIEnv *env) {
2019 return AndroidRuntime::registerNativeMethods(env,
2020 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2021}