blob: d7ab854d63ba8496e20dcdf7e3029d0cc38ea3e6 [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;
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800178 jint kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -0700179 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 Tinker5de2e902019-01-25 23:09:36 -0800429 } else if (err == ERROR_UNSUPPORTED) {
430 jniThrowException(env, "java/lang/UnsupportedOperationException", msg);
431 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700432 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
433 jniThrowException(env, "android/media/NotProvisionedException", msg);
434 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700435 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
436 jniThrowException(env, "android/media/ResourceBusyException", msg);
437 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700438 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
439 jniThrowException(env, "android/media/DeniedByServerException", msg);
440 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700441 } else if (err == DEAD_OBJECT) {
442 jniThrowException(env, "android/media/MediaDrmResetException",
443 "mediaserver died");
444 return true;
Jeff Tinker20594d82018-12-12 08:31:22 -0800445 } else if (isSessionException(err)) {
446 throwSessionException(env, msg, err);
447 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800448 } else if (err != OK) {
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700449 String8 errbuf;
450 if (drmMessage != NULL) {
451 if (msg == NULL) {
452 msg = drmMessage;
453 } else {
Jeff Tinker29799862014-08-27 11:05:13 -0700454 errbuf = String8::format("%s: %s", msg, drmMessage);
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700455 msg = errbuf.string();
456 }
457 }
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700458 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800459 return true;
460 }
461 return false;
462}
463
464static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000465 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800466 return jdrm ? jdrm->getDrm() : NULL;
467}
468
469JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800470 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
471 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800472 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800473 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700474 if (mDrm != NULL) {
475 mDrm->setListener(this);
476 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800477}
478
479JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800480 JNIEnv *env = AndroidRuntime::getJNIEnv();
481
482 env->DeleteWeakGlobalRef(mObject);
483 mObject = NULL;
484}
485
486// static
487sp<IDrm> JDrm::MakeDrm() {
488 sp<IServiceManager> sm = defaultServiceManager();
489
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700490 sp<IBinder> binder = sm->getService(String16("media.drm"));
491 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
492 if (service == NULL) {
493 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800494 }
495
Jeff Tinkerd12b7c02016-04-22 17:50:33 -0700496 sp<IDrm> drm = service->makeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800497 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
498 return NULL;
499 }
500
501 return drm;
502}
503
504// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800505sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800506 sp<IDrm> drm = MakeDrm();
507
508 if (drm == NULL) {
509 return NULL;
510 }
511
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800512 status_t err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800513
514 if (err != OK) {
515 return NULL;
516 }
517
518 return drm;
519}
520
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700521status_t JDrm::setListener(const sp<DrmListener>& listener) {
522 Mutex::Autolock lock(mLock);
523 mListener = listener;
524 return OK;
525}
526
527void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
528 sp<DrmListener> listener;
529 mLock.lock();
530 listener = mListener;
531 mLock.unlock();
532
533 if (listener != NULL) {
534 Mutex::Autolock lock(mNotifyLock);
535 listener->notify(eventType, extra, obj);
536 }
537}
538
Jeff Tinker600071c2014-04-11 16:11:15 -0700539void JDrm::disconnect() {
540 if (mDrm != NULL) {
541 mDrm->destroyPlugin();
542 mDrm.clear();
543 }
544}
545
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700546
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800547// static
Jeff Tinker5de2e902019-01-25 23:09:36 -0800548status_t JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
549 DrmPlugin::SecurityLevel securityLevel, bool *isSupported) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800550 sp<IDrm> drm = MakeDrm();
551
552 if (drm == NULL) {
Jeff Tinker5de2e902019-01-25 23:09:36 -0800553 return BAD_VALUE;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800554 }
555
Jeff Tinker5de2e902019-01-25 23:09:36 -0800556 return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel, isSupported);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800557}
558
559status_t JDrm::initCheck() const {
560 return mDrm == NULL ? NO_INIT : OK;
561}
562
563// JNI conversion utilities
564static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
565 Vector<uint8_t> vector;
566 size_t length = env->GetArrayLength(byteArray);
567 vector.insertAt((size_t)0, length);
568 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
569 return vector;
570}
571
572static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
573 size_t length = vector.size();
574 jbyteArray result = env->NewByteArray(length);
575 if (result != NULL) {
576 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
577 }
578 return result;
579}
580
581static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800582 String8 result;
583
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700584 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800585 if (s) {
586 result = s;
587 env->ReleaseStringUTFChars(jstr, s);
588 }
589 return result;
590}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700591
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800592/*
593 import java.util.HashMap;
594 import java.util.Set;
595 import java.Map.Entry;
596 import jav.util.Iterator;
597
598 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800599 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800600 Iterator i = s.iterator();
601 Entry e = s.next();
602*/
603
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200604static KeyedVector<String8, String8> HashMapToKeyedVector(
605 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800606 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800607 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200608 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800609
610 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
611 if (entrySet) {
612 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
613 if (iterator) {
614 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
615 while (hasNext) {
616 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
617 if (entry) {
618 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200619 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700620 jniThrowException(env, "java/lang/IllegalArgumentException",
621 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200622 env->DeleteLocalRef(entry);
623 *pIsOK = false;
624 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800625 }
626 jstring jkey = static_cast<jstring>(obj);
627
628 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200629 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700630 jniThrowException(env, "java/lang/IllegalArgumentException",
631 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200632 env->DeleteLocalRef(entry);
633 *pIsOK = false;
634 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800635 }
636 jstring jvalue = static_cast<jstring>(obj);
637
638 String8 key = JStringToString8(env, jkey);
639 String8 value = JStringToString8(env, jvalue);
640 keyedVector.add(key, value);
641
642 env->DeleteLocalRef(jkey);
643 env->DeleteLocalRef(jvalue);
644 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
645 }
646 env->DeleteLocalRef(entry);
647 }
648 env->DeleteLocalRef(iterator);
649 }
650 env->DeleteLocalRef(entrySet);
651 }
652 return keyedVector;
653}
654
655static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800656 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800657 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
658 for (size_t i = 0; i < map.size(); ++i) {
659 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
660 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
661 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
662 env->DeleteLocalRef(jkey);
663 env->DeleteLocalRef(jvalue);
664 }
665 return hashMap;
666}
667
668static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800669 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800670 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800671 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800672 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800673 while (iter != list.end()) {
674 jbyteArray byteArray = VectorToJByteArray(env, *iter);
675 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
676 env->DeleteLocalRef(byteArray);
677 iter++;
678 }
679
680 return arrayList;
681}
682
683} // namespace android
684
685using namespace android;
686
687static sp<JDrm> setDrm(
688 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000689 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800690 if (drm != NULL) {
691 drm->incStrong(thiz);
692 }
693 if (old != NULL) {
694 old->decStrong(thiz);
695 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000696 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800697
698 return old;
699}
700
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800701static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800702 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700703 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800704 return false;
705 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800706 return true;
707}
708
709static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
710{
711 if (!CheckDrm(env, drm)) {
712 return false;
713 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800714
715 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700716 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800717 return false;
718 }
719 return true;
720}
721
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800722static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700723 sp<JDrm> drm = setDrm(env, thiz, NULL);
724 if (drm != NULL) {
725 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700726 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700727 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800728}
729
730static void android_media_MediaDrm_native_init(JNIEnv *env) {
731 jclass clazz;
732 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000733 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700734 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Jeff Tinker74797f82015-03-31 15:44:34 -0700735 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700736
737 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700738 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700739 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700740 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700741 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700742 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700743 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700744 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700745 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800746 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
747 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800748
Jeff Tinker74797f82015-03-31 15:44:34 -0700749 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
750 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
751 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
752 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700753 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
754 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800755 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
756 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700757
Jeff Tinker17b89222013-05-21 12:35:06 -0700758 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
759 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
760 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
761 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
762 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
763 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
764
Jeff Tinkere4095a82014-03-04 13:17:11 -0800765 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
766 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
767 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
768 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
769
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800770 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
771 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
772 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
773 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
774 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
775 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
776 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
777 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
778 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
779 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
780 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
781 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800782 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
783 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800784 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
785 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
786
787 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
788 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700789 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800790 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700791 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800792 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700793 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800794 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700795 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800796 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700797 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800798 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
799
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800800 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_USABLE", "I");
Jeff Tinker55d26242018-10-10 16:10:43 -0700801 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800802 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_RELEASED", "I");
803 gOfflineLicenseStates.kOfflineLicenseStateReleased = env->GetStaticIntField(clazz, field);
Jeff Tinker55d26242018-10-10 16:10:43 -0700804 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
805 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
806
807 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
808
Jeff Tinker2bca5252018-02-11 18:59:14 +0000809 jmethodID getMaxSecurityLevel;
810 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
811 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
812
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700813 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700814 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
815 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700816 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800817
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700818 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
819 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
820 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
821 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
822 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
823 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800824 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
825 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
826 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
827 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700828
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800829 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700830 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
831 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800832
Jeff Tinkere4095a82014-03-04 13:17:11 -0800833 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
834 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
835 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700836 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800837
Adam Stone94395c92018-01-30 12:07:00 -0800838 // Metrics-related fields and classes.
839 FIND_CLASS(clazz, "android/os/PersistableBundle");
840 jfieldID bundleCreatorId;
841 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
842 "Landroid/os/Parcelable$Creator;");
843 jobject bundleCreator;
844 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
845 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
846 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
847 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
848 "(Landroid/os/Parcel;)Ljava/lang/Object;");
849 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
850
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800851 FIND_CLASS(clazz, "java/util/ArrayList");
852 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
853 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
854
855 FIND_CLASS(clazz, "java/util/HashMap");
856 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
857 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
858 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
859 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
860 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
861
862 FIND_CLASS(clazz, "java/util/Set");
863 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
864
865 FIND_CLASS(clazz, "java/util/Iterator");
866 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
867 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
868
869 FIND_CLASS(clazz, "java/util/Map$Entry");
870 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
871 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800872
873 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700874 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800875
876 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700877 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800878
879 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700880 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700881
882 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
883 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
884 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800885
886 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
887 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
888 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
889 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
890
891 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
892 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800893}
894
895static void android_media_MediaDrm_native_setup(
896 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800897 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800898
899 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700900 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800901 return;
902 }
903
904 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
905
906 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700907 jniThrowException(env, "java/lang/IllegalArgumentException",
908 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800909 return;
910 }
911
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800912 String8 packageName;
913 if (jappPackageName == NULL) {
914 jniThrowException(env, "java/lang/IllegalArgumentException",
915 "application package name cannot be null");
916 return;
917 }
918
919 packageName = JStringToString8(env, jappPackageName);
920 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800921
922 status_t err = drm->initCheck();
923
924 if (err != OK) {
925 jniThrowException(
926 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700927 "android/media/UnsupportedSchemeException",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800928 "Failed to instantiate drm object.");
929 return;
930 }
931
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700932 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
933 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800934 setDrm(env, thiz, drm);
935}
936
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800937DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
938 DrmPlugin::SecurityLevel level;
939
940 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
941 level = DrmPlugin::kSecurityLevelMax;
942 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
943 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
944 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
945 level = DrmPlugin::kSecurityLevelSwSecureDecode;
946 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
947 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
948 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
949 level = DrmPlugin::kSecurityLevelHwSecureDecode;
950 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
951 level = DrmPlugin::kSecurityLevelHwSecureAll;
952 } else {
953 level = DrmPlugin::kSecurityLevelUnknown;
954 }
955 return level;
956}
957
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800958static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800959 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
960 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800961
962 if (uuidObj == NULL) {
963 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
964 return false;
965 }
966
967 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
968
969 if (uuid.size() != 16) {
970 jniThrowException(
971 env,
972 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -0700973 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800974 return false;
975 }
976
Jeff Tinker7cda4912013-08-21 11:52:34 -0700977 String8 mimeType;
978 if (jmimeType != NULL) {
979 mimeType = JStringToString8(env, jmimeType);
980 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800981 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -0700982
Jeff Tinker5de2e902019-01-25 23:09:36 -0800983 bool isSupported;
984 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
985 securityLevel, &isSupported);
986
987 if (throwExceptionAsNecessary(env, err, "Failed to query crypto scheme support")) {
988 return false;
989 }
990 return isSupported;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800991}
992
993static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +0000994 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800995 sp<IDrm> drm = GetDrm(env, thiz);
996
Jeff Tinker55d26242018-10-10 16:10:43 -0700997 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800998 return NULL;
999 }
1000
1001 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001002 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1003 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +00001004 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1005 return NULL;
1006 }
1007
1008 status_t err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001009
1010 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
1011 return NULL;
1012 }
1013
1014 return VectorToJByteArray(env, sessionId);
1015}
1016
1017static void android_media_MediaDrm_closeSession(
1018 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1019 sp<IDrm> drm = GetDrm(env, thiz);
1020
1021 if (!CheckSession(env, drm, jsessionId)) {
1022 return;
1023 }
1024
1025 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1026
1027 status_t err = drm->closeSession(sessionId);
1028
1029 throwExceptionAsNecessary(env, err, "Failed to close session");
1030}
1031
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001032static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001033 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001034 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001035 sp<IDrm> drm = GetDrm(env, thiz);
1036
1037 if (!CheckSession(env, drm, jsessionId)) {
1038 return NULL;
1039 }
1040
1041 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1042
1043 Vector<uint8_t> initData;
1044 if (jinitData != NULL) {
1045 initData = JByteArrayToVector(env, jinitData);
1046 }
1047
1048 String8 mimeType;
1049 if (jmimeType != NULL) {
1050 mimeType = JStringToString8(env, jmimeType);
1051 }
1052
Jeff Tinker17b89222013-05-21 12:35:06 -07001053 DrmPlugin::KeyType keyType;
1054 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1055 keyType = DrmPlugin::kKeyType_Streaming;
1056 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1057 keyType = DrmPlugin::kKeyType_Offline;
1058 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1059 keyType = DrmPlugin::kKeyType_Release;
1060 } else {
1061 jniThrowException(env, "java/lang/IllegalArgumentException",
1062 "invalid keyType");
1063 return NULL;
1064 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001065
1066 KeyedVector<String8, String8> optParams;
1067 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001068 bool isOK;
1069 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1070 if (!isOK) {
1071 return NULL;
1072 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001073 }
1074
1075 Vector<uint8_t> request;
1076 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001077 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001078
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001079 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001080 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001081
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001082 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001083 return NULL;
1084 }
1085
1086 // Fill out return obj
1087 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001088 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001089
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001090 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001091
1092 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001093 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001094 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001095 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001096
1097 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001098 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001099
1100 switch (keyRequestType) {
1101 case DrmPlugin::kKeyRequestType_Initial:
1102 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1103 gKeyRequestTypes.kKeyRequestTypeInitial);
1104 break;
1105 case DrmPlugin::kKeyRequestType_Renewal:
1106 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1107 gKeyRequestTypes.kKeyRequestTypeRenewal);
1108 break;
1109 case DrmPlugin::kKeyRequestType_Release:
1110 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1111 gKeyRequestTypes.kKeyRequestTypeRelease);
1112 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001113 case DrmPlugin::kKeyRequestType_None:
1114 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1115 gKeyRequestTypes.kKeyRequestTypeNone);
1116 break;
1117 case DrmPlugin::kKeyRequestType_Update:
1118 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1119 gKeyRequestTypes.kKeyRequestTypeUpdate);
1120 break;
1121
Jeff Tinker74797f82015-03-31 15:44:34 -07001122 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001123 throwStateException(env, "DRM plugin failure: unknown key request type",
1124 ERROR_DRM_UNKNOWN);
1125 break;
1126 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001127 }
1128
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001129 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001130}
1131
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001132static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001133 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1134 sp<IDrm> drm = GetDrm(env, thiz);
1135
1136 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001137 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001138 }
1139
1140 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1141
1142 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001143 jniThrowException(env, "java/lang/IllegalArgumentException",
1144 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001145 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001146 }
1147 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001148 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001149
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001150 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001151
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001152 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
1153 return NULL;
1154 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001155 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001156}
1157
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001158static void android_media_MediaDrm_removeKeys(
1159 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1160 sp<IDrm> drm = GetDrm(env, thiz);
1161
Jeff Tinker55d26242018-10-10 16:10:43 -07001162 if (!CheckDrm(env, drm)) {
1163 return;
1164 }
1165
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001166 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001167 jniThrowException(env, "java/lang/IllegalArgumentException",
1168 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001169 return;
1170 }
1171
1172 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1173
1174 status_t err = drm->removeKeys(keySetId);
1175
1176 throwExceptionAsNecessary(env, err, "Failed to remove keys");
1177}
1178
1179static void android_media_MediaDrm_restoreKeys(
1180 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1181 jbyteArray jkeysetId) {
1182
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001183 sp<IDrm> drm = GetDrm(env, thiz);
1184
1185 if (!CheckSession(env, drm, jsessionId)) {
1186 return;
1187 }
1188
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001189 if (jkeysetId == NULL) {
1190 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1191 return;
1192 }
1193
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001194 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001195 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001196
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001197 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001198
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001199 throwExceptionAsNecessary(env, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001200}
1201
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001202static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001203 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1204 sp<IDrm> drm = GetDrm(env, thiz);
1205
1206 if (!CheckSession(env, drm, jsessionId)) {
1207 return NULL;
1208 }
1209 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1210
1211 KeyedVector<String8, String8> infoMap;
1212
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001213 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001214
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001215 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001216 return NULL;
1217 }
1218
1219 return KeyedVectorToHashMap(env, infoMap);
1220}
1221
Jeff Tinkere4095a82014-03-04 13:17:11 -08001222static jobject android_media_MediaDrm_getProvisionRequestNative(
1223 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001224 sp<IDrm> drm = GetDrm(env, thiz);
1225
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001226 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001227 return NULL;
1228 }
1229
1230 Vector<uint8_t> request;
1231 String8 defaultUrl;
1232
Jeff Tinkere4095a82014-03-04 13:17:11 -08001233 String8 certType;
1234 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1235 certType = "X.509";
1236 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1237 certType = "none";
1238 } else {
1239 certType = "invalid";
1240 }
1241
1242 String8 certAuthority = JStringToString8(env, jcertAuthority);
1243 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001244
1245 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
1246 return NULL;
1247 }
1248
1249 // Fill out return obj
1250 jclass clazz;
1251 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1252
1253 jobject provisionObj = NULL;
1254
1255 if (clazz) {
1256 provisionObj = env->AllocObject(clazz);
1257 jbyteArray jrequest = VectorToJByteArray(env, request);
1258 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1259
1260 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1261 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1262 }
1263
1264 return provisionObj;
1265}
1266
Jeff Tinkere4095a82014-03-04 13:17:11 -08001267static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001268 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1269 sp<IDrm> drm = GetDrm(env, thiz);
1270
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001271 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001272 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001273 }
1274
1275 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001276 jniThrowException(env, "java/lang/IllegalArgumentException",
1277 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001278 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001279 }
1280
1281 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001282 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001283
Jeff Tinkere4095a82014-03-04 13:17:11 -08001284 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1285
1286 // Fill out return obj
1287 jclass clazz = gFields.certificateClassId;
1288
1289 jobject certificateObj = NULL;
1290
1291 if (clazz && certificate.size() && wrappedKey.size()) {
1292 certificateObj = env->AllocObject(clazz);
1293 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1294 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1295
1296 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1297 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1298 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001299
1300 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001301 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001302}
1303
1304static jobject android_media_MediaDrm_getSecureStops(
1305 JNIEnv *env, jobject thiz) {
1306 sp<IDrm> drm = GetDrm(env, thiz);
1307
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001308 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001309 return NULL;
1310 }
1311
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001312 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001313
1314 status_t err = drm->getSecureStops(secureStops);
1315
1316 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1317 return NULL;
1318 }
1319
1320 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1321}
1322
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001323static jobject android_media_MediaDrm_getSecureStopIds(
1324 JNIEnv *env, jobject thiz) {
1325 sp<IDrm> drm = GetDrm(env, thiz);
1326
Jeff Tinker55d26242018-10-10 16:10:43 -07001327 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001328 return NULL;
1329 }
1330
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001331 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001332
1333 status_t err = drm->getSecureStopIds(secureStopIds);
1334
1335 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop Ids")) {
1336 return NULL;
1337 }
1338
1339 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1340}
1341
Jeff Tinker1b51c722014-10-31 00:54:26 -07001342static jbyteArray android_media_MediaDrm_getSecureStop(
1343 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1344 sp<IDrm> drm = GetDrm(env, thiz);
1345
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001346 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001347 return NULL;
1348 }
1349
1350 Vector<uint8_t> secureStop;
1351
1352 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1353
1354 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1355 return NULL;
1356 }
1357
1358 return VectorToJByteArray(env, secureStop);
1359}
1360
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001361static void android_media_MediaDrm_releaseSecureStops(
1362 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1363 sp<IDrm> drm = GetDrm(env, thiz);
1364
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001365 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001366 return;
1367 }
1368
1369 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1370
1371 status_t err = drm->releaseSecureStops(ssRelease);
1372
1373 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1374}
1375
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001376static void android_media_MediaDrm_removeSecureStop(
1377 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1378 sp<IDrm> drm = GetDrm(env, thiz);
1379
Jeff Tinker55d26242018-10-10 16:10:43 -07001380 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001381 return;
1382 }
1383
1384 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1385
1386 throwExceptionAsNecessary(env, err, "Failed to remove secure stop");
1387}
1388
1389static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001390 JNIEnv *env, jobject thiz) {
1391 sp<IDrm> drm = GetDrm(env, thiz);
1392
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001393 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001394 return;
1395 }
1396
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001397 status_t err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001398
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001399 throwExceptionAsNecessary(env, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001400}
1401
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001402
1403static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1404 switch(level) {
1405 case DrmPlugin::kHdcpLevelUnknown:
1406 return gHdcpLevels.kHdcpLevelUnknown;
1407 case DrmPlugin::kHdcpNone:
1408 return gHdcpLevels.kHdcpNone;
1409 case DrmPlugin::kHdcpV1:
1410 return gHdcpLevels.kHdcpV1;
1411 case DrmPlugin::kHdcpV2:
1412 return gHdcpLevels.kHdcpV2;
1413 case DrmPlugin::kHdcpV2_1:
1414 return gHdcpLevels.kHdcpV2_1;
1415 case DrmPlugin::kHdcpV2_2:
1416 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001417 case DrmPlugin::kHdcpV2_3:
1418 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001419 case DrmPlugin::kHdcpNoOutput:
1420 return gHdcpLevels.kHdcpNoOutput;
1421 }
1422 return gHdcpLevels.kHdcpNone;
1423}
1424
1425static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1426 jobject thiz) {
1427 sp<IDrm> drm = GetDrm(env, thiz);
1428
1429 if (!CheckDrm(env, drm)) {
1430 return gHdcpLevels.kHdcpNone;
1431 }
1432
1433 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1434 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1435
1436 status_t err = drm->getHdcpLevels(&connected, &max);
1437
1438 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1439 return gHdcpLevels.kHdcpLevelUnknown;
1440 }
1441 return HdcpLevelTojint(connected);
1442}
1443
1444static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1445 jobject thiz) {
1446 sp<IDrm> drm = GetDrm(env, thiz);
1447
1448 if (!CheckDrm(env, drm)) {
1449 return gHdcpLevels.kHdcpLevelUnknown;
1450 }
1451
1452 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1453 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1454
1455 status_t err = drm->getHdcpLevels(&connected, &max);
1456
1457 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1458 return gHdcpLevels.kHdcpLevelUnknown;
1459 }
1460 return HdcpLevelTojint(max);
1461}
1462
1463static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1464 jobject thiz) {
1465 sp<IDrm> drm = GetDrm(env, thiz);
1466
1467 if (!CheckDrm(env, drm)) {
1468 return 0;
1469 }
1470
1471 uint32_t open = 0, max = 0;
1472 status_t err = drm->getNumberOfSessions(&open, &max);
1473
1474 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1475 return 0;
1476 }
1477 return open;
1478}
1479
1480static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1481 jobject thiz) {
1482 sp<IDrm> drm = GetDrm(env, thiz);
1483
1484 if (!CheckDrm(env, drm)) {
1485 return 0;
1486 }
1487
1488 uint32_t open = 0, max = 0;
1489 status_t err = drm->getNumberOfSessions(&open, &max);
1490
1491 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1492 return 0;
1493 }
1494 return max;
1495}
1496
1497static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1498 jobject thiz, jbyteArray jsessionId) {
1499 sp<IDrm> drm = GetDrm(env, thiz);
1500
1501 if (!CheckSession(env, drm, jsessionId)) {
1502 return gSecurityLevels.kSecurityLevelUnknown;
1503 }
1504
1505 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1506
1507 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1508
1509 status_t err = drm->getSecurityLevel(sessionId, &level);
1510
1511 if (throwExceptionAsNecessary(env, err, "Failed to get security level")) {
1512 return gSecurityLevels.kSecurityLevelUnknown;
1513 }
1514
1515 switch(level) {
1516 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1517 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1518 case DrmPlugin::kSecurityLevelSwSecureDecode:
1519 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1520 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1521 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1522 case DrmPlugin::kSecurityLevelHwSecureDecode:
1523 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1524 case DrmPlugin::kSecurityLevelHwSecureAll:
1525 return gSecurityLevels.kSecurityLevelHwSecureAll;
1526 default:
1527 return gSecurityLevels.kSecurityLevelUnknown;
1528 }
1529}
1530
Jeff Tinker55d26242018-10-10 16:10:43 -07001531static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1532 JNIEnv *env, jobject thiz) {
1533 sp<IDrm> drm = GetDrm(env, thiz);
1534
1535 if (!CheckDrm(env, drm)) {
1536 return NULL;
1537 }
1538
1539 List<Vector<uint8_t> > keySetIds;
1540
1541 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1542
1543 if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) {
1544 return NULL;
1545 }
1546
1547 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1548}
1549
1550static void android_media_MediaDrm_removeOfflineLicense(
1551 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1552 sp<IDrm> drm = GetDrm(env, thiz);
1553
1554 if (!CheckDrm(env, drm)) {
1555 return;
1556 }
1557
1558 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1559
1560 throwExceptionAsNecessary(env, err, "Failed to remove offline license");
1561}
1562
1563static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1564 jobject thiz, jbyteArray jkeySetId) {
1565 sp<IDrm> drm = GetDrm(env, thiz);
1566
1567 if (!CheckDrm(env, drm)) {
1568 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1569 }
1570
1571 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1572
1573 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1574
1575 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1576
1577 if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) {
1578 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1579 }
1580
1581 switch(state) {
1582 case DrmPlugin::kOfflineLicenseStateUsable:
1583 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -08001584 case DrmPlugin::kOfflineLicenseStateReleased:
1585 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -07001586 default:
1587 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1588 }
1589}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001590
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001591static jstring android_media_MediaDrm_getPropertyString(
1592 JNIEnv *env, jobject thiz, jstring jname) {
1593 sp<IDrm> drm = GetDrm(env, thiz);
1594
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001595 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001596 return NULL;
1597 }
1598
1599 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001600 jniThrowException(env, "java/lang/IllegalArgumentException",
1601 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001602 return NULL;
1603 }
1604
1605 String8 name = JStringToString8(env, jname);
1606 String8 value;
1607
1608 status_t err = drm->getPropertyString(name, value);
1609
1610 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1611 return NULL;
1612 }
1613
1614 return env->NewStringUTF(value.string());
1615}
1616
1617static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1618 JNIEnv *env, jobject thiz, jstring jname) {
1619 sp<IDrm> drm = GetDrm(env, thiz);
1620
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001621 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001622 return NULL;
1623 }
1624
1625 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001626 jniThrowException(env, "java/lang/IllegalArgumentException",
1627 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001628 return NULL;
1629 }
1630
1631 String8 name = JStringToString8(env, jname);
1632 Vector<uint8_t> value;
1633
1634 status_t err = drm->getPropertyByteArray(name, value);
1635
1636 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1637 return NULL;
1638 }
1639
1640 return VectorToJByteArray(env, value);
1641}
1642
1643static void android_media_MediaDrm_setPropertyString(
1644 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1645 sp<IDrm> drm = GetDrm(env, thiz);
1646
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001647 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001648 return;
1649 }
1650
Jeff Tinkereada5372013-05-21 12:48:14 -07001651 if (jname == NULL) {
1652 jniThrowException(env, "java/lang/IllegalArgumentException",
1653 "property name String is null");
1654 return;
1655 }
1656
1657 if (jvalue == NULL) {
1658 jniThrowException(env, "java/lang/IllegalArgumentException",
1659 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001660 return;
1661 }
1662
1663 String8 name = JStringToString8(env, jname);
1664 String8 value = JStringToString8(env, jvalue);
1665
1666 status_t err = drm->setPropertyString(name, value);
1667
1668 throwExceptionAsNecessary(env, err, "Failed to set property");
1669}
1670
1671static void android_media_MediaDrm_setPropertyByteArray(
1672 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1673 sp<IDrm> drm = GetDrm(env, thiz);
1674
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001675 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001676 return;
1677 }
1678
Jeff Tinkereada5372013-05-21 12:48:14 -07001679 if (jname == NULL) {
1680 jniThrowException(env, "java/lang/IllegalArgumentException",
1681 "property name String is null");
1682 return;
1683 }
1684
1685 if (jvalue == NULL) {
1686 jniThrowException(env, "java/lang/IllegalArgumentException",
1687 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001688 return;
1689 }
1690
1691 String8 name = JStringToString8(env, jname);
1692 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1693
1694 status_t err = drm->setPropertyByteArray(name, value);
1695
1696 throwExceptionAsNecessary(env, err, "Failed to set property");
1697}
1698
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001699static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001700 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001701 jstring jalgorithm) {
1702
1703 sp<IDrm> drm = GetDrm(env, jdrm);
1704
1705 if (!CheckSession(env, drm, jsessionId)) {
1706 return;
1707 }
1708
1709 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001710 jniThrowException(env, "java/lang/IllegalArgumentException",
1711 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001712 return;
1713 }
1714
1715 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1716 String8 algorithm = JStringToString8(env, jalgorithm);
1717
1718 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1719
1720 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1721}
1722
1723static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001724 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001725 jstring jalgorithm) {
1726
1727 sp<IDrm> drm = GetDrm(env, jdrm);
1728
1729 if (!CheckSession(env, drm, jsessionId)) {
1730 return;
1731 }
1732
1733 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001734 jniThrowException(env, "java/lang/IllegalArgumentException",
1735 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001736 return;
1737 }
1738
1739 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1740 String8 algorithm = JStringToString8(env, jalgorithm);
1741
1742 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1743
1744 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1745}
1746
1747
1748static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001749 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001750 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1751
1752 sp<IDrm> drm = GetDrm(env, jdrm);
1753
1754 if (!CheckSession(env, drm, jsessionId)) {
1755 return NULL;
1756 }
1757
1758 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001759 jniThrowException(env, "java/lang/IllegalArgumentException",
1760 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001761 return NULL;
1762 }
1763
1764 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1765 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1766 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1767 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1768 Vector<uint8_t> output;
1769
1770 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1771
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001772 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1773 return NULL;
1774 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001775
1776 return VectorToJByteArray(env, output);
1777}
1778
1779static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001780 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001781 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1782
1783 sp<IDrm> drm = GetDrm(env, jdrm);
1784
1785 if (!CheckSession(env, drm, jsessionId)) {
1786 return NULL;
1787 }
1788
1789 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001790 jniThrowException(env, "java/lang/IllegalArgumentException",
1791 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001792 return NULL;
1793 }
1794
1795 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1796 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1797 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1798 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1799 Vector<uint8_t> output;
1800
1801 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001802 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1803 return NULL;
1804 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001805
1806 return VectorToJByteArray(env, output);
1807}
1808
1809static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001810 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001811 jbyteArray jkeyId, jbyteArray jmessage) {
1812
1813 sp<IDrm> drm = GetDrm(env, jdrm);
1814
1815 if (!CheckSession(env, drm, jsessionId)) {
1816 return NULL;
1817 }
1818
1819 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001820 jniThrowException(env, "java/lang/IllegalArgumentException",
1821 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001822 return NULL;
1823 }
1824
1825 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1826 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1827 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1828 Vector<uint8_t> signature;
1829
1830 status_t err = drm->sign(sessionId, keyId, message, signature);
1831
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001832 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1833 return NULL;
1834 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001835
1836 return VectorToJByteArray(env, signature);
1837}
1838
1839static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001840 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001841 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1842
1843 sp<IDrm> drm = GetDrm(env, jdrm);
1844
1845 if (!CheckSession(env, drm, jsessionId)) {
1846 return false;
1847 }
1848
1849 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001850 jniThrowException(env, "java/lang/IllegalArgumentException",
1851 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001852 return false;
1853 }
1854
1855 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1856 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1857 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1858 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1859 bool match;
1860
1861 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1862
1863 throwExceptionAsNecessary(env, err, "Failed to verify");
1864 return match;
1865}
1866
Adam Stonec06e10e2017-12-19 12:54:33 -08001867static jobject
1868android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1869{
1870 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001871
1872 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001873 return NULL;
1874 }
1875
1876 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001877 PersistableBundle metrics;
1878 status_t err = drm->getMetrics(&metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001879 if (err != OK) {
1880 ALOGE("getMetrics failed: %d", (int)err);
1881 return (jobject) NULL;
1882 }
1883
Adam Stone94395c92018-01-30 12:07:00 -08001884 return nativeToJavaPersistableBundle(env, thiz, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001885}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001886
Jeff Tinkere4095a82014-03-04 13:17:11 -08001887static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001888 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001889 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1890
1891 sp<IDrm> drm = GetDrm(env, jdrm);
1892
1893 if (!CheckSession(env, drm, jsessionId)) {
1894 return NULL;
1895 }
1896
1897 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1898 jniThrowException(env, "java/lang/IllegalArgumentException",
1899 "required argument is null");
1900 return NULL;
1901 }
1902
1903 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1904 String8 algorithm = JStringToString8(env, jalgorithm);
1905 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1906 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1907 Vector<uint8_t> signature;
1908
1909 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1910
1911 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1912 return NULL;
1913 }
1914
1915 return VectorToJByteArray(env, signature);
1916}
1917
1918
Daniel Micay76f6a862015-09-19 17:31:01 -04001919static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001920 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
1921
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001922 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1923
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001924 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001925 (void *)android_media_MediaDrm_native_setup },
1926
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001927 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001928 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1929
Jeff Tinker2bca5252018-02-11 18:59:14 +00001930 { "openSession", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001931 (void *)android_media_MediaDrm_openSession },
1932
1933 { "closeSession", "([B)V",
1934 (void *)android_media_MediaDrm_closeSession },
1935
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001936 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1937 "Landroid/media/MediaDrm$KeyRequest;",
1938 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001939
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001940 { "provideKeyResponse", "([B[B)[B",
1941 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001942
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001943 { "removeKeys", "([B)V",
1944 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001945
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001946 { "restoreKeys", "([B[B)V",
1947 (void *)android_media_MediaDrm_restoreKeys },
1948
1949 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1950 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001951
Jeff Tinkere4095a82014-03-04 13:17:11 -08001952 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1953 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001954
Jeff Tinkere4095a82014-03-04 13:17:11 -08001955 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1956 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001957
1958 { "getSecureStops", "()Ljava/util/List;",
1959 (void *)android_media_MediaDrm_getSecureStops },
1960
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001961 { "getSecureStopIds", "()Ljava/util/List;",
1962 (void *)android_media_MediaDrm_getSecureStopIds },
1963
Jeff Tinker1b51c722014-10-31 00:54:26 -07001964 { "getSecureStop", "([B)[B",
1965 (void *)android_media_MediaDrm_getSecureStop },
1966
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001967 { "releaseSecureStops", "([B)V",
1968 (void *)android_media_MediaDrm_releaseSecureStops },
1969
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001970 { "removeSecureStop", "([B)V",
1971 (void *)android_media_MediaDrm_removeSecureStop },
1972
1973 { "removeAllSecureStops", "()V",
1974 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07001975
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001976 { "getConnectedHdcpLevel", "()I",
1977 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
1978
1979 { "getMaxHdcpLevel", "()I",
1980 (void *)android_media_MediaDrm_getMaxHdcpLevel },
1981
1982 { "getOpenSessionCount", "()I",
1983 (void *)android_media_MediaDrm_getOpenSessionCount },
1984
1985 { "getMaxSessionCount", "()I",
1986 (void *)android_media_MediaDrm_getMaxSessionCount },
1987
1988 { "getSecurityLevel", "([B)I",
1989 (void *)android_media_MediaDrm_getSecurityLevel },
1990
Jeff Tinker55d26242018-10-10 16:10:43 -07001991 { "removeOfflineLicense", "([B)V",
1992 (void *)android_media_MediaDrm_removeOfflineLicense },
1993
1994 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
1995 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
1996
1997 { "getOfflineLicenseState", "([B)I",
1998 (void *)android_media_MediaDrm_getOfflineLicenseState },
1999
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002000 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2001 (void *)android_media_MediaDrm_getPropertyString },
2002
2003 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2004 (void *)android_media_MediaDrm_getPropertyByteArray },
2005
2006 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2007 (void *)android_media_MediaDrm_setPropertyString },
2008
2009 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2010 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002011
2012 { "setCipherAlgorithmNative",
2013 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2014 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2015
2016 { "setMacAlgorithmNative",
2017 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2018 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2019
2020 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2021 (void *)android_media_MediaDrm_encryptNative },
2022
2023 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2024 (void *)android_media_MediaDrm_decryptNative },
2025
2026 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2027 (void *)android_media_MediaDrm_signNative },
2028
2029 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2030 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002031
2032 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2033 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002034
2035 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2036 (void *)android_media_MediaDrm_native_getMetrics },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002037};
2038
2039int register_android_media_Drm(JNIEnv *env) {
2040 return AndroidRuntime::registerNativeMethods(env,
2041 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2042}