blob: 681d76ab0dfee4c8e53e3e848a961b1c054c2393 [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
Robert Shihd2e8b432019-11-21 20:27:56 -080030#include <android/hardware/drm/1.3/IDrmFactory.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>
Robert Shihba6777e2019-11-12 13:04:59 -080036#include <mediadrm/DrmMetricsConsumer.h>
Robert Shih218b9532019-08-15 14:48:11 -070037#include <mediadrm/DrmUtils.h>
Robert Shihba6777e2019-11-12 13:04:59 -080038#include <mediadrm/IDrmMetricsConsumer.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080039#include <mediadrm/IDrm.h>
Robert Shih696989f2021-02-12 23:25:16 -080040#include <utils/Vector.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080041
Adam Stone94395c92018-01-30 12:07:00 -080042using ::android::os::PersistableBundle;
Robert Shihd2e8b432019-11-21 20:27:56 -080043namespace drm = ::android::hardware::drm;
Adam Stone94395c92018-01-30 12:07:00 -080044
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080045namespace android {
46
47#define FIND_CLASS(var, className) \
48 var = env->FindClass(className); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070049 LOG_FATAL_IF(! (var), "Unable to find class %s", className);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080050
51#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
52 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070053 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080054
55#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
56 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070057 LOG_FATAL_IF(! (var), "Unable to find method %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080058
Jeff Tinker54cfbd62013-04-02 13:14:59 -070059#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
60 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070061 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070062
63#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
64 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070065 LOG_FATAL_IF(! (var), "Unable to find static method %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070066
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070067#define GET_STATIC_OBJECT_FIELD(var, clazz, fieldId) \
68 var = env->GetStaticObjectField(clazz, fieldId); \
69 LOG_FATAL_IF(! (var), "Unable to find static object field %p", fieldId);
Adam Stone94395c92018-01-30 12:07:00 -080070
Jeff Tinker54cfbd62013-04-02 13:14:59 -070071
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080072struct RequestFields {
73 jfieldID data;
74 jfieldID defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -070075 jfieldID requestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080076};
77
78struct ArrayListFields {
79 jmethodID init;
80 jmethodID add;
81};
82
83struct HashmapFields {
84 jmethodID init;
85 jmethodID get;
86 jmethodID put;
87 jmethodID entrySet;
88};
89
90struct SetFields {
91 jmethodID iterator;
92};
93
94struct IteratorFields {
95 jmethodID next;
96 jmethodID hasNext;
97};
98
99struct EntryFields {
100 jmethodID getKey;
101 jmethodID getValue;
102};
103
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700104struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -0700105 jint kEventProvisionRequired;
106 jint kEventKeyRequired;
107 jint kEventKeyExpired;
108 jint kEventVendorDefined;
Ronghua Wua6d72092015-03-04 11:16:02 -0800109 jint kEventSessionReclaimed;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700110} gEventTypes;
111
Jeff Tinker74797f82015-03-31 15:44:34 -0700112struct EventWhat {
113 jint kWhatDrmEvent;
114 jint kWhatExpirationUpdate;
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700115 jint kWhatKeyStatusChange;
Jeff Tinker20594d82018-12-12 08:31:22 -0800116 jint kWhatSessionLostState;
Jeff Tinker74797f82015-03-31 15:44:34 -0700117} gEventWhat;
118
Jeff Tinker17b89222013-05-21 12:35:06 -0700119struct KeyTypes {
120 jint kKeyTypeStreaming;
121 jint kKeyTypeOffline;
122 jint kKeyTypeRelease;
123} gKeyTypes;
124
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700125struct KeyRequestTypes {
126 jint kKeyRequestTypeInitial;
127 jint kKeyRequestTypeRenewal;
128 jint kKeyRequestTypeRelease;
Rahul Frias8f761ba2018-01-22 23:43:54 -0800129 jint kKeyRequestTypeNone;
130 jint kKeyRequestTypeUpdate;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700131} gKeyRequestTypes;
132
Jeff Tinkere4095a82014-03-04 13:17:11 -0800133struct CertificateTypes {
134 jint kCertificateTypeNone;
135 jint kCertificateTypeX509;
136} gCertificateTypes;
137
138struct CertificateFields {
139 jfieldID wrappedPrivateKey;
140 jfieldID certificateData;
141};
142
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700143struct StateExceptionFields {
144 jmethodID init;
145 jclass classId;
146};
147
Jeff Tinker20594d82018-12-12 08:31:22 -0800148struct SessionExceptionFields {
149 jmethodID init;
150 jclass classId;
151 jfieldID errorCode;
152};
153
154struct SessionExceptionErrorCodes {
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800155 jint kErrorUnknown;
Jeff Tinker20594d82018-12-12 08:31:22 -0800156 jint kResourceContention;
157} gSessionExceptionErrorCodes;
158
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800159struct HDCPLevels {
160 jint kHdcpLevelUnknown;
161 jint kHdcpNone;
162 jint kHdcpV1;
163 jint kHdcpV2;
164 jint kHdcpV2_1;
165 jint kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800166 jint kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800167 jint kHdcpNoOutput;
168} gHdcpLevels;
169
170struct SecurityLevels {
171 jint kSecurityLevelUnknown;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000172 jint kSecurityLevelMax;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800173 jint kSecurityLevelSwSecureCrypto;
174 jint kSecurityLevelSwSecureDecode;
175 jint kSecurityLevelHwSecureCrypto;
176 jint kSecurityLevelHwSecureDecode;
177 jint kSecurityLevelHwSecureAll;
178} gSecurityLevels;
179
Jeff Tinker55d26242018-10-10 16:10:43 -0700180struct OfflineLicenseState {
181 jint kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800182 jint kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -0700183 jint kOfflineLicenseStateUnknown;
184} gOfflineLicenseStates;
185
Robert Shih9d4e2d42019-11-08 13:51:49 -0800186struct KeyStatusFields {
187 jmethodID init;
188 jclass classId;
189};
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800190
Robert Shih696989f2021-02-12 23:25:16 -0800191struct LogMessageFields {
192 jmethodID init;
193 jclass classId;
194};
195
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800196struct fields_t {
197 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700198 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700199 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800200 RequestFields provisionRequest;
201 ArrayListFields arraylist;
202 HashmapFields hashmap;
203 SetFields set;
204 IteratorFields iterator;
205 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800206 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700207 StateExceptionFields stateException;
Jeff Tinker20594d82018-12-12 08:31:22 -0800208 SessionExceptionFields sessionException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800209 jclass certificateClassId;
210 jclass hashmapClassId;
211 jclass arraylistClassId;
212 jclass stringClassId;
Adam Stone94395c92018-01-30 12:07:00 -0800213 jobject bundleCreator;
214 jmethodID createFromParcelId;
215 jclass parcelCreatorClassId;
Robert Shih9d4e2d42019-11-08 13:51:49 -0800216 KeyStatusFields keyStatus;
Robert Shih696989f2021-02-12 23:25:16 -0800217 LogMessageFields logMessage;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800218};
219
220static fields_t gFields;
221
Adam Stone94395c92018-01-30 12:07:00 -0800222namespace {
223
Robert Shih9d4e2d42019-11-08 13:51:49 -0800224jbyteArray hidlVectorToJByteArray(const hardware::hidl_vec<uint8_t> &vector) {
225 JNIEnv *env = AndroidRuntime::getJNIEnv();
226 size_t length = vector.size();
227 jbyteArray result = env->NewByteArray(length);
228 if (result != NULL) {
229 env->SetByteArrayRegion(result, 0, length, reinterpret_cast<const jbyte *>(vector.data()));
230 }
231 return result;
232}
233
Robert Shih696989f2021-02-12 23:25:16 -0800234jobject hidlLogMessagesToJavaList(JNIEnv *env, const Vector<drm::V1_4::LogMessage> &logs) {
235 jclass clazz = gFields.arraylistClassId;
236 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
237 clazz = gFields.logMessage.classId;
238 for (auto log: logs) {
239 jobject jLog = env->NewObject(clazz, gFields.logMessage.init,
240 static_cast<jlong>(log.timeMs),
241 static_cast<jint>(log.priority),
242 env->NewStringUTF(log.message.c_str()));
243 env->CallBooleanMethod(arrayList, gFields.arraylist.add, jLog);
244 }
245 return arrayList;
246}
Robert Shih46849832022-12-15 10:30:51 -0800247
248int drmThrowException(JNIEnv* env, const char *className, const DrmStatus &err, const char *msg) {
249 using namespace android::jnihelp;
250 jstring _detailMessage = CreateExceptionMsg(env, msg);
251 int _status = ThrowException(env, className, "(Ljava/lang/String;III)V",
252 _detailMessage,
253 err.getCdmErr(),
254 err.getOemErr(),
255 err.getContext());
256 if (_detailMessage != NULL) {
257 env->DeleteLocalRef(_detailMessage);
258 }
259 return _status;
260}
Adam Stone94395c92018-01-30 12:07:00 -0800261} // namespace anonymous
262
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700263// ----------------------------------------------------------------------------
264// ref-counted object for callbacks
265class JNIDrmListener: public DrmListener
266{
267public:
268 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
269 ~JNIDrmListener();
Robert Shih9d4e2d42019-11-08 13:51:49 -0800270 virtual void notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *arg = NULL);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700271private:
272 JNIDrmListener();
273 jclass mClass; // Reference to MediaDrm class
274 jobject mObject; // Weak ref to MediaDrm Java object to call on
275};
276
277JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
278{
279 // Hold onto the MediaDrm class for use in calling the static method
280 // that posts events to the application thread.
281 jclass clazz = env->GetObjectClass(thiz);
282 if (clazz == NULL) {
283 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700284 jniThrowException(env, "java/lang/Exception",
285 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700286 return;
287 }
288 mClass = (jclass)env->NewGlobalRef(clazz);
289
290 // We use a weak reference so the MediaDrm object can be garbage collected.
291 // The reference is only used as a proxy for callbacks.
292 mObject = env->NewGlobalRef(weak_thiz);
293}
294
295JNIDrmListener::~JNIDrmListener()
296{
297 // remove global references
298 JNIEnv *env = AndroidRuntime::getJNIEnv();
299 env->DeleteGlobalRef(mObject);
300 env->DeleteGlobalRef(mClass);
301}
302
303void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
Robert Shih9d4e2d42019-11-08 13:51:49 -0800304 const ListenerArgs *args)
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700305{
Jeff Tinker74797f82015-03-31 15:44:34 -0700306 jint jwhat;
307 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700308
309 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700310 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700311 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700312 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700313 jeventType = gEventTypes.kEventProvisionRequired;
314 break;
315 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700316 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700317 jeventType = gEventTypes.kEventKeyRequired;
318 break;
319 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700320 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700321 jeventType = gEventTypes.kEventKeyExpired;
322 break;
323 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700324 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700325 jeventType = gEventTypes.kEventVendorDefined;
326 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800327 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700328 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800329 jeventType = gEventTypes.kEventSessionReclaimed;
330 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700331 case DrmPlugin::kDrmPluginEventExpirationUpdate:
332 jwhat = gEventWhat.kWhatExpirationUpdate;
333 break;
334 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700335 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700336 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800337 case DrmPlugin::kDrmPluginEventSessionLostState:
338 jwhat = gEventWhat.kWhatSessionLostState;
339 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700340 default:
341 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
342 return;
343 }
344
345 JNIEnv *env = AndroidRuntime::getJNIEnv();
Robert Shih9d4e2d42019-11-08 13:51:49 -0800346 if (args) {
347 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
348 jwhat, jeventType, extra,
349 args->jSessionId, args->jData, args->jExpirationTime,
350 args->jKeyStatusList, args->jHasNewUsableKey);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700351 }
352
353 if (env->ExceptionCheck()) {
354 ALOGW("An exception occurred while notifying an event.");
355 LOGW_EX(env);
356 env->ExceptionClear();
357 }
358}
359
Robert Shih620f4a62021-02-15 03:28:42 -0800360jint MediaErrorToJavaError(status_t err) {
361#define STATUS_CASE(status) \
362 case status: \
363 return J##status
364
365 switch (err) {
366 STATUS_CASE(ERROR_DRM_UNKNOWN);
367 STATUS_CASE(ERROR_DRM_NO_LICENSE);
368 STATUS_CASE(ERROR_DRM_LICENSE_EXPIRED);
369 STATUS_CASE(ERROR_DRM_RESOURCE_BUSY);
370 STATUS_CASE(ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION);
371 STATUS_CASE(ERROR_DRM_SESSION_NOT_OPENED);
372 STATUS_CASE(ERROR_DRM_CANNOT_HANDLE);
373 STATUS_CASE(ERROR_DRM_INSUFFICIENT_SECURITY);
374 STATUS_CASE(ERROR_DRM_FRAME_TOO_LARGE);
375 STATUS_CASE(ERROR_DRM_SESSION_LOST_STATE);
376 STATUS_CASE(ERROR_DRM_CERTIFICATE_MALFORMED);
377 STATUS_CASE(ERROR_DRM_CERTIFICATE_MISSING);
378 STATUS_CASE(ERROR_DRM_CRYPTO_LIBRARY);
379 STATUS_CASE(ERROR_DRM_GENERIC_OEM);
380 STATUS_CASE(ERROR_DRM_GENERIC_PLUGIN);
381 STATUS_CASE(ERROR_DRM_INIT_DATA);
382 STATUS_CASE(ERROR_DRM_KEY_NOT_LOADED);
383 STATUS_CASE(ERROR_DRM_LICENSE_PARSE);
384 STATUS_CASE(ERROR_DRM_LICENSE_POLICY);
385 STATUS_CASE(ERROR_DRM_LICENSE_RELEASE);
386 STATUS_CASE(ERROR_DRM_LICENSE_REQUEST_REJECTED);
387 STATUS_CASE(ERROR_DRM_LICENSE_RESTORE);
388 STATUS_CASE(ERROR_DRM_LICENSE_STATE);
389 STATUS_CASE(ERROR_DRM_MEDIA_FRAMEWORK);
390 STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE);
391 STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG);
392 STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE);
Robert Shiha37ae8e2021-03-03 03:35:12 -0800393 STATUS_CASE(ERROR_DRM_PROVISIONING_REQUEST_REJECTED);
Robert Shih620f4a62021-02-15 03:28:42 -0800394 STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY);
395 STATUS_CASE(ERROR_DRM_RESOURCE_CONTENTION);
396 STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE);
397 STATUS_CASE(ERROR_DRM_STORAGE_READ);
398 STATUS_CASE(ERROR_DRM_STORAGE_WRITE);
399 STATUS_CASE(ERROR_DRM_ZERO_SUBSAMPLES);
400#undef STATUS_CASE
401 }
402 return static_cast<jint>(err);
403}
404
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530405static void throwStateException(JNIEnv *env, const char *msg, const DrmStatus &err) {
406 ALOGE("Illegal state exception: %s (%d)", msg, static_cast<status_t>(err));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700407
Robert Shih620f4a62021-02-15 03:28:42 -0800408 jint jerr = MediaErrorToJavaError(err);
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700409 jobject exception = env->NewObject(gFields.stateException.classId,
Robert Shih46849832022-12-15 10:30:51 -0800410 gFields.stateException.init, env->NewStringUTF(msg), static_cast<int>(jerr),
411 err.getCdmErr(), err.getOemErr(), err.getContext());
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700412 env->Throw(static_cast<jthrowable>(exception));
413}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700414
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530415static void throwSessionException(JNIEnv *env, const char *msg, const DrmStatus &err) {
416 ALOGE("Session exception: %s (%d)", msg, static_cast<status_t>(err));
Jeff Tinker20594d82018-12-12 08:31:22 -0800417
418 jint jErrorCode = 0;
419 switch(err) {
420 case ERROR_DRM_RESOURCE_CONTENTION:
421 jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
422 break;
423 default:
424 break;
425 }
426
427 jobject exception = env->NewObject(gFields.sessionException.classId,
Robert Shih46849832022-12-15 10:30:51 -0800428 gFields.sessionException.init,
429 env->NewStringUTF(msg),
430 jErrorCode,
431 err.getCdmErr(),
432 err.getOemErr(),
433 err.getContext());
Jeff Tinker20594d82018-12-12 08:31:22 -0800434
Jeff Tinker20594d82018-12-12 08:31:22 -0800435 env->Throw(static_cast<jthrowable>(exception));
436}
437
438static bool isSessionException(status_t err) {
439 return err == ERROR_DRM_RESOURCE_CONTENTION;
440}
441
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800442static bool throwExceptionAsNecessary(
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530443 JNIEnv *env, const sp<IDrm> &drm, const DrmStatus &err, const char *msg = NULL) {
Robert Shih60dab872021-02-13 11:24:59 -0800444 std::string msgStr;
Robert Shih13eb27b2021-02-20 00:08:16 -0800445 if (drm != NULL && err != OK) {
Robert Shih60dab872021-02-13 11:24:59 -0800446 msgStr = DrmUtils::GetExceptionMessage(err, msg, drm);
447 msg = msgStr.c_str();
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700448 }
449
Jeff Tinkereb13c762017-11-01 15:29:38 -0700450 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800451 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
452 return true;
Jeff Tinker5de2e902019-01-25 23:09:36 -0800453 } else if (err == ERROR_UNSUPPORTED) {
454 jniThrowException(env, "java/lang/UnsupportedOperationException", msg);
455 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700456 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
Robert Shih46849832022-12-15 10:30:51 -0800457 drmThrowException(env, "android/media/NotProvisionedException", err, msg);
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700458 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700459 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
Robert Shih46849832022-12-15 10:30:51 -0800460 drmThrowException(env, "android/media/ResourceBusyException", err, msg);
Jeff Tinker3ed38262013-08-02 23:24:51 -0700461 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700462 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
Robert Shih46849832022-12-15 10:30:51 -0800463 drmThrowException(env, "android/media/DeniedByServerException", err, msg);
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700464 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700465 } else if (err == DEAD_OBJECT) {
Robert Shih250f6a72021-02-26 08:20:31 -0800466 jniThrowException(env, "android/media/MediaDrmResetException", msg);
Jeff Tinker314b7f32015-06-15 17:45:43 -0700467 return true;
Jeff Tinker20594d82018-12-12 08:31:22 -0800468 } else if (isSessionException(err)) {
469 throwSessionException(env, msg, err);
470 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800471 } else if (err != OK) {
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700472 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800473 return true;
474 }
475 return false;
476}
477
478static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000479 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800480 return jdrm ? jdrm->getDrm() : NULL;
481}
482
483JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800484 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
485 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800486 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800487 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700488 if (mDrm != NULL) {
489 mDrm->setListener(this);
490 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800491}
492
493JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800494 JNIEnv *env = AndroidRuntime::getJNIEnv();
495
496 env->DeleteWeakGlobalRef(mObject);
497 mObject = NULL;
498}
499
500// static
501sp<IDrm> JDrm::MakeDrm() {
Robert Shih218b9532019-08-15 14:48:11 -0700502 return DrmUtils::MakeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800503}
504
505// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800506sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800507 sp<IDrm> drm = MakeDrm();
508
509 if (drm == NULL) {
510 return NULL;
511 }
512
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530513 DrmStatus err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800514
515 if (err != OK) {
516 return NULL;
517 }
518
519 return drm;
520}
521
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700522status_t JDrm::setListener(const sp<DrmListener>& listener) {
523 Mutex::Autolock lock(mLock);
524 mListener = listener;
525 return OK;
526}
527
Robert Shih9d4e2d42019-11-08 13:51:49 -0800528void JDrm::notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *args) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700529 sp<DrmListener> listener;
530 mLock.lock();
531 listener = mListener;
532 mLock.unlock();
533
534 if (listener != NULL) {
535 Mutex::Autolock lock(mNotifyLock);
Robert Shih9d4e2d42019-11-08 13:51:49 -0800536 listener->notify(eventType, extra, args);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700537 }
538}
539
Robert Shih3a523902019-08-15 14:48:11 -0700540void JDrm::sendEvent(
541 DrmPlugin::EventType eventType,
542 const hardware::hidl_vec<uint8_t> &sessionId,
543 const hardware::hidl_vec<uint8_t> &data) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800544 ListenerArgs args{
545 .jSessionId = hidlVectorToJByteArray(sessionId),
546 .jData = hidlVectorToJByteArray(data),
547 };
548 notify(eventType, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700549}
550
551void JDrm::sendExpirationUpdate(
552 const hardware::hidl_vec<uint8_t> &sessionId,
553 int64_t expiryTimeInMS) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800554 ListenerArgs args{
555 .jSessionId = hidlVectorToJByteArray(sessionId),
556 .jExpirationTime = expiryTimeInMS,
557 };
558 notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700559}
560
561void JDrm::sendKeysChange(
562 const hardware::hidl_vec<uint8_t> &sessionId,
563 const std::vector<DrmKeyStatus> &keyStatusList,
564 bool hasNewUsableKey) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800565 JNIEnv *env = AndroidRuntime::getJNIEnv();
566 jclass clazz = gFields.arraylistClassId;
567 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
568 clazz = gFields.keyStatus.classId;
569 for (const auto &keyStatus : keyStatusList) {
570 jbyteArray jKeyId(hidlVectorToJByteArray(keyStatus.keyId));
571 jint jStatusCode(keyStatus.type);
572 jobject jKeyStatus = env->NewObject(clazz, gFields.keyStatus.init, jKeyId, jStatusCode);
573 env->CallBooleanMethod(arrayList, gFields.arraylist.add, jKeyStatus);
574 }
575 ListenerArgs args{
576 .jSessionId = hidlVectorToJByteArray(sessionId),
577 .jKeyStatusList = arrayList,
578 .jHasNewUsableKey = hasNewUsableKey,
579 };
580 notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700581}
582
583void JDrm::sendSessionLostState(
584 const hardware::hidl_vec<uint8_t> &sessionId) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800585 ListenerArgs args{
586 .jSessionId = hidlVectorToJByteArray(sessionId),
587 };
588 notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700589}
590
Jeff Tinker600071c2014-04-11 16:11:15 -0700591void JDrm::disconnect() {
592 if (mDrm != NULL) {
593 mDrm->destroyPlugin();
594 mDrm.clear();
595 }
596}
597
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700598
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800599// static
Jeff Tinker5de2e902019-01-25 23:09:36 -0800600status_t JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
601 DrmPlugin::SecurityLevel securityLevel, bool *isSupported) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800602 sp<IDrm> drm = MakeDrm();
603
604 if (drm == NULL) {
Jeff Tinker5de2e902019-01-25 23:09:36 -0800605 return BAD_VALUE;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800606 }
607
Jeff Tinker5de2e902019-01-25 23:09:36 -0800608 return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel, isSupported);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800609}
610
611status_t JDrm::initCheck() const {
612 return mDrm == NULL ? NO_INIT : OK;
613}
614
615// JNI conversion utilities
616static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
617 Vector<uint8_t> vector;
618 size_t length = env->GetArrayLength(byteArray);
619 vector.insertAt((size_t)0, length);
620 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
621 return vector;
622}
623
624static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
625 size_t length = vector.size();
626 jbyteArray result = env->NewByteArray(length);
627 if (result != NULL) {
628 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
629 }
630 return result;
631}
632
633static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800634 String8 result;
635
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700636 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800637 if (s) {
638 result = s;
639 env->ReleaseStringUTFChars(jstr, s);
640 }
641 return result;
642}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700643
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800644/*
645 import java.util.HashMap;
646 import java.util.Set;
647 import java.Map.Entry;
648 import jav.util.Iterator;
649
650 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800651 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800652 Iterator i = s.iterator();
653 Entry e = s.next();
654*/
655
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200656static KeyedVector<String8, String8> HashMapToKeyedVector(
657 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800658 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800659 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200660 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800661
662 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
663 if (entrySet) {
664 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
665 if (iterator) {
666 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
667 while (hasNext) {
668 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
669 if (entry) {
670 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200671 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700672 jniThrowException(env, "java/lang/IllegalArgumentException",
673 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200674 env->DeleteLocalRef(entry);
675 *pIsOK = false;
676 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800677 }
678 jstring jkey = static_cast<jstring>(obj);
679
680 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200681 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700682 jniThrowException(env, "java/lang/IllegalArgumentException",
683 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200684 env->DeleteLocalRef(entry);
685 *pIsOK = false;
686 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800687 }
688 jstring jvalue = static_cast<jstring>(obj);
689
690 String8 key = JStringToString8(env, jkey);
691 String8 value = JStringToString8(env, jvalue);
692 keyedVector.add(key, value);
693
694 env->DeleteLocalRef(jkey);
695 env->DeleteLocalRef(jvalue);
696 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
697 }
698 env->DeleteLocalRef(entry);
699 }
700 env->DeleteLocalRef(iterator);
701 }
702 env->DeleteLocalRef(entrySet);
703 }
704 return keyedVector;
705}
706
707static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800708 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800709 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
710 for (size_t i = 0; i < map.size(); ++i) {
711 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
712 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
713 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
714 env->DeleteLocalRef(jkey);
715 env->DeleteLocalRef(jvalue);
716 }
717 return hashMap;
718}
719
720static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800721 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800722 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800723 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800724 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800725 while (iter != list.end()) {
726 jbyteArray byteArray = VectorToJByteArray(env, *iter);
727 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
728 env->DeleteLocalRef(byteArray);
729 iter++;
730 }
731
732 return arrayList;
733}
734
735} // namespace android
736
737using namespace android;
738
739static sp<JDrm> setDrm(
740 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000741 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800742 if (drm != NULL) {
743 drm->incStrong(thiz);
744 }
745 if (old != NULL) {
746 old->decStrong(thiz);
747 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000748 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800749
750 return old;
751}
752
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800753static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800754 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700755 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800756 return false;
757 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800758 return true;
759}
760
761static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
762{
763 if (!CheckDrm(env, drm)) {
764 return false;
765 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800766
767 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700768 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800769 return false;
770 }
771 return true;
772}
773
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800774static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700775 sp<JDrm> drm = setDrm(env, thiz, NULL);
776 if (drm != NULL) {
777 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700778 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700779 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800780}
781
782static void android_media_MediaDrm_native_init(JNIEnv *env) {
783 jclass clazz;
784 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000785 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700786 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Robert Shih9d4e2d42019-11-08 13:51:49 -0800787 "(Ljava/lang/Object;III[B[BJLjava/util/List;Z)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700788
789 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700790 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700791 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700792 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700793 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700794 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700795 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700796 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700797 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800798 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
799 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800800
Jeff Tinker74797f82015-03-31 15:44:34 -0700801 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
802 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
803 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
804 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700805 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
806 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800807 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
808 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700809
Jeff Tinker17b89222013-05-21 12:35:06 -0700810 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
811 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
812 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
813 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
814 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
815 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
816
Jeff Tinkere4095a82014-03-04 13:17:11 -0800817 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
818 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
819 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
820 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
821
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800822 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
823 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
824 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
825 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
826 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
827 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
828 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
829 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
830 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
831 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
832 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
833 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800834 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
835 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800836 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
837 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
838
839 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
840 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700841 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800842 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700843 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800844 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700845 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800846 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700847 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800848 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700849 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800850 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
851
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800852 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_USABLE", "I");
Jeff Tinker55d26242018-10-10 16:10:43 -0700853 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800854 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_RELEASED", "I");
855 gOfflineLicenseStates.kOfflineLicenseStateReleased = env->GetStaticIntField(clazz, field);
Jeff Tinker55d26242018-10-10 16:10:43 -0700856 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
857 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
858
859 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
860
Jeff Tinker2bca5252018-02-11 18:59:14 +0000861 jmethodID getMaxSecurityLevel;
862 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
863 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
864
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700865 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700866 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
867 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700868 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800869
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700870 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
871 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
872 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
873 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
874 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
875 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800876 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
877 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
878 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
879 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700880
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800881 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700882 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
883 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800884
Jeff Tinkere4095a82014-03-04 13:17:11 -0800885 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
886 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
887 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700888 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800889
Adam Stone94395c92018-01-30 12:07:00 -0800890 // Metrics-related fields and classes.
891 FIND_CLASS(clazz, "android/os/PersistableBundle");
892 jfieldID bundleCreatorId;
893 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
894 "Landroid/os/Parcelable$Creator;");
895 jobject bundleCreator;
896 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
897 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
898 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
899 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
900 "(Landroid/os/Parcel;)Ljava/lang/Object;");
901 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
902
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800903 FIND_CLASS(clazz, "java/util/ArrayList");
904 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
905 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
906
907 FIND_CLASS(clazz, "java/util/HashMap");
908 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
909 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
910 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
911 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
912 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
913
914 FIND_CLASS(clazz, "java/util/Set");
915 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
916
917 FIND_CLASS(clazz, "java/util/Iterator");
918 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
919 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
920
921 FIND_CLASS(clazz, "java/util/Map$Entry");
922 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
923 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800924
925 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700926 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800927
928 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700929 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800930
931 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700932 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700933
934 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
Robert Shih46849832022-12-15 10:30:51 -0800935 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(Ljava/lang/String;IIII)V");
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700936 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800937
938 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
Robert Shih46849832022-12-15 10:30:51 -0800939 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(Ljava/lang/String;IIII)V");
Jeff Tinker20594d82018-12-12 08:31:22 -0800940 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
941 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
942
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800943 GET_STATIC_FIELD_ID(field, clazz, "ERROR_UNKNOWN", "I");
944 gSessionExceptionErrorCodes.kErrorUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800945 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
946 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Robert Shih9d4e2d42019-11-08 13:51:49 -0800947
948 FIND_CLASS(clazz, "android/media/MediaDrm$KeyStatus");
949 gFields.keyStatus.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
950 GET_METHOD_ID(gFields.keyStatus.init, clazz, "<init>", "([BI)V");
Robert Shih696989f2021-02-12 23:25:16 -0800951
952 FIND_CLASS(clazz, "android/media/MediaDrm$LogMessage");
953 gFields.logMessage.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
954 GET_METHOD_ID(gFields.logMessage.init, clazz, "<init>", "(JILjava/lang/String;)V");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800955}
956
957static void android_media_MediaDrm_native_setup(
958 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800959 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800960
961 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700962 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800963 return;
964 }
965
966 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
967
968 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700969 jniThrowException(env, "java/lang/IllegalArgumentException",
970 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800971 return;
972 }
973
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800974 String8 packageName;
975 if (jappPackageName == NULL) {
976 jniThrowException(env, "java/lang/IllegalArgumentException",
977 "application package name cannot be null");
978 return;
979 }
980
981 packageName = JStringToString8(env, jappPackageName);
982 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800983
984 status_t err = drm->initCheck();
985
986 if (err != OK) {
Robert Shih250f6a72021-02-26 08:20:31 -0800987 auto logs(DrmUtils::gLogBuf.getLogs());
988 auto msg(DrmUtils::GetExceptionMessage(err, "Failed to instantiate drm object", logs));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800989 jniThrowException(
990 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700991 "android/media/UnsupportedSchemeException",
Robert Shih250f6a72021-02-26 08:20:31 -0800992 msg.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800993 return;
994 }
995
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700996 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
997 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800998 setDrm(env, thiz, drm);
999}
1000
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001001DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
1002 DrmPlugin::SecurityLevel level;
1003
1004 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
1005 level = DrmPlugin::kSecurityLevelMax;
1006 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
1007 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
1008 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
1009 level = DrmPlugin::kSecurityLevelSwSecureDecode;
1010 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
1011 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
1012 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
1013 level = DrmPlugin::kSecurityLevelHwSecureDecode;
1014 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
1015 level = DrmPlugin::kSecurityLevelHwSecureAll;
1016 } else {
1017 level = DrmPlugin::kSecurityLevelUnknown;
1018 }
1019 return level;
1020}
1021
Robert Shihd2e8b432019-11-21 20:27:56 -08001022static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
Kyle Zhang621af3e2022-03-17 23:39:05 +00001023 sp<IDrm> drm = android::DrmUtils::MakeDrm();
Robert Shihd2e8b432019-11-21 20:27:56 -08001024 std::vector<uint8_t> bv;
Kyle Zhang621af3e2022-03-17 23:39:05 +00001025 drm->getSupportedSchemes(bv);
Robert Shihd2e8b432019-11-21 20:27:56 -08001026
1027 jbyteArray jUuidBytes = env->NewByteArray(bv.size());
1028 env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
1029 return jUuidBytes;
1030}
1031
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001032static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001033 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
1034 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001035
1036 if (uuidObj == NULL) {
1037 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1038 return false;
1039 }
1040
1041 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
1042
1043 if (uuid.size() != 16) {
1044 jniThrowException(
1045 env,
1046 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -07001047 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001048 return false;
1049 }
1050
Jeff Tinker7cda4912013-08-21 11:52:34 -07001051 String8 mimeType;
1052 if (jmimeType != NULL) {
1053 mimeType = JStringToString8(env, jmimeType);
1054 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001055 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -07001056
Jeff Tinker5de2e902019-01-25 23:09:36 -08001057 bool isSupported;
1058 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
1059 securityLevel, &isSupported);
1060
Robert Shih60dab872021-02-13 11:24:59 -08001061 if (throwExceptionAsNecessary(env, NULL, err, "Failed to query crypto scheme support")) {
Jeff Tinker5de2e902019-01-25 23:09:36 -08001062 return false;
1063 }
1064 return isSupported;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001065}
1066
1067static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +00001068 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001069 sp<IDrm> drm = GetDrm(env, thiz);
1070
Jeff Tinker55d26242018-10-10 16:10:43 -07001071 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001072 return NULL;
1073 }
1074
1075 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001076 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1077 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +00001078 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1079 return NULL;
1080 }
1081
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301082 DrmStatus err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001083
Robert Shih60dab872021-02-13 11:24:59 -08001084 if (throwExceptionAsNecessary(env, drm, err, "Failed to open session")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001085 return NULL;
1086 }
1087
1088 return VectorToJByteArray(env, sessionId);
1089}
1090
1091static void android_media_MediaDrm_closeSession(
1092 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1093 sp<IDrm> drm = GetDrm(env, thiz);
1094
1095 if (!CheckSession(env, drm, jsessionId)) {
1096 return;
1097 }
1098
1099 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1100
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301101 DrmStatus err = drm->closeSession(sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001102
Robert Shih60dab872021-02-13 11:24:59 -08001103 throwExceptionAsNecessary(env, drm, err, "Failed to close session");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001104}
1105
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001106static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001107 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001108 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001109 sp<IDrm> drm = GetDrm(env, thiz);
1110
1111 if (!CheckSession(env, drm, jsessionId)) {
1112 return NULL;
1113 }
1114
1115 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1116
1117 Vector<uint8_t> initData;
1118 if (jinitData != NULL) {
1119 initData = JByteArrayToVector(env, jinitData);
1120 }
1121
1122 String8 mimeType;
1123 if (jmimeType != NULL) {
1124 mimeType = JStringToString8(env, jmimeType);
1125 }
1126
Jeff Tinker17b89222013-05-21 12:35:06 -07001127 DrmPlugin::KeyType keyType;
1128 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1129 keyType = DrmPlugin::kKeyType_Streaming;
1130 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1131 keyType = DrmPlugin::kKeyType_Offline;
1132 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1133 keyType = DrmPlugin::kKeyType_Release;
1134 } else {
1135 jniThrowException(env, "java/lang/IllegalArgumentException",
1136 "invalid keyType");
1137 return NULL;
1138 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001139
1140 KeyedVector<String8, String8> optParams;
1141 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001142 bool isOK;
1143 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1144 if (!isOK) {
1145 return NULL;
1146 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001147 }
1148
1149 Vector<uint8_t> request;
1150 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001151 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001152
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301153 DrmStatus err = drm->getKeyRequest(sessionId, initData, mimeType, keyType, optParams, request,
1154 defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001155
Robert Shih60dab872021-02-13 11:24:59 -08001156 if (throwExceptionAsNecessary(env, drm, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001157 return NULL;
1158 }
1159
1160 // Fill out return obj
1161 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001162 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001163
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001164 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001165
1166 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001167 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001168 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001169 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001170
1171 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001172 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001173
1174 switch (keyRequestType) {
1175 case DrmPlugin::kKeyRequestType_Initial:
1176 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1177 gKeyRequestTypes.kKeyRequestTypeInitial);
1178 break;
1179 case DrmPlugin::kKeyRequestType_Renewal:
1180 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1181 gKeyRequestTypes.kKeyRequestTypeRenewal);
1182 break;
1183 case DrmPlugin::kKeyRequestType_Release:
1184 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1185 gKeyRequestTypes.kKeyRequestTypeRelease);
1186 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001187 case DrmPlugin::kKeyRequestType_None:
1188 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1189 gKeyRequestTypes.kKeyRequestTypeNone);
1190 break;
1191 case DrmPlugin::kKeyRequestType_Update:
1192 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1193 gKeyRequestTypes.kKeyRequestTypeUpdate);
1194 break;
1195
Jeff Tinker74797f82015-03-31 15:44:34 -07001196 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001197 throwStateException(env, "DRM plugin failure: unknown key request type",
1198 ERROR_DRM_UNKNOWN);
1199 break;
1200 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001201 }
1202
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001203 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001204}
1205
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001206static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001207 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1208 sp<IDrm> drm = GetDrm(env, thiz);
1209
1210 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001211 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001212 }
1213
1214 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1215
1216 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001217 jniThrowException(env, "java/lang/IllegalArgumentException",
1218 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001219 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001220 }
1221 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001222 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001223
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301224 DrmStatus err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001225
Robert Shih60dab872021-02-13 11:24:59 -08001226 if (throwExceptionAsNecessary(env, drm, err, "Failed to handle key response")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001227 return NULL;
1228 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001229 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001230}
1231
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001232static void android_media_MediaDrm_removeKeys(
1233 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1234 sp<IDrm> drm = GetDrm(env, thiz);
1235
Jeff Tinker55d26242018-10-10 16:10:43 -07001236 if (!CheckDrm(env, drm)) {
1237 return;
1238 }
1239
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001240 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001241 jniThrowException(env, "java/lang/IllegalArgumentException",
1242 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001243 return;
1244 }
1245
1246 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1247
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301248 DrmStatus err = drm->removeKeys(keySetId);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001249
Robert Shih60dab872021-02-13 11:24:59 -08001250 throwExceptionAsNecessary(env, drm, err, "Failed to remove keys");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001251}
1252
1253static void android_media_MediaDrm_restoreKeys(
1254 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1255 jbyteArray jkeysetId) {
1256
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001257 sp<IDrm> drm = GetDrm(env, thiz);
1258
1259 if (!CheckSession(env, drm, jsessionId)) {
1260 return;
1261 }
1262
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001263 if (jkeysetId == NULL) {
1264 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1265 return;
1266 }
1267
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001268 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001269 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001270
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301271 DrmStatus err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001272
Robert Shih60dab872021-02-13 11:24:59 -08001273 throwExceptionAsNecessary(env, drm, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001274}
1275
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001276static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001277 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1278 sp<IDrm> drm = GetDrm(env, thiz);
1279
1280 if (!CheckSession(env, drm, jsessionId)) {
1281 return NULL;
1282 }
1283 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1284
1285 KeyedVector<String8, String8> infoMap;
1286
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301287 DrmStatus err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001288
Robert Shih60dab872021-02-13 11:24:59 -08001289 if (throwExceptionAsNecessary(env, drm, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001290 return NULL;
1291 }
1292
1293 return KeyedVectorToHashMap(env, infoMap);
1294}
1295
Jeff Tinkere4095a82014-03-04 13:17:11 -08001296static jobject android_media_MediaDrm_getProvisionRequestNative(
1297 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001298 sp<IDrm> drm = GetDrm(env, thiz);
1299
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001300 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001301 return NULL;
1302 }
1303
1304 Vector<uint8_t> request;
1305 String8 defaultUrl;
1306
Jeff Tinkere4095a82014-03-04 13:17:11 -08001307 String8 certType;
1308 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1309 certType = "X.509";
1310 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1311 certType = "none";
1312 } else {
1313 certType = "invalid";
1314 }
1315
1316 String8 certAuthority = JStringToString8(env, jcertAuthority);
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301317 DrmStatus err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001318
Robert Shih60dab872021-02-13 11:24:59 -08001319 if (throwExceptionAsNecessary(env, drm, err, "Failed to get provision request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001320 return NULL;
1321 }
1322
1323 // Fill out return obj
1324 jclass clazz;
1325 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1326
1327 jobject provisionObj = NULL;
1328
1329 if (clazz) {
1330 provisionObj = env->AllocObject(clazz);
1331 jbyteArray jrequest = VectorToJByteArray(env, request);
1332 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1333
1334 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1335 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1336 }
1337
1338 return provisionObj;
1339}
1340
Jeff Tinkere4095a82014-03-04 13:17:11 -08001341static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001342 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1343 sp<IDrm> drm = GetDrm(env, thiz);
1344
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001345 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001346 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001347 }
1348
1349 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001350 jniThrowException(env, "java/lang/IllegalArgumentException",
1351 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001352 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001353 }
1354
1355 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001356 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001357
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301358 DrmStatus err = drm->provideProvisionResponse(response, certificate, wrappedKey);
Jeff Tinkere4095a82014-03-04 13:17:11 -08001359
1360 // Fill out return obj
1361 jclass clazz = gFields.certificateClassId;
1362
1363 jobject certificateObj = NULL;
1364
1365 if (clazz && certificate.size() && wrappedKey.size()) {
1366 certificateObj = env->AllocObject(clazz);
1367 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1368 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1369
1370 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1371 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1372 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001373
Robert Shih60dab872021-02-13 11:24:59 -08001374 throwExceptionAsNecessary(env, drm, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001375 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001376}
1377
1378static jobject android_media_MediaDrm_getSecureStops(
1379 JNIEnv *env, jobject thiz) {
1380 sp<IDrm> drm = GetDrm(env, thiz);
1381
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001382 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001383 return NULL;
1384 }
1385
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001386 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001387
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301388 DrmStatus err = drm->getSecureStops(secureStops);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001389
Robert Shih60dab872021-02-13 11:24:59 -08001390 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stops")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001391 return NULL;
1392 }
1393
1394 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1395}
1396
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001397static jobject android_media_MediaDrm_getSecureStopIds(
1398 JNIEnv *env, jobject thiz) {
1399 sp<IDrm> drm = GetDrm(env, thiz);
1400
Jeff Tinker55d26242018-10-10 16:10:43 -07001401 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001402 return NULL;
1403 }
1404
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001405 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001406
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301407 DrmStatus err = drm->getSecureStopIds(secureStopIds);
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001408
Robert Shih60dab872021-02-13 11:24:59 -08001409 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop Ids")) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001410 return NULL;
1411 }
1412
1413 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1414}
1415
Jeff Tinker1b51c722014-10-31 00:54:26 -07001416static jbyteArray android_media_MediaDrm_getSecureStop(
1417 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1418 sp<IDrm> drm = GetDrm(env, thiz);
1419
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001420 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001421 return NULL;
1422 }
1423
1424 Vector<uint8_t> secureStop;
1425
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301426 DrmStatus err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
Jeff Tinker1b51c722014-10-31 00:54:26 -07001427
Robert Shih60dab872021-02-13 11:24:59 -08001428 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop")) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001429 return NULL;
1430 }
1431
1432 return VectorToJByteArray(env, secureStop);
1433}
1434
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001435static void android_media_MediaDrm_releaseSecureStops(
1436 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1437 sp<IDrm> drm = GetDrm(env, thiz);
1438
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001439 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001440 return;
1441 }
1442
1443 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1444
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301445 DrmStatus err = drm->releaseSecureStops(ssRelease);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001446
Robert Shih60dab872021-02-13 11:24:59 -08001447 throwExceptionAsNecessary(env, drm, err, "Failed to release secure stops");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001448}
1449
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001450static void android_media_MediaDrm_removeSecureStop(
1451 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1452 sp<IDrm> drm = GetDrm(env, thiz);
1453
Jeff Tinker55d26242018-10-10 16:10:43 -07001454 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001455 return;
1456 }
1457
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301458 DrmStatus err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001459
Robert Shih60dab872021-02-13 11:24:59 -08001460 throwExceptionAsNecessary(env, drm, err, "Failed to remove secure stop");
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001461}
1462
1463static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001464 JNIEnv *env, jobject thiz) {
1465 sp<IDrm> drm = GetDrm(env, thiz);
1466
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001467 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001468 return;
1469 }
1470
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301471 DrmStatus err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001472
Robert Shih60dab872021-02-13 11:24:59 -08001473 throwExceptionAsNecessary(env, drm, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001474}
1475
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001476
1477static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1478 switch(level) {
1479 case DrmPlugin::kHdcpLevelUnknown:
1480 return gHdcpLevels.kHdcpLevelUnknown;
1481 case DrmPlugin::kHdcpNone:
1482 return gHdcpLevels.kHdcpNone;
1483 case DrmPlugin::kHdcpV1:
1484 return gHdcpLevels.kHdcpV1;
1485 case DrmPlugin::kHdcpV2:
1486 return gHdcpLevels.kHdcpV2;
1487 case DrmPlugin::kHdcpV2_1:
1488 return gHdcpLevels.kHdcpV2_1;
1489 case DrmPlugin::kHdcpV2_2:
1490 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001491 case DrmPlugin::kHdcpV2_3:
1492 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001493 case DrmPlugin::kHdcpNoOutput:
1494 return gHdcpLevels.kHdcpNoOutput;
1495 }
1496 return gHdcpLevels.kHdcpNone;
1497}
1498
1499static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1500 jobject thiz) {
1501 sp<IDrm> drm = GetDrm(env, thiz);
1502
1503 if (!CheckDrm(env, drm)) {
1504 return gHdcpLevels.kHdcpNone;
1505 }
1506
1507 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1508 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1509
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301510 DrmStatus err = drm->getHdcpLevels(&connected, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001511
Robert Shih60dab872021-02-13 11:24:59 -08001512 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001513 return gHdcpLevels.kHdcpLevelUnknown;
1514 }
1515 return HdcpLevelTojint(connected);
1516}
1517
1518static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1519 jobject thiz) {
1520 sp<IDrm> drm = GetDrm(env, thiz);
1521
1522 if (!CheckDrm(env, drm)) {
1523 return gHdcpLevels.kHdcpLevelUnknown;
1524 }
1525
1526 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1527 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1528
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301529 DrmStatus err = drm->getHdcpLevels(&connected, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001530
Robert Shih60dab872021-02-13 11:24:59 -08001531 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001532 return gHdcpLevels.kHdcpLevelUnknown;
1533 }
1534 return HdcpLevelTojint(max);
1535}
1536
1537static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1538 jobject thiz) {
1539 sp<IDrm> drm = GetDrm(env, thiz);
1540
1541 if (!CheckDrm(env, drm)) {
1542 return 0;
1543 }
1544
1545 uint32_t open = 0, max = 0;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301546 DrmStatus err = drm->getNumberOfSessions(&open, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001547
Robert Shih60dab872021-02-13 11:24:59 -08001548 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001549 return 0;
1550 }
1551 return open;
1552}
1553
1554static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1555 jobject thiz) {
1556 sp<IDrm> drm = GetDrm(env, thiz);
1557
1558 if (!CheckDrm(env, drm)) {
1559 return 0;
1560 }
1561
1562 uint32_t open = 0, max = 0;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301563 DrmStatus err = drm->getNumberOfSessions(&open, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001564
Robert Shih60dab872021-02-13 11:24:59 -08001565 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001566 return 0;
1567 }
1568 return max;
1569}
1570
1571static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1572 jobject thiz, jbyteArray jsessionId) {
1573 sp<IDrm> drm = GetDrm(env, thiz);
1574
1575 if (!CheckSession(env, drm, jsessionId)) {
1576 return gSecurityLevels.kSecurityLevelUnknown;
1577 }
1578
1579 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1580
1581 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1582
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301583 DrmStatus err = drm->getSecurityLevel(sessionId, &level);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001584
Robert Shih60dab872021-02-13 11:24:59 -08001585 if (throwExceptionAsNecessary(env, drm, err, "Failed to get security level")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001586 return gSecurityLevels.kSecurityLevelUnknown;
1587 }
1588
1589 switch(level) {
1590 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1591 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1592 case DrmPlugin::kSecurityLevelSwSecureDecode:
1593 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1594 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1595 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1596 case DrmPlugin::kSecurityLevelHwSecureDecode:
1597 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1598 case DrmPlugin::kSecurityLevelHwSecureAll:
1599 return gSecurityLevels.kSecurityLevelHwSecureAll;
1600 default:
1601 return gSecurityLevels.kSecurityLevelUnknown;
1602 }
1603}
1604
Jeff Tinker55d26242018-10-10 16:10:43 -07001605static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1606 JNIEnv *env, jobject thiz) {
1607 sp<IDrm> drm = GetDrm(env, thiz);
1608
1609 if (!CheckDrm(env, drm)) {
1610 return NULL;
1611 }
1612
1613 List<Vector<uint8_t> > keySetIds;
1614
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301615 DrmStatus err = drm->getOfflineLicenseKeySetIds(keySetIds);
Jeff Tinker55d26242018-10-10 16:10:43 -07001616
Robert Shih60dab872021-02-13 11:24:59 -08001617 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline key set Ids")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001618 return NULL;
1619 }
1620
1621 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1622}
1623
1624static void android_media_MediaDrm_removeOfflineLicense(
1625 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1626 sp<IDrm> drm = GetDrm(env, thiz);
1627
1628 if (!CheckDrm(env, drm)) {
1629 return;
1630 }
1631
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301632 DrmStatus err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
Jeff Tinker55d26242018-10-10 16:10:43 -07001633
Robert Shih60dab872021-02-13 11:24:59 -08001634 throwExceptionAsNecessary(env, drm, err, "Failed to remove offline license");
Jeff Tinker55d26242018-10-10 16:10:43 -07001635}
1636
1637static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1638 jobject thiz, jbyteArray jkeySetId) {
1639 sp<IDrm> drm = GetDrm(env, thiz);
1640
1641 if (!CheckDrm(env, drm)) {
1642 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1643 }
1644
1645 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1646
1647 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1648
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301649 DrmStatus err = drm->getOfflineLicenseState(keySetId, &state);
Jeff Tinker55d26242018-10-10 16:10:43 -07001650
Robert Shih60dab872021-02-13 11:24:59 -08001651 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline license state")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001652 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1653 }
1654
1655 switch(state) {
1656 case DrmPlugin::kOfflineLicenseStateUsable:
1657 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -08001658 case DrmPlugin::kOfflineLicenseStateReleased:
1659 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -07001660 default:
1661 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1662 }
1663}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001664
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001665static jstring android_media_MediaDrm_getPropertyString(
1666 JNIEnv *env, jobject thiz, jstring jname) {
1667 sp<IDrm> drm = GetDrm(env, thiz);
1668
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001669 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001670 return NULL;
1671 }
1672
1673 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001674 jniThrowException(env, "java/lang/IllegalArgumentException",
1675 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001676 return NULL;
1677 }
1678
1679 String8 name = JStringToString8(env, jname);
1680 String8 value;
1681
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301682 DrmStatus err = drm->getPropertyString(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001683
Robert Shih60dab872021-02-13 11:24:59 -08001684 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001685 return NULL;
1686 }
1687
1688 return env->NewStringUTF(value.string());
1689}
1690
1691static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1692 JNIEnv *env, jobject thiz, jstring jname) {
1693 sp<IDrm> drm = GetDrm(env, thiz);
1694
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001695 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001696 return NULL;
1697 }
1698
1699 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001700 jniThrowException(env, "java/lang/IllegalArgumentException",
1701 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001702 return NULL;
1703 }
1704
1705 String8 name = JStringToString8(env, jname);
1706 Vector<uint8_t> value;
1707
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301708 DrmStatus err = drm->getPropertyByteArray(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001709
Robert Shih60dab872021-02-13 11:24:59 -08001710 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001711 return NULL;
1712 }
1713
1714 return VectorToJByteArray(env, value);
1715}
1716
1717static void android_media_MediaDrm_setPropertyString(
1718 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1719 sp<IDrm> drm = GetDrm(env, thiz);
1720
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001721 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001722 return;
1723 }
1724
Jeff Tinkereada5372013-05-21 12:48:14 -07001725 if (jname == NULL) {
1726 jniThrowException(env, "java/lang/IllegalArgumentException",
1727 "property name String is null");
1728 return;
1729 }
1730
1731 if (jvalue == NULL) {
1732 jniThrowException(env, "java/lang/IllegalArgumentException",
1733 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001734 return;
1735 }
1736
1737 String8 name = JStringToString8(env, jname);
1738 String8 value = JStringToString8(env, jvalue);
1739
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301740 DrmStatus err = drm->setPropertyString(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001741
Robert Shih60dab872021-02-13 11:24:59 -08001742 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001743}
1744
1745static void android_media_MediaDrm_setPropertyByteArray(
1746 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1747 sp<IDrm> drm = GetDrm(env, thiz);
1748
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001749 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001750 return;
1751 }
1752
Jeff Tinkereada5372013-05-21 12:48:14 -07001753 if (jname == NULL) {
1754 jniThrowException(env, "java/lang/IllegalArgumentException",
1755 "property name String is null");
1756 return;
1757 }
1758
1759 if (jvalue == NULL) {
1760 jniThrowException(env, "java/lang/IllegalArgumentException",
1761 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001762 return;
1763 }
1764
1765 String8 name = JStringToString8(env, jname);
1766 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1767
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301768 DrmStatus err = drm->setPropertyByteArray(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001769
Robert Shih60dab872021-02-13 11:24:59 -08001770 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001771}
1772
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001773static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001774 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001775 jstring jalgorithm) {
1776
1777 sp<IDrm> drm = GetDrm(env, jdrm);
1778
1779 if (!CheckSession(env, drm, jsessionId)) {
1780 return;
1781 }
1782
1783 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001784 jniThrowException(env, "java/lang/IllegalArgumentException",
1785 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001786 return;
1787 }
1788
1789 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1790 String8 algorithm = JStringToString8(env, jalgorithm);
1791
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301792 DrmStatus err = drm->setCipherAlgorithm(sessionId, algorithm);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001793
Robert Shih60dab872021-02-13 11:24:59 -08001794 throwExceptionAsNecessary(env, drm, err, "Failed to set cipher algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001795}
1796
1797static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001798 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001799 jstring jalgorithm) {
1800
1801 sp<IDrm> drm = GetDrm(env, jdrm);
1802
1803 if (!CheckSession(env, drm, jsessionId)) {
1804 return;
1805 }
1806
1807 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001808 jniThrowException(env, "java/lang/IllegalArgumentException",
1809 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001810 return;
1811 }
1812
1813 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1814 String8 algorithm = JStringToString8(env, jalgorithm);
1815
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301816 DrmStatus err = drm->setMacAlgorithm(sessionId, algorithm);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001817
Robert Shih60dab872021-02-13 11:24:59 -08001818 throwExceptionAsNecessary(env, drm, err, "Failed to set mac algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001819}
1820
1821
1822static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001823 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001824 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1825
1826 sp<IDrm> drm = GetDrm(env, jdrm);
1827
1828 if (!CheckSession(env, drm, jsessionId)) {
1829 return NULL;
1830 }
1831
1832 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001833 jniThrowException(env, "java/lang/IllegalArgumentException",
1834 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001835 return NULL;
1836 }
1837
1838 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1839 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1840 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1841 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1842 Vector<uint8_t> output;
1843
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301844 DrmStatus err = drm->encrypt(sessionId, keyId, input, iv, output);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001845
Robert Shih60dab872021-02-13 11:24:59 -08001846 if (throwExceptionAsNecessary(env, drm, err, "Failed to encrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001847 return NULL;
1848 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001849
1850 return VectorToJByteArray(env, output);
1851}
1852
1853static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001854 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001855 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1856
1857 sp<IDrm> drm = GetDrm(env, jdrm);
1858
1859 if (!CheckSession(env, drm, jsessionId)) {
1860 return NULL;
1861 }
1862
1863 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001864 jniThrowException(env, "java/lang/IllegalArgumentException",
1865 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001866 return NULL;
1867 }
1868
1869 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1870 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1871 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1872 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1873 Vector<uint8_t> output;
1874
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301875 DrmStatus err = drm->decrypt(sessionId, keyId, input, iv, output);
Robert Shih60dab872021-02-13 11:24:59 -08001876 if (throwExceptionAsNecessary(env, drm, err, "Failed to decrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001877 return NULL;
1878 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001879
1880 return VectorToJByteArray(env, output);
1881}
1882
1883static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001884 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001885 jbyteArray jkeyId, jbyteArray jmessage) {
1886
1887 sp<IDrm> drm = GetDrm(env, jdrm);
1888
1889 if (!CheckSession(env, drm, jsessionId)) {
1890 return NULL;
1891 }
1892
1893 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001894 jniThrowException(env, "java/lang/IllegalArgumentException",
1895 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001896 return NULL;
1897 }
1898
1899 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1900 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1901 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1902 Vector<uint8_t> signature;
1903
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301904 DrmStatus err = drm->sign(sessionId, keyId, message, signature);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001905
Robert Shih60dab872021-02-13 11:24:59 -08001906 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001907 return NULL;
1908 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001909
1910 return VectorToJByteArray(env, signature);
1911}
1912
1913static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001914 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001915 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1916
1917 sp<IDrm> drm = GetDrm(env, jdrm);
1918
1919 if (!CheckSession(env, drm, jsessionId)) {
1920 return false;
1921 }
1922
1923 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001924 jniThrowException(env, "java/lang/IllegalArgumentException",
1925 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001926 return false;
1927 }
1928
1929 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1930 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1931 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1932 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1933 bool match;
1934
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301935 DrmStatus err = drm->verify(sessionId, keyId, message, signature, match);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001936
Robert Shih60dab872021-02-13 11:24:59 -08001937 throwExceptionAsNecessary(env, drm, err, "Failed to verify");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001938 return match;
1939}
1940
Adam Stonec06e10e2017-12-19 12:54:33 -08001941static jobject
1942android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1943{
1944 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001945
1946 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001947 return NULL;
1948 }
1949
1950 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001951 PersistableBundle metrics;
Robert Shihba6777e2019-11-12 13:04:59 -08001952 sp<IDrmMetricsConsumer> consumer(new DrmMetricsConsumer(&metrics));
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301953 DrmStatus err = drm->getMetrics(consumer);
Adam Stonec06e10e2017-12-19 12:54:33 -08001954 if (err != OK) {
1955 ALOGE("getMetrics failed: %d", (int)err);
1956 return (jobject) NULL;
1957 }
1958
Robert Shih4354a962019-11-10 12:09:08 -08001959 return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001960}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001961
Jeff Tinkere4095a82014-03-04 13:17:11 -08001962static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001963 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001964 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1965
1966 sp<IDrm> drm = GetDrm(env, jdrm);
1967
1968 if (!CheckSession(env, drm, jsessionId)) {
1969 return NULL;
1970 }
1971
1972 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1973 jniThrowException(env, "java/lang/IllegalArgumentException",
1974 "required argument is null");
1975 return NULL;
1976 }
1977
1978 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1979 String8 algorithm = JStringToString8(env, jalgorithm);
1980 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1981 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1982 Vector<uint8_t> signature;
1983
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301984 DrmStatus err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
Jeff Tinkere4095a82014-03-04 13:17:11 -08001985
Robert Shih60dab872021-02-13 11:24:59 -08001986 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001987 return NULL;
1988 }
1989
1990 return VectorToJByteArray(env, signature);
1991}
1992
Robert Shih205f7a92021-01-19 21:12:10 -08001993static jboolean android_media_MediaDrm_requiresSecureDecoder(
1994 JNIEnv *env, jobject thiz, jstring jmimeType,
1995 jint jSecurityLevel) {
1996 sp<IDrm> drm = GetDrm(env, thiz);
1997 if (!CheckDrm(env, drm)) {
1998 return JNI_FALSE;
1999 }
2000
2001 String8 mimeType;
2002 if (jmimeType != NULL) {
2003 mimeType = JStringToString8(env, jmimeType);
2004 }
2005
2006 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
2007 if (securityLevel == DrmPlugin::kSecurityLevelUnknown) {
2008 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
2009 return JNI_FALSE;
2010 }
2011
Robert Shih5bb242a2021-04-28 10:04:51 -07002012 bool required = false;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302013 DrmStatus err = OK;
Robert Shih205f7a92021-01-19 21:12:10 -08002014 if (securityLevel == DrmPlugin::kSecurityLevelMax) {
Robert Shih5bb242a2021-04-28 10:04:51 -07002015 err = drm->requiresSecureDecoder(mimeType.c_str(), &required);
2016 } else {
2017 err = drm->requiresSecureDecoder(mimeType.c_str(), securityLevel, &required);
Robert Shih205f7a92021-01-19 21:12:10 -08002018 }
Robert Shih5bb242a2021-04-28 10:04:51 -07002019 if (throwExceptionAsNecessary(env, drm, err, "Failed to query secure decoder requirement")) {
2020 return false;
2021 }
2022 return required;
Robert Shih205f7a92021-01-19 21:12:10 -08002023}
Jeff Tinkere4095a82014-03-04 13:17:11 -08002024
Robert Shih02937122021-01-20 00:05:20 -08002025static void android_media_MediaDrm_setPlaybackId(
2026 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
2027 jstring jplaybackId) {
2028 sp<IDrm> drm = GetDrm(env, thiz);
2029 if (!CheckSession(env, drm, jsessionId)) {
2030 return;
2031 }
2032
2033 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2034
2035 String8 playbackId;
2036 if (jplaybackId != NULL) {
2037 playbackId = JStringToString8(env, jplaybackId);
2038 }
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302039 DrmStatus err = drm->setPlaybackId(sessionId, playbackId.c_str());
Robert Shih60dab872021-02-13 11:24:59 -08002040 throwExceptionAsNecessary(env, drm, err, "Failed to set playbackId");
Robert Shih02937122021-01-20 00:05:20 -08002041}
2042
Robert Shih696989f2021-02-12 23:25:16 -08002043static jobject android_media_MediaDrm_getLogMessages(
2044 JNIEnv *env, jobject thiz) {
2045 sp<IDrm> drm = GetDrm(env, thiz);
2046 if (!CheckDrm(env, drm)) {
2047 return NULL;
2048 }
2049
2050 Vector<drm::V1_4::LogMessage> logs;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302051 DrmStatus err = drm->getLogMessages(logs);
Robert Shih696989f2021-02-12 23:25:16 -08002052 ALOGI("drm->getLogMessages %zu logs", logs.size());
Robert Shih60dab872021-02-13 11:24:59 -08002053 if (throwExceptionAsNecessary(env, drm, err, "Failed to get log messages")) {
Robert Shih696989f2021-02-12 23:25:16 -08002054 return NULL;
2055 }
2056 return hidlLogMessagesToJavaList(env, logs);
2057}
2058
Daniel Micay76f6a862015-09-19 17:31:01 -04002059static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002060 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
2061
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002062 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
2063
Edwin Wong4d1d84e2017-01-04 09:37:49 -08002064 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002065 (void *)android_media_MediaDrm_native_setup },
2066
Robert Shihd2e8b432019-11-21 20:27:56 -08002067 { "getSupportedCryptoSchemesNative", "()[B",
2068 (void *)android_media_MediaDrm_getSupportedCryptoSchemesNative },
2069
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08002070 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002071 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
2072
Robert Shih02937122021-01-20 00:05:20 -08002073 { "openSessionNative", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002074 (void *)android_media_MediaDrm_openSession },
2075
Robert Shih02937122021-01-20 00:05:20 -08002076 { "closeSessionNative", "([B)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002077 (void *)android_media_MediaDrm_closeSession },
2078
Robert Shih890eb572021-01-19 08:16:39 -08002079 { "getKeyRequestNative", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002080 "Landroid/media/MediaDrm$KeyRequest;",
2081 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002082
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002083 { "provideKeyResponse", "([B[B)[B",
2084 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002085
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002086 { "removeKeys", "([B)V",
2087 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002088
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002089 { "restoreKeys", "([B[B)V",
2090 (void *)android_media_MediaDrm_restoreKeys },
2091
2092 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
2093 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002094
Jeff Tinkere4095a82014-03-04 13:17:11 -08002095 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
2096 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002097
Jeff Tinkere4095a82014-03-04 13:17:11 -08002098 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
2099 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002100
2101 { "getSecureStops", "()Ljava/util/List;",
2102 (void *)android_media_MediaDrm_getSecureStops },
2103
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002104 { "getSecureStopIds", "()Ljava/util/List;",
2105 (void *)android_media_MediaDrm_getSecureStopIds },
2106
Jeff Tinker1b51c722014-10-31 00:54:26 -07002107 { "getSecureStop", "([B)[B",
2108 (void *)android_media_MediaDrm_getSecureStop },
2109
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002110 { "releaseSecureStops", "([B)V",
2111 (void *)android_media_MediaDrm_releaseSecureStops },
2112
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002113 { "removeSecureStop", "([B)V",
2114 (void *)android_media_MediaDrm_removeSecureStop },
2115
2116 { "removeAllSecureStops", "()V",
2117 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07002118
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002119 { "getConnectedHdcpLevel", "()I",
2120 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
2121
2122 { "getMaxHdcpLevel", "()I",
2123 (void *)android_media_MediaDrm_getMaxHdcpLevel },
2124
2125 { "getOpenSessionCount", "()I",
2126 (void *)android_media_MediaDrm_getOpenSessionCount },
2127
2128 { "getMaxSessionCount", "()I",
2129 (void *)android_media_MediaDrm_getMaxSessionCount },
2130
2131 { "getSecurityLevel", "([B)I",
2132 (void *)android_media_MediaDrm_getSecurityLevel },
2133
Jeff Tinker55d26242018-10-10 16:10:43 -07002134 { "removeOfflineLicense", "([B)V",
2135 (void *)android_media_MediaDrm_removeOfflineLicense },
2136
2137 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
2138 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
2139
2140 { "getOfflineLicenseState", "([B)I",
2141 (void *)android_media_MediaDrm_getOfflineLicenseState },
2142
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002143 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2144 (void *)android_media_MediaDrm_getPropertyString },
2145
2146 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2147 (void *)android_media_MediaDrm_getPropertyByteArray },
2148
2149 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2150 (void *)android_media_MediaDrm_setPropertyString },
2151
2152 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2153 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002154
2155 { "setCipherAlgorithmNative",
2156 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2157 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2158
2159 { "setMacAlgorithmNative",
2160 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2161 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2162
2163 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2164 (void *)android_media_MediaDrm_encryptNative },
2165
2166 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2167 (void *)android_media_MediaDrm_decryptNative },
2168
2169 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2170 (void *)android_media_MediaDrm_signNative },
2171
2172 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2173 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002174
2175 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2176 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002177
2178 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2179 (void *)android_media_MediaDrm_native_getMetrics },
Robert Shih205f7a92021-01-19 21:12:10 -08002180
2181 { "requiresSecureDecoder", "(Ljava/lang/String;I)Z",
2182 (void *)android_media_MediaDrm_requiresSecureDecoder },
Robert Shih02937122021-01-20 00:05:20 -08002183
2184 { "setPlaybackId", "([BLjava/lang/String;)V",
2185 (void *)android_media_MediaDrm_setPlaybackId },
Robert Shih696989f2021-02-12 23:25:16 -08002186
2187 { "getLogMessages", "()Ljava/util/List;",
2188 (void *)android_media_MediaDrm_getLogMessages },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002189};
2190
2191int register_android_media_Drm(JNIEnv *env) {
2192 return AndroidRuntime::registerNativeMethods(env,
2193 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2194}