blob: c616b84fa6fb26f44833e683ba3e0a0cab8108e2 [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) {
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +0000711 jstring jkey = env->NewStringUTF(map.keyAt(i).c_str());
712 jstring jvalue = env->NewStringUTF(map.valueAt(i).c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800713 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();
Kyle Zhang452bc552023-01-23 22:37:45 +00001024 if (drm == NULL) return env->NewByteArray(0);
1025
Robert Shihd2e8b432019-11-21 20:27:56 -08001026 std::vector<uint8_t> bv;
Kyle Zhang621af3e2022-03-17 23:39:05 +00001027 drm->getSupportedSchemes(bv);
Robert Shihd2e8b432019-11-21 20:27:56 -08001028 jbyteArray jUuidBytes = env->NewByteArray(bv.size());
1029 env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
1030 return jUuidBytes;
1031}
1032
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001033static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001034 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
1035 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001036
1037 if (uuidObj == NULL) {
1038 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1039 return false;
1040 }
1041
1042 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
1043
1044 if (uuid.size() != 16) {
1045 jniThrowException(
1046 env,
1047 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -07001048 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001049 return false;
1050 }
1051
Jeff Tinker7cda4912013-08-21 11:52:34 -07001052 String8 mimeType;
1053 if (jmimeType != NULL) {
1054 mimeType = JStringToString8(env, jmimeType);
1055 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001056 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -07001057
Jeff Tinker5de2e902019-01-25 23:09:36 -08001058 bool isSupported;
1059 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
1060 securityLevel, &isSupported);
1061
Robert Shih60dab872021-02-13 11:24:59 -08001062 if (throwExceptionAsNecessary(env, NULL, err, "Failed to query crypto scheme support")) {
Jeff Tinker5de2e902019-01-25 23:09:36 -08001063 return false;
1064 }
1065 return isSupported;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001066}
1067
1068static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +00001069 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001070 sp<IDrm> drm = GetDrm(env, thiz);
1071
Jeff Tinker55d26242018-10-10 16:10:43 -07001072 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001073 return NULL;
1074 }
1075
1076 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001077 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1078 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +00001079 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1080 return NULL;
1081 }
1082
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301083 DrmStatus err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001084
Robert Shih60dab872021-02-13 11:24:59 -08001085 if (throwExceptionAsNecessary(env, drm, err, "Failed to open session")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001086 return NULL;
1087 }
1088
1089 return VectorToJByteArray(env, sessionId);
1090}
1091
1092static void android_media_MediaDrm_closeSession(
1093 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1094 sp<IDrm> drm = GetDrm(env, thiz);
1095
1096 if (!CheckSession(env, drm, jsessionId)) {
1097 return;
1098 }
1099
1100 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1101
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301102 DrmStatus err = drm->closeSession(sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001103
Robert Shih60dab872021-02-13 11:24:59 -08001104 throwExceptionAsNecessary(env, drm, err, "Failed to close session");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001105}
1106
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001107static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001108 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001109 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001110 sp<IDrm> drm = GetDrm(env, thiz);
1111
1112 if (!CheckSession(env, drm, jsessionId)) {
1113 return NULL;
1114 }
1115
1116 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1117
1118 Vector<uint8_t> initData;
1119 if (jinitData != NULL) {
1120 initData = JByteArrayToVector(env, jinitData);
1121 }
1122
1123 String8 mimeType;
1124 if (jmimeType != NULL) {
1125 mimeType = JStringToString8(env, jmimeType);
1126 }
1127
Jeff Tinker17b89222013-05-21 12:35:06 -07001128 DrmPlugin::KeyType keyType;
1129 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1130 keyType = DrmPlugin::kKeyType_Streaming;
1131 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1132 keyType = DrmPlugin::kKeyType_Offline;
1133 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1134 keyType = DrmPlugin::kKeyType_Release;
1135 } else {
1136 jniThrowException(env, "java/lang/IllegalArgumentException",
1137 "invalid keyType");
1138 return NULL;
1139 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001140
1141 KeyedVector<String8, String8> optParams;
1142 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001143 bool isOK;
1144 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1145 if (!isOK) {
1146 return NULL;
1147 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001148 }
1149
1150 Vector<uint8_t> request;
1151 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001152 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001153
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301154 DrmStatus err = drm->getKeyRequest(sessionId, initData, mimeType, keyType, optParams, request,
1155 defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001156
Robert Shih60dab872021-02-13 11:24:59 -08001157 if (throwExceptionAsNecessary(env, drm, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001158 return NULL;
1159 }
1160
1161 // Fill out return obj
1162 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001163 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001164
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001165 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001166
1167 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001168 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001169 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001170 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001171
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001172 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.c_str());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001173 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001174
1175 switch (keyRequestType) {
1176 case DrmPlugin::kKeyRequestType_Initial:
1177 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1178 gKeyRequestTypes.kKeyRequestTypeInitial);
1179 break;
1180 case DrmPlugin::kKeyRequestType_Renewal:
1181 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1182 gKeyRequestTypes.kKeyRequestTypeRenewal);
1183 break;
1184 case DrmPlugin::kKeyRequestType_Release:
1185 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1186 gKeyRequestTypes.kKeyRequestTypeRelease);
1187 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001188 case DrmPlugin::kKeyRequestType_None:
1189 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1190 gKeyRequestTypes.kKeyRequestTypeNone);
1191 break;
1192 case DrmPlugin::kKeyRequestType_Update:
1193 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1194 gKeyRequestTypes.kKeyRequestTypeUpdate);
1195 break;
1196
Jeff Tinker74797f82015-03-31 15:44:34 -07001197 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001198 throwStateException(env, "DRM plugin failure: unknown key request type",
1199 ERROR_DRM_UNKNOWN);
1200 break;
1201 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001202 }
1203
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001204 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001205}
1206
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001207static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001208 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1209 sp<IDrm> drm = GetDrm(env, thiz);
1210
1211 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001212 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001213 }
1214
1215 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1216
1217 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001218 jniThrowException(env, "java/lang/IllegalArgumentException",
1219 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001220 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001221 }
1222 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001223 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001224
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301225 DrmStatus err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001226
Robert Shih60dab872021-02-13 11:24:59 -08001227 if (throwExceptionAsNecessary(env, drm, err, "Failed to handle key response")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001228 return NULL;
1229 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001230 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001231}
1232
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001233static void android_media_MediaDrm_removeKeys(
1234 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1235 sp<IDrm> drm = GetDrm(env, thiz);
1236
Jeff Tinker55d26242018-10-10 16:10:43 -07001237 if (!CheckDrm(env, drm)) {
1238 return;
1239 }
1240
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001241 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001242 jniThrowException(env, "java/lang/IllegalArgumentException",
1243 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001244 return;
1245 }
1246
1247 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1248
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301249 DrmStatus err = drm->removeKeys(keySetId);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001250
Robert Shih60dab872021-02-13 11:24:59 -08001251 throwExceptionAsNecessary(env, drm, err, "Failed to remove keys");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001252}
1253
1254static void android_media_MediaDrm_restoreKeys(
1255 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1256 jbyteArray jkeysetId) {
1257
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001258 sp<IDrm> drm = GetDrm(env, thiz);
1259
1260 if (!CheckSession(env, drm, jsessionId)) {
1261 return;
1262 }
1263
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001264 if (jkeysetId == NULL) {
1265 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1266 return;
1267 }
1268
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001269 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001270 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001271
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301272 DrmStatus err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001273
Robert Shih60dab872021-02-13 11:24:59 -08001274 throwExceptionAsNecessary(env, drm, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001275}
1276
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001277static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001278 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1279 sp<IDrm> drm = GetDrm(env, thiz);
1280
1281 if (!CheckSession(env, drm, jsessionId)) {
1282 return NULL;
1283 }
1284 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1285
1286 KeyedVector<String8, String8> infoMap;
1287
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301288 DrmStatus err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001289
Robert Shih60dab872021-02-13 11:24:59 -08001290 if (throwExceptionAsNecessary(env, drm, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001291 return NULL;
1292 }
1293
1294 return KeyedVectorToHashMap(env, infoMap);
1295}
1296
Jeff Tinkere4095a82014-03-04 13:17:11 -08001297static jobject android_media_MediaDrm_getProvisionRequestNative(
1298 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001299 sp<IDrm> drm = GetDrm(env, thiz);
1300
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001301 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001302 return NULL;
1303 }
1304
1305 Vector<uint8_t> request;
1306 String8 defaultUrl;
1307
Jeff Tinkere4095a82014-03-04 13:17:11 -08001308 String8 certType;
1309 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1310 certType = "X.509";
1311 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1312 certType = "none";
1313 } else {
1314 certType = "invalid";
1315 }
1316
1317 String8 certAuthority = JStringToString8(env, jcertAuthority);
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301318 DrmStatus err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001319
Robert Shih60dab872021-02-13 11:24:59 -08001320 if (throwExceptionAsNecessary(env, drm, err, "Failed to get provision request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001321 return NULL;
1322 }
1323
1324 // Fill out return obj
1325 jclass clazz;
1326 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1327
1328 jobject provisionObj = NULL;
1329
1330 if (clazz) {
1331 provisionObj = env->AllocObject(clazz);
1332 jbyteArray jrequest = VectorToJByteArray(env, request);
1333 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1334
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001335 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001336 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1337 }
1338
1339 return provisionObj;
1340}
1341
Jeff Tinkere4095a82014-03-04 13:17:11 -08001342static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001343 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1344 sp<IDrm> drm = GetDrm(env, thiz);
1345
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001346 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001347 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001348 }
1349
1350 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001351 jniThrowException(env, "java/lang/IllegalArgumentException",
1352 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001353 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001354 }
1355
1356 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001357 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001358
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301359 DrmStatus err = drm->provideProvisionResponse(response, certificate, wrappedKey);
Jeff Tinkere4095a82014-03-04 13:17:11 -08001360
1361 // Fill out return obj
1362 jclass clazz = gFields.certificateClassId;
1363
1364 jobject certificateObj = NULL;
1365
1366 if (clazz && certificate.size() && wrappedKey.size()) {
1367 certificateObj = env->AllocObject(clazz);
1368 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1369 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1370
1371 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1372 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1373 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001374
Robert Shih60dab872021-02-13 11:24:59 -08001375 throwExceptionAsNecessary(env, drm, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001376 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001377}
1378
1379static jobject android_media_MediaDrm_getSecureStops(
1380 JNIEnv *env, jobject thiz) {
1381 sp<IDrm> drm = GetDrm(env, thiz);
1382
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001383 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001384 return NULL;
1385 }
1386
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001387 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001388
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301389 DrmStatus err = drm->getSecureStops(secureStops);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001390
Robert Shih60dab872021-02-13 11:24:59 -08001391 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stops")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001392 return NULL;
1393 }
1394
1395 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1396}
1397
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001398static jobject android_media_MediaDrm_getSecureStopIds(
1399 JNIEnv *env, jobject thiz) {
1400 sp<IDrm> drm = GetDrm(env, thiz);
1401
Jeff Tinker55d26242018-10-10 16:10:43 -07001402 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001403 return NULL;
1404 }
1405
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001406 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001407
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301408 DrmStatus err = drm->getSecureStopIds(secureStopIds);
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001409
Robert Shih60dab872021-02-13 11:24:59 -08001410 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop Ids")) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001411 return NULL;
1412 }
1413
1414 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1415}
1416
Jeff Tinker1b51c722014-10-31 00:54:26 -07001417static jbyteArray android_media_MediaDrm_getSecureStop(
1418 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1419 sp<IDrm> drm = GetDrm(env, thiz);
1420
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001421 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001422 return NULL;
1423 }
1424
1425 Vector<uint8_t> secureStop;
1426
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301427 DrmStatus err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
Jeff Tinker1b51c722014-10-31 00:54:26 -07001428
Robert Shih60dab872021-02-13 11:24:59 -08001429 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop")) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001430 return NULL;
1431 }
1432
1433 return VectorToJByteArray(env, secureStop);
1434}
1435
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001436static void android_media_MediaDrm_releaseSecureStops(
1437 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1438 sp<IDrm> drm = GetDrm(env, thiz);
1439
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001440 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001441 return;
1442 }
1443
1444 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1445
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301446 DrmStatus err = drm->releaseSecureStops(ssRelease);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001447
Robert Shih60dab872021-02-13 11:24:59 -08001448 throwExceptionAsNecessary(env, drm, err, "Failed to release secure stops");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001449}
1450
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001451static void android_media_MediaDrm_removeSecureStop(
1452 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1453 sp<IDrm> drm = GetDrm(env, thiz);
1454
Jeff Tinker55d26242018-10-10 16:10:43 -07001455 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001456 return;
1457 }
1458
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301459 DrmStatus err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001460
Robert Shih60dab872021-02-13 11:24:59 -08001461 throwExceptionAsNecessary(env, drm, err, "Failed to remove secure stop");
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001462}
1463
1464static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001465 JNIEnv *env, jobject thiz) {
1466 sp<IDrm> drm = GetDrm(env, thiz);
1467
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001468 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001469 return;
1470 }
1471
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301472 DrmStatus err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001473
Robert Shih60dab872021-02-13 11:24:59 -08001474 throwExceptionAsNecessary(env, drm, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001475}
1476
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001477
1478static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1479 switch(level) {
1480 case DrmPlugin::kHdcpLevelUnknown:
1481 return gHdcpLevels.kHdcpLevelUnknown;
1482 case DrmPlugin::kHdcpNone:
1483 return gHdcpLevels.kHdcpNone;
1484 case DrmPlugin::kHdcpV1:
1485 return gHdcpLevels.kHdcpV1;
1486 case DrmPlugin::kHdcpV2:
1487 return gHdcpLevels.kHdcpV2;
1488 case DrmPlugin::kHdcpV2_1:
1489 return gHdcpLevels.kHdcpV2_1;
1490 case DrmPlugin::kHdcpV2_2:
1491 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001492 case DrmPlugin::kHdcpV2_3:
1493 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001494 case DrmPlugin::kHdcpNoOutput:
1495 return gHdcpLevels.kHdcpNoOutput;
1496 }
1497 return gHdcpLevels.kHdcpNone;
1498}
1499
1500static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1501 jobject thiz) {
1502 sp<IDrm> drm = GetDrm(env, thiz);
1503
1504 if (!CheckDrm(env, drm)) {
1505 return gHdcpLevels.kHdcpNone;
1506 }
1507
1508 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1509 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1510
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301511 DrmStatus err = drm->getHdcpLevels(&connected, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001512
Robert Shih60dab872021-02-13 11:24:59 -08001513 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001514 return gHdcpLevels.kHdcpLevelUnknown;
1515 }
1516 return HdcpLevelTojint(connected);
1517}
1518
1519static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1520 jobject thiz) {
1521 sp<IDrm> drm = GetDrm(env, thiz);
1522
1523 if (!CheckDrm(env, drm)) {
1524 return gHdcpLevels.kHdcpLevelUnknown;
1525 }
1526
1527 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1528 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1529
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301530 DrmStatus err = drm->getHdcpLevels(&connected, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001531
Robert Shih60dab872021-02-13 11:24:59 -08001532 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001533 return gHdcpLevels.kHdcpLevelUnknown;
1534 }
1535 return HdcpLevelTojint(max);
1536}
1537
1538static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1539 jobject thiz) {
1540 sp<IDrm> drm = GetDrm(env, thiz);
1541
1542 if (!CheckDrm(env, drm)) {
1543 return 0;
1544 }
1545
1546 uint32_t open = 0, max = 0;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301547 DrmStatus err = drm->getNumberOfSessions(&open, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001548
Robert Shih60dab872021-02-13 11:24:59 -08001549 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001550 return 0;
1551 }
1552 return open;
1553}
1554
1555static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1556 jobject thiz) {
1557 sp<IDrm> drm = GetDrm(env, thiz);
1558
1559 if (!CheckDrm(env, drm)) {
1560 return 0;
1561 }
1562
1563 uint32_t open = 0, max = 0;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301564 DrmStatus err = drm->getNumberOfSessions(&open, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001565
Robert Shih60dab872021-02-13 11:24:59 -08001566 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001567 return 0;
1568 }
1569 return max;
1570}
1571
1572static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1573 jobject thiz, jbyteArray jsessionId) {
1574 sp<IDrm> drm = GetDrm(env, thiz);
1575
1576 if (!CheckSession(env, drm, jsessionId)) {
1577 return gSecurityLevels.kSecurityLevelUnknown;
1578 }
1579
1580 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1581
1582 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1583
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301584 DrmStatus err = drm->getSecurityLevel(sessionId, &level);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001585
Robert Shih60dab872021-02-13 11:24:59 -08001586 if (throwExceptionAsNecessary(env, drm, err, "Failed to get security level")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001587 return gSecurityLevels.kSecurityLevelUnknown;
1588 }
1589
1590 switch(level) {
1591 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1592 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1593 case DrmPlugin::kSecurityLevelSwSecureDecode:
1594 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1595 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1596 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1597 case DrmPlugin::kSecurityLevelHwSecureDecode:
1598 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1599 case DrmPlugin::kSecurityLevelHwSecureAll:
1600 return gSecurityLevels.kSecurityLevelHwSecureAll;
1601 default:
1602 return gSecurityLevels.kSecurityLevelUnknown;
1603 }
1604}
1605
Jeff Tinker55d26242018-10-10 16:10:43 -07001606static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1607 JNIEnv *env, jobject thiz) {
1608 sp<IDrm> drm = GetDrm(env, thiz);
1609
1610 if (!CheckDrm(env, drm)) {
1611 return NULL;
1612 }
1613
1614 List<Vector<uint8_t> > keySetIds;
1615
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301616 DrmStatus err = drm->getOfflineLicenseKeySetIds(keySetIds);
Jeff Tinker55d26242018-10-10 16:10:43 -07001617
Robert Shih60dab872021-02-13 11:24:59 -08001618 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline key set Ids")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001619 return NULL;
1620 }
1621
1622 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1623}
1624
1625static void android_media_MediaDrm_removeOfflineLicense(
1626 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1627 sp<IDrm> drm = GetDrm(env, thiz);
1628
1629 if (!CheckDrm(env, drm)) {
1630 return;
1631 }
1632
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301633 DrmStatus err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
Jeff Tinker55d26242018-10-10 16:10:43 -07001634
Robert Shih60dab872021-02-13 11:24:59 -08001635 throwExceptionAsNecessary(env, drm, err, "Failed to remove offline license");
Jeff Tinker55d26242018-10-10 16:10:43 -07001636}
1637
1638static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1639 jobject thiz, jbyteArray jkeySetId) {
1640 sp<IDrm> drm = GetDrm(env, thiz);
1641
1642 if (!CheckDrm(env, drm)) {
1643 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1644 }
1645
1646 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1647
1648 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1649
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301650 DrmStatus err = drm->getOfflineLicenseState(keySetId, &state);
Jeff Tinker55d26242018-10-10 16:10:43 -07001651
Robert Shih60dab872021-02-13 11:24:59 -08001652 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline license state")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001653 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1654 }
1655
1656 switch(state) {
1657 case DrmPlugin::kOfflineLicenseStateUsable:
1658 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -08001659 case DrmPlugin::kOfflineLicenseStateReleased:
1660 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -07001661 default:
1662 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1663 }
1664}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001665
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001666static jstring android_media_MediaDrm_getPropertyString(
1667 JNIEnv *env, jobject thiz, jstring jname) {
1668 sp<IDrm> drm = GetDrm(env, thiz);
1669
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001670 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001671 return NULL;
1672 }
1673
1674 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001675 jniThrowException(env, "java/lang/IllegalArgumentException",
1676 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001677 return NULL;
1678 }
1679
1680 String8 name = JStringToString8(env, jname);
1681 String8 value;
1682
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301683 DrmStatus err = drm->getPropertyString(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001684
Robert Shih60dab872021-02-13 11:24:59 -08001685 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001686 return NULL;
1687 }
1688
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001689 return env->NewStringUTF(value.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001690}
1691
1692static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1693 JNIEnv *env, jobject thiz, jstring jname) {
1694 sp<IDrm> drm = GetDrm(env, thiz);
1695
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001696 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001697 return NULL;
1698 }
1699
1700 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001701 jniThrowException(env, "java/lang/IllegalArgumentException",
1702 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001703 return NULL;
1704 }
1705
1706 String8 name = JStringToString8(env, jname);
1707 Vector<uint8_t> value;
1708
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301709 DrmStatus err = drm->getPropertyByteArray(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001710
Robert Shih60dab872021-02-13 11:24:59 -08001711 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001712 return NULL;
1713 }
1714
1715 return VectorToJByteArray(env, value);
1716}
1717
1718static void android_media_MediaDrm_setPropertyString(
1719 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1720 sp<IDrm> drm = GetDrm(env, thiz);
1721
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001722 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001723 return;
1724 }
1725
Jeff Tinkereada5372013-05-21 12:48:14 -07001726 if (jname == NULL) {
1727 jniThrowException(env, "java/lang/IllegalArgumentException",
1728 "property name String is null");
1729 return;
1730 }
1731
1732 if (jvalue == NULL) {
1733 jniThrowException(env, "java/lang/IllegalArgumentException",
1734 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001735 return;
1736 }
1737
1738 String8 name = JStringToString8(env, jname);
1739 String8 value = JStringToString8(env, jvalue);
1740
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301741 DrmStatus err = drm->setPropertyString(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001742
Robert Shih60dab872021-02-13 11:24:59 -08001743 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001744}
1745
1746static void android_media_MediaDrm_setPropertyByteArray(
1747 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1748 sp<IDrm> drm = GetDrm(env, thiz);
1749
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001750 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001751 return;
1752 }
1753
Jeff Tinkereada5372013-05-21 12:48:14 -07001754 if (jname == NULL) {
1755 jniThrowException(env, "java/lang/IllegalArgumentException",
1756 "property name String is null");
1757 return;
1758 }
1759
1760 if (jvalue == NULL) {
1761 jniThrowException(env, "java/lang/IllegalArgumentException",
1762 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001763 return;
1764 }
1765
1766 String8 name = JStringToString8(env, jname);
1767 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1768
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301769 DrmStatus err = drm->setPropertyByteArray(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001770
Robert Shih60dab872021-02-13 11:24:59 -08001771 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001772}
1773
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001774static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001775 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001776 jstring jalgorithm) {
1777
1778 sp<IDrm> drm = GetDrm(env, jdrm);
1779
1780 if (!CheckSession(env, drm, jsessionId)) {
1781 return;
1782 }
1783
1784 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001785 jniThrowException(env, "java/lang/IllegalArgumentException",
1786 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001787 return;
1788 }
1789
1790 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1791 String8 algorithm = JStringToString8(env, jalgorithm);
1792
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301793 DrmStatus err = drm->setCipherAlgorithm(sessionId, algorithm);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001794
Robert Shih60dab872021-02-13 11:24:59 -08001795 throwExceptionAsNecessary(env, drm, err, "Failed to set cipher algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001796}
1797
1798static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001799 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001800 jstring jalgorithm) {
1801
1802 sp<IDrm> drm = GetDrm(env, jdrm);
1803
1804 if (!CheckSession(env, drm, jsessionId)) {
1805 return;
1806 }
1807
1808 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001809 jniThrowException(env, "java/lang/IllegalArgumentException",
1810 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001811 return;
1812 }
1813
1814 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1815 String8 algorithm = JStringToString8(env, jalgorithm);
1816
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301817 DrmStatus err = drm->setMacAlgorithm(sessionId, algorithm);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001818
Robert Shih60dab872021-02-13 11:24:59 -08001819 throwExceptionAsNecessary(env, drm, err, "Failed to set mac algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001820}
1821
1822
1823static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001824 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001825 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1826
1827 sp<IDrm> drm = GetDrm(env, jdrm);
1828
1829 if (!CheckSession(env, drm, jsessionId)) {
1830 return NULL;
1831 }
1832
1833 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001834 jniThrowException(env, "java/lang/IllegalArgumentException",
1835 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001836 return NULL;
1837 }
1838
1839 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1840 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1841 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1842 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1843 Vector<uint8_t> output;
1844
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301845 DrmStatus err = drm->encrypt(sessionId, keyId, input, iv, output);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001846
Robert Shih60dab872021-02-13 11:24:59 -08001847 if (throwExceptionAsNecessary(env, drm, err, "Failed to encrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001848 return NULL;
1849 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001850
1851 return VectorToJByteArray(env, output);
1852}
1853
1854static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001855 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001856 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1857
1858 sp<IDrm> drm = GetDrm(env, jdrm);
1859
1860 if (!CheckSession(env, drm, jsessionId)) {
1861 return NULL;
1862 }
1863
1864 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001865 jniThrowException(env, "java/lang/IllegalArgumentException",
1866 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001867 return NULL;
1868 }
1869
1870 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1871 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1872 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1873 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1874 Vector<uint8_t> output;
1875
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301876 DrmStatus err = drm->decrypt(sessionId, keyId, input, iv, output);
Robert Shih60dab872021-02-13 11:24:59 -08001877 if (throwExceptionAsNecessary(env, drm, err, "Failed to decrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001878 return NULL;
1879 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001880
1881 return VectorToJByteArray(env, output);
1882}
1883
1884static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001885 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001886 jbyteArray jkeyId, jbyteArray jmessage) {
1887
1888 sp<IDrm> drm = GetDrm(env, jdrm);
1889
1890 if (!CheckSession(env, drm, jsessionId)) {
1891 return NULL;
1892 }
1893
1894 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001895 jniThrowException(env, "java/lang/IllegalArgumentException",
1896 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001897 return NULL;
1898 }
1899
1900 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1901 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1902 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1903 Vector<uint8_t> signature;
1904
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301905 DrmStatus err = drm->sign(sessionId, keyId, message, signature);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001906
Robert Shih60dab872021-02-13 11:24:59 -08001907 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001908 return NULL;
1909 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001910
1911 return VectorToJByteArray(env, signature);
1912}
1913
1914static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001915 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001916 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1917
1918 sp<IDrm> drm = GetDrm(env, jdrm);
1919
1920 if (!CheckSession(env, drm, jsessionId)) {
1921 return false;
1922 }
1923
1924 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001925 jniThrowException(env, "java/lang/IllegalArgumentException",
1926 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001927 return false;
1928 }
1929
1930 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1931 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1932 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1933 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1934 bool match;
1935
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301936 DrmStatus err = drm->verify(sessionId, keyId, message, signature, match);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001937
Robert Shih60dab872021-02-13 11:24:59 -08001938 throwExceptionAsNecessary(env, drm, err, "Failed to verify");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001939 return match;
1940}
1941
Adam Stonec06e10e2017-12-19 12:54:33 -08001942static jobject
1943android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1944{
1945 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001946
1947 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001948 return NULL;
1949 }
1950
1951 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001952 PersistableBundle metrics;
Robert Shihba6777e2019-11-12 13:04:59 -08001953 sp<IDrmMetricsConsumer> consumer(new DrmMetricsConsumer(&metrics));
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301954 DrmStatus err = drm->getMetrics(consumer);
Adam Stonec06e10e2017-12-19 12:54:33 -08001955 if (err != OK) {
1956 ALOGE("getMetrics failed: %d", (int)err);
1957 return (jobject) NULL;
1958 }
1959
Robert Shih4354a962019-11-10 12:09:08 -08001960 return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001961}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001962
Jeff Tinkere4095a82014-03-04 13:17:11 -08001963static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001964 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001965 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1966
1967 sp<IDrm> drm = GetDrm(env, jdrm);
1968
1969 if (!CheckSession(env, drm, jsessionId)) {
1970 return NULL;
1971 }
1972
1973 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1974 jniThrowException(env, "java/lang/IllegalArgumentException",
1975 "required argument is null");
1976 return NULL;
1977 }
1978
1979 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1980 String8 algorithm = JStringToString8(env, jalgorithm);
1981 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1982 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1983 Vector<uint8_t> signature;
1984
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301985 DrmStatus err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
Jeff Tinkere4095a82014-03-04 13:17:11 -08001986
Robert Shih60dab872021-02-13 11:24:59 -08001987 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001988 return NULL;
1989 }
1990
1991 return VectorToJByteArray(env, signature);
1992}
1993
Robert Shih205f7a92021-01-19 21:12:10 -08001994static jboolean android_media_MediaDrm_requiresSecureDecoder(
1995 JNIEnv *env, jobject thiz, jstring jmimeType,
1996 jint jSecurityLevel) {
1997 sp<IDrm> drm = GetDrm(env, thiz);
1998 if (!CheckDrm(env, drm)) {
1999 return JNI_FALSE;
2000 }
2001
2002 String8 mimeType;
2003 if (jmimeType != NULL) {
2004 mimeType = JStringToString8(env, jmimeType);
2005 }
2006
2007 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
2008 if (securityLevel == DrmPlugin::kSecurityLevelUnknown) {
2009 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
2010 return JNI_FALSE;
2011 }
2012
Robert Shih5bb242a2021-04-28 10:04:51 -07002013 bool required = false;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302014 DrmStatus err = OK;
Robert Shih205f7a92021-01-19 21:12:10 -08002015 if (securityLevel == DrmPlugin::kSecurityLevelMax) {
Robert Shih5bb242a2021-04-28 10:04:51 -07002016 err = drm->requiresSecureDecoder(mimeType.c_str(), &required);
2017 } else {
2018 err = drm->requiresSecureDecoder(mimeType.c_str(), securityLevel, &required);
Robert Shih205f7a92021-01-19 21:12:10 -08002019 }
Robert Shih5bb242a2021-04-28 10:04:51 -07002020 if (throwExceptionAsNecessary(env, drm, err, "Failed to query secure decoder requirement")) {
2021 return false;
2022 }
2023 return required;
Robert Shih205f7a92021-01-19 21:12:10 -08002024}
Jeff Tinkere4095a82014-03-04 13:17:11 -08002025
Robert Shih02937122021-01-20 00:05:20 -08002026static void android_media_MediaDrm_setPlaybackId(
2027 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
2028 jstring jplaybackId) {
2029 sp<IDrm> drm = GetDrm(env, thiz);
2030 if (!CheckSession(env, drm, jsessionId)) {
2031 return;
2032 }
2033
2034 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2035
2036 String8 playbackId;
2037 if (jplaybackId != NULL) {
2038 playbackId = JStringToString8(env, jplaybackId);
2039 }
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302040 DrmStatus err = drm->setPlaybackId(sessionId, playbackId.c_str());
Robert Shih60dab872021-02-13 11:24:59 -08002041 throwExceptionAsNecessary(env, drm, err, "Failed to set playbackId");
Robert Shih02937122021-01-20 00:05:20 -08002042}
2043
Robert Shih696989f2021-02-12 23:25:16 -08002044static jobject android_media_MediaDrm_getLogMessages(
2045 JNIEnv *env, jobject thiz) {
2046 sp<IDrm> drm = GetDrm(env, thiz);
2047 if (!CheckDrm(env, drm)) {
2048 return NULL;
2049 }
2050
2051 Vector<drm::V1_4::LogMessage> logs;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302052 DrmStatus err = drm->getLogMessages(logs);
Robert Shih696989f2021-02-12 23:25:16 -08002053 ALOGI("drm->getLogMessages %zu logs", logs.size());
Robert Shih60dab872021-02-13 11:24:59 -08002054 if (throwExceptionAsNecessary(env, drm, err, "Failed to get log messages")) {
Robert Shih696989f2021-02-12 23:25:16 -08002055 return NULL;
2056 }
2057 return hidlLogMessagesToJavaList(env, logs);
2058}
2059
Daniel Micay76f6a862015-09-19 17:31:01 -04002060static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002061 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
2062
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002063 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
2064
Edwin Wong4d1d84e2017-01-04 09:37:49 -08002065 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002066 (void *)android_media_MediaDrm_native_setup },
2067
Robert Shihd2e8b432019-11-21 20:27:56 -08002068 { "getSupportedCryptoSchemesNative", "()[B",
2069 (void *)android_media_MediaDrm_getSupportedCryptoSchemesNative },
2070
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08002071 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002072 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
2073
Robert Shih02937122021-01-20 00:05:20 -08002074 { "openSessionNative", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002075 (void *)android_media_MediaDrm_openSession },
2076
Robert Shih02937122021-01-20 00:05:20 -08002077 { "closeSessionNative", "([B)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002078 (void *)android_media_MediaDrm_closeSession },
2079
Robert Shih890eb572021-01-19 08:16:39 -08002080 { "getKeyRequestNative", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002081 "Landroid/media/MediaDrm$KeyRequest;",
2082 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002083
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002084 { "provideKeyResponse", "([B[B)[B",
2085 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002086
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002087 { "removeKeys", "([B)V",
2088 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002089
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002090 { "restoreKeys", "([B[B)V",
2091 (void *)android_media_MediaDrm_restoreKeys },
2092
2093 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
2094 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002095
Jeff Tinkere4095a82014-03-04 13:17:11 -08002096 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
2097 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002098
Jeff Tinkere4095a82014-03-04 13:17:11 -08002099 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
2100 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002101
2102 { "getSecureStops", "()Ljava/util/List;",
2103 (void *)android_media_MediaDrm_getSecureStops },
2104
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002105 { "getSecureStopIds", "()Ljava/util/List;",
2106 (void *)android_media_MediaDrm_getSecureStopIds },
2107
Jeff Tinker1b51c722014-10-31 00:54:26 -07002108 { "getSecureStop", "([B)[B",
2109 (void *)android_media_MediaDrm_getSecureStop },
2110
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002111 { "releaseSecureStops", "([B)V",
2112 (void *)android_media_MediaDrm_releaseSecureStops },
2113
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002114 { "removeSecureStop", "([B)V",
2115 (void *)android_media_MediaDrm_removeSecureStop },
2116
2117 { "removeAllSecureStops", "()V",
2118 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07002119
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002120 { "getConnectedHdcpLevel", "()I",
2121 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
2122
2123 { "getMaxHdcpLevel", "()I",
2124 (void *)android_media_MediaDrm_getMaxHdcpLevel },
2125
2126 { "getOpenSessionCount", "()I",
2127 (void *)android_media_MediaDrm_getOpenSessionCount },
2128
2129 { "getMaxSessionCount", "()I",
2130 (void *)android_media_MediaDrm_getMaxSessionCount },
2131
2132 { "getSecurityLevel", "([B)I",
2133 (void *)android_media_MediaDrm_getSecurityLevel },
2134
Jeff Tinker55d26242018-10-10 16:10:43 -07002135 { "removeOfflineLicense", "([B)V",
2136 (void *)android_media_MediaDrm_removeOfflineLicense },
2137
2138 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
2139 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
2140
2141 { "getOfflineLicenseState", "([B)I",
2142 (void *)android_media_MediaDrm_getOfflineLicenseState },
2143
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002144 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2145 (void *)android_media_MediaDrm_getPropertyString },
2146
2147 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2148 (void *)android_media_MediaDrm_getPropertyByteArray },
2149
2150 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2151 (void *)android_media_MediaDrm_setPropertyString },
2152
2153 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2154 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002155
2156 { "setCipherAlgorithmNative",
2157 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2158 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2159
2160 { "setMacAlgorithmNative",
2161 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2162 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2163
2164 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2165 (void *)android_media_MediaDrm_encryptNative },
2166
2167 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2168 (void *)android_media_MediaDrm_decryptNative },
2169
2170 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2171 (void *)android_media_MediaDrm_signNative },
2172
2173 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2174 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002175
2176 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2177 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002178
2179 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2180 (void *)android_media_MediaDrm_native_getMetrics },
Robert Shih205f7a92021-01-19 21:12:10 -08002181
2182 { "requiresSecureDecoder", "(Ljava/lang/String;I)Z",
2183 (void *)android_media_MediaDrm_requiresSecureDecoder },
Robert Shih02937122021-01-20 00:05:20 -08002184
2185 { "setPlaybackId", "([BLjava/lang/String;)V",
2186 (void *)android_media_MediaDrm_setPlaybackId },
Robert Shih696989f2021-02-12 23:25:16 -08002187
2188 { "getLogMessages", "()Ljava/util/List;",
2189 (void *)android_media_MediaDrm_getLogMessages },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002190};
2191
2192int register_android_media_Drm(JNIEnv *env) {
2193 return AndroidRuntime::registerNativeMethods(env,
2194 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2195}