blob: 48cd53dc44d7ac80f80c66d39d8eebe8aa62e5d6 [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
Marvin Ramin00c82542024-03-18 16:03:03 +010030#include <android_companion_virtualdevice_flags.h>
31#include <android/companion/virtualnative/IVirtualDeviceManagerNative.h>
Robert Shihd2e8b432019-11-21 20:27:56 -080032#include <android/hardware/drm/1.3/IDrmFactory.h>
Jeff Tinker54cfbd62013-04-02 13:14:59 -070033#include <binder/Parcel.h>
Adam Stone94395c92018-01-30 12:07:00 -080034#include <binder/PersistableBundle.h>
Jeff Tinkerdc614f82016-02-12 08:58:32 -080035#include <cutils/properties.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080036#include <media/stagefright/foundation/ADebug.h>
Jeff Tinkerf7568b52013-04-17 14:24:40 -070037#include <media/stagefright/MediaErrors.h>
Robert Shihba6777e2019-11-12 13:04:59 -080038#include <mediadrm/DrmMetricsConsumer.h>
Robert Shih218b9532019-08-15 14:48:11 -070039#include <mediadrm/DrmUtils.h>
Robert Shihba6777e2019-11-12 13:04:59 -080040#include <mediadrm/IDrmMetricsConsumer.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080041#include <mediadrm/IDrm.h>
Robert Shih696989f2021-02-12 23:25:16 -080042#include <utils/Vector.h>
Kyle Zhangb61d8022023-10-04 00:14:59 +000043#include <map>
44#include <string>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080045
Marvin Ramin00c82542024-03-18 16:03:03 +010046using ::android::companion::virtualnative::IVirtualDeviceManagerNative;
Adam Stone94395c92018-01-30 12:07:00 -080047using ::android::os::PersistableBundle;
Robert Shihd2e8b432019-11-21 20:27:56 -080048namespace drm = ::android::hardware::drm;
Marvin Ramin00c82542024-03-18 16:03:03 +010049namespace virtualdevice_flags = android::companion::virtualdevice::flags;
Adam Stone94395c92018-01-30 12:07:00 -080050
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080051namespace android {
52
53#define FIND_CLASS(var, className) \
54 var = env->FindClass(className); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070055 LOG_FATAL_IF(! (var), "Unable to find class %s", className);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080056
57#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
58 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070059 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080060
61#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
62 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070063 LOG_FATAL_IF(! (var), "Unable to find method %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080064
Jeff Tinker54cfbd62013-04-02 13:14:59 -070065#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
66 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070067 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070068
69#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
70 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070071 LOG_FATAL_IF(! (var), "Unable to find static method %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070072
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070073#define GET_STATIC_OBJECT_FIELD(var, clazz, fieldId) \
74 var = env->GetStaticObjectField(clazz, fieldId); \
75 LOG_FATAL_IF(! (var), "Unable to find static object field %p", fieldId);
Adam Stone94395c92018-01-30 12:07:00 -080076
Jeff Tinker54cfbd62013-04-02 13:14:59 -070077
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080078struct RequestFields {
79 jfieldID data;
80 jfieldID defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -070081 jfieldID requestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080082};
83
84struct ArrayListFields {
85 jmethodID init;
86 jmethodID add;
87};
88
89struct HashmapFields {
90 jmethodID init;
91 jmethodID get;
92 jmethodID put;
93 jmethodID entrySet;
94};
95
96struct SetFields {
97 jmethodID iterator;
98};
99
100struct IteratorFields {
101 jmethodID next;
102 jmethodID hasNext;
103};
104
105struct EntryFields {
106 jmethodID getKey;
107 jmethodID getValue;
108};
109
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700110struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -0700111 jint kEventProvisionRequired;
112 jint kEventKeyRequired;
113 jint kEventKeyExpired;
114 jint kEventVendorDefined;
Ronghua Wua6d72092015-03-04 11:16:02 -0800115 jint kEventSessionReclaimed;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700116} gEventTypes;
117
Jeff Tinker74797f82015-03-31 15:44:34 -0700118struct EventWhat {
119 jint kWhatDrmEvent;
120 jint kWhatExpirationUpdate;
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700121 jint kWhatKeyStatusChange;
Jeff Tinker20594d82018-12-12 08:31:22 -0800122 jint kWhatSessionLostState;
Jeff Tinker74797f82015-03-31 15:44:34 -0700123} gEventWhat;
124
Jeff Tinker17b89222013-05-21 12:35:06 -0700125struct KeyTypes {
126 jint kKeyTypeStreaming;
127 jint kKeyTypeOffline;
128 jint kKeyTypeRelease;
129} gKeyTypes;
130
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700131struct KeyRequestTypes {
132 jint kKeyRequestTypeInitial;
133 jint kKeyRequestTypeRenewal;
134 jint kKeyRequestTypeRelease;
Rahul Frias8f761ba2018-01-22 23:43:54 -0800135 jint kKeyRequestTypeNone;
136 jint kKeyRequestTypeUpdate;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700137} gKeyRequestTypes;
138
Jeff Tinkere4095a82014-03-04 13:17:11 -0800139struct CertificateTypes {
140 jint kCertificateTypeNone;
141 jint kCertificateTypeX509;
142} gCertificateTypes;
143
144struct CertificateFields {
145 jfieldID wrappedPrivateKey;
146 jfieldID certificateData;
147};
148
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700149struct StateExceptionFields {
150 jmethodID init;
151 jclass classId;
152};
153
Jeff Tinker20594d82018-12-12 08:31:22 -0800154struct SessionExceptionFields {
155 jmethodID init;
156 jclass classId;
157 jfieldID errorCode;
158};
159
160struct SessionExceptionErrorCodes {
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800161 jint kErrorUnknown;
Jeff Tinker20594d82018-12-12 08:31:22 -0800162 jint kResourceContention;
163} gSessionExceptionErrorCodes;
164
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800165struct HDCPLevels {
166 jint kHdcpLevelUnknown;
167 jint kHdcpNone;
168 jint kHdcpV1;
169 jint kHdcpV2;
170 jint kHdcpV2_1;
171 jint kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800172 jint kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800173 jint kHdcpNoOutput;
174} gHdcpLevels;
175
176struct SecurityLevels {
177 jint kSecurityLevelUnknown;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000178 jint kSecurityLevelMax;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800179 jint kSecurityLevelSwSecureCrypto;
180 jint kSecurityLevelSwSecureDecode;
181 jint kSecurityLevelHwSecureCrypto;
182 jint kSecurityLevelHwSecureDecode;
183 jint kSecurityLevelHwSecureAll;
184} gSecurityLevels;
185
Jeff Tinker55d26242018-10-10 16:10:43 -0700186struct OfflineLicenseState {
187 jint kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800188 jint kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -0700189 jint kOfflineLicenseStateUnknown;
190} gOfflineLicenseStates;
191
Robert Shih9d4e2d42019-11-08 13:51:49 -0800192struct KeyStatusFields {
193 jmethodID init;
194 jclass classId;
195};
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800196
Robert Shih696989f2021-02-12 23:25:16 -0800197struct LogMessageFields {
198 jmethodID init;
199 jclass classId;
200};
201
Kyle Zhangb61d8022023-10-04 00:14:59 +0000202struct DrmExceptionFields {
203 jmethodID init;
204 jclass classId;
205};
206
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800207struct fields_t {
208 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700209 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700210 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800211 RequestFields provisionRequest;
212 ArrayListFields arraylist;
213 HashmapFields hashmap;
214 SetFields set;
215 IteratorFields iterator;
216 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800217 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700218 StateExceptionFields stateException;
Jeff Tinker20594d82018-12-12 08:31:22 -0800219 SessionExceptionFields sessionException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800220 jclass certificateClassId;
221 jclass hashmapClassId;
222 jclass arraylistClassId;
223 jclass stringClassId;
Adam Stone94395c92018-01-30 12:07:00 -0800224 jobject bundleCreator;
225 jmethodID createFromParcelId;
226 jclass parcelCreatorClassId;
Robert Shih9d4e2d42019-11-08 13:51:49 -0800227 KeyStatusFields keyStatus;
Robert Shih696989f2021-02-12 23:25:16 -0800228 LogMessageFields logMessage;
Kyle Zhangb61d8022023-10-04 00:14:59 +0000229 std::map<std::string, DrmExceptionFields> exceptionCtors;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800230};
231
232static fields_t gFields;
233
Adam Stone94395c92018-01-30 12:07:00 -0800234namespace {
235
Robert Shih9d4e2d42019-11-08 13:51:49 -0800236jbyteArray hidlVectorToJByteArray(const hardware::hidl_vec<uint8_t> &vector) {
237 JNIEnv *env = AndroidRuntime::getJNIEnv();
238 size_t length = vector.size();
239 jbyteArray result = env->NewByteArray(length);
240 if (result != NULL) {
241 env->SetByteArrayRegion(result, 0, length, reinterpret_cast<const jbyte *>(vector.data()));
242 }
243 return result;
244}
245
Robert Shih696989f2021-02-12 23:25:16 -0800246jobject hidlLogMessagesToJavaList(JNIEnv *env, const Vector<drm::V1_4::LogMessage> &logs) {
247 jclass clazz = gFields.arraylistClassId;
248 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
249 clazz = gFields.logMessage.classId;
250 for (auto log: logs) {
251 jobject jLog = env->NewObject(clazz, gFields.logMessage.init,
252 static_cast<jlong>(log.timeMs),
253 static_cast<jint>(log.priority),
254 env->NewStringUTF(log.message.c_str()));
255 env->CallBooleanMethod(arrayList, gFields.arraylist.add, jLog);
256 }
257 return arrayList;
258}
Robert Shih46849832022-12-15 10:30:51 -0800259
Kyle Zhangb61d8022023-10-04 00:14:59 +0000260void resolveDrmExceptionCtor(JNIEnv *env, const char *className) {
261 jclass clazz;
262 jmethodID init;
263 FIND_CLASS(clazz, className);
264 GET_METHOD_ID(init, clazz, "<init>", "(Ljava/lang/String;III)V");
265 gFields.exceptionCtors[std::string(className)] = {
266 .init = init,
267 .classId = static_cast<jclass>(env->NewGlobalRef(clazz))
268 };
269}
270
271void drmThrowException(JNIEnv* env, const char *className, const DrmStatus &err, const char *msg) {
Robert Shih46849832022-12-15 10:30:51 -0800272 using namespace android::jnihelp;
Kyle Zhangb61d8022023-10-04 00:14:59 +0000273
274 if (gFields.exceptionCtors.count(std::string(className)) == 0) {
275 jniThrowException(env, className, msg);
276 } else {
277 jstring _detailMessage = CreateExceptionMsg(env, msg);
278 jobject exception = env->NewObject(gFields.exceptionCtors[std::string(className)].classId,
279 gFields.exceptionCtors[std::string(className)].init, _detailMessage,
280 err.getCdmErr(), err.getOemErr(), err.getContext());
281 env->Throw(static_cast<jthrowable>(exception));
282 if (_detailMessage != NULL) {
283 env->DeleteLocalRef(_detailMessage);
284 }
Robert Shih46849832022-12-15 10:30:51 -0800285 }
Robert Shih46849832022-12-15 10:30:51 -0800286}
Adam Stone94395c92018-01-30 12:07:00 -0800287} // namespace anonymous
288
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700289// ----------------------------------------------------------------------------
290// ref-counted object for callbacks
291class JNIDrmListener: public DrmListener
292{
293public:
294 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
295 ~JNIDrmListener();
Robert Shih9d4e2d42019-11-08 13:51:49 -0800296 virtual void notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *arg = NULL);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700297private:
298 JNIDrmListener();
299 jclass mClass; // Reference to MediaDrm class
300 jobject mObject; // Weak ref to MediaDrm Java object to call on
301};
302
303JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
304{
305 // Hold onto the MediaDrm class for use in calling the static method
306 // that posts events to the application thread.
307 jclass clazz = env->GetObjectClass(thiz);
308 if (clazz == NULL) {
309 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700310 jniThrowException(env, "java/lang/Exception",
311 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700312 return;
313 }
314 mClass = (jclass)env->NewGlobalRef(clazz);
315
316 // We use a weak reference so the MediaDrm object can be garbage collected.
317 // The reference is only used as a proxy for callbacks.
318 mObject = env->NewGlobalRef(weak_thiz);
319}
320
321JNIDrmListener::~JNIDrmListener()
322{
323 // remove global references
324 JNIEnv *env = AndroidRuntime::getJNIEnv();
325 env->DeleteGlobalRef(mObject);
326 env->DeleteGlobalRef(mClass);
327}
328
329void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
Robert Shih9d4e2d42019-11-08 13:51:49 -0800330 const ListenerArgs *args)
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700331{
Jeff Tinker74797f82015-03-31 15:44:34 -0700332 jint jwhat;
333 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700334
335 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700336 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700337 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700338 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700339 jeventType = gEventTypes.kEventProvisionRequired;
340 break;
341 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700342 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700343 jeventType = gEventTypes.kEventKeyRequired;
344 break;
345 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700346 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700347 jeventType = gEventTypes.kEventKeyExpired;
348 break;
349 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700350 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700351 jeventType = gEventTypes.kEventVendorDefined;
352 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800353 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700354 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800355 jeventType = gEventTypes.kEventSessionReclaimed;
356 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700357 case DrmPlugin::kDrmPluginEventExpirationUpdate:
358 jwhat = gEventWhat.kWhatExpirationUpdate;
359 break;
360 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700361 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700362 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800363 case DrmPlugin::kDrmPluginEventSessionLostState:
364 jwhat = gEventWhat.kWhatSessionLostState;
365 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700366 default:
367 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
368 return;
369 }
370
371 JNIEnv *env = AndroidRuntime::getJNIEnv();
Robert Shih9d4e2d42019-11-08 13:51:49 -0800372 if (args) {
373 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
374 jwhat, jeventType, extra,
375 args->jSessionId, args->jData, args->jExpirationTime,
376 args->jKeyStatusList, args->jHasNewUsableKey);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700377 }
378
379 if (env->ExceptionCheck()) {
380 ALOGW("An exception occurred while notifying an event.");
381 LOGW_EX(env);
382 env->ExceptionClear();
383 }
384}
385
Robert Shih620f4a62021-02-15 03:28:42 -0800386jint MediaErrorToJavaError(status_t err) {
387#define STATUS_CASE(status) \
388 case status: \
389 return J##status
390
391 switch (err) {
392 STATUS_CASE(ERROR_DRM_UNKNOWN);
393 STATUS_CASE(ERROR_DRM_NO_LICENSE);
394 STATUS_CASE(ERROR_DRM_LICENSE_EXPIRED);
395 STATUS_CASE(ERROR_DRM_RESOURCE_BUSY);
396 STATUS_CASE(ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION);
397 STATUS_CASE(ERROR_DRM_SESSION_NOT_OPENED);
398 STATUS_CASE(ERROR_DRM_CANNOT_HANDLE);
399 STATUS_CASE(ERROR_DRM_INSUFFICIENT_SECURITY);
400 STATUS_CASE(ERROR_DRM_FRAME_TOO_LARGE);
401 STATUS_CASE(ERROR_DRM_SESSION_LOST_STATE);
402 STATUS_CASE(ERROR_DRM_CERTIFICATE_MALFORMED);
403 STATUS_CASE(ERROR_DRM_CERTIFICATE_MISSING);
404 STATUS_CASE(ERROR_DRM_CRYPTO_LIBRARY);
405 STATUS_CASE(ERROR_DRM_GENERIC_OEM);
406 STATUS_CASE(ERROR_DRM_GENERIC_PLUGIN);
407 STATUS_CASE(ERROR_DRM_INIT_DATA);
408 STATUS_CASE(ERROR_DRM_KEY_NOT_LOADED);
409 STATUS_CASE(ERROR_DRM_LICENSE_PARSE);
410 STATUS_CASE(ERROR_DRM_LICENSE_POLICY);
411 STATUS_CASE(ERROR_DRM_LICENSE_RELEASE);
412 STATUS_CASE(ERROR_DRM_LICENSE_REQUEST_REJECTED);
413 STATUS_CASE(ERROR_DRM_LICENSE_RESTORE);
414 STATUS_CASE(ERROR_DRM_LICENSE_STATE);
415 STATUS_CASE(ERROR_DRM_MEDIA_FRAMEWORK);
416 STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE);
417 STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG);
418 STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE);
Robert Shiha37ae8e2021-03-03 03:35:12 -0800419 STATUS_CASE(ERROR_DRM_PROVISIONING_REQUEST_REJECTED);
Robert Shih620f4a62021-02-15 03:28:42 -0800420 STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY);
421 STATUS_CASE(ERROR_DRM_RESOURCE_CONTENTION);
422 STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE);
423 STATUS_CASE(ERROR_DRM_STORAGE_READ);
424 STATUS_CASE(ERROR_DRM_STORAGE_WRITE);
425 STATUS_CASE(ERROR_DRM_ZERO_SUBSAMPLES);
426#undef STATUS_CASE
427 }
428 return static_cast<jint>(err);
429}
430
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530431static void throwStateException(JNIEnv *env, const char *msg, const DrmStatus &err) {
432 ALOGE("Illegal state exception: %s (%d)", msg, static_cast<status_t>(err));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700433
Robert Shih620f4a62021-02-15 03:28:42 -0800434 jint jerr = MediaErrorToJavaError(err);
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700435 jobject exception = env->NewObject(gFields.stateException.classId,
Robert Shih46849832022-12-15 10:30:51 -0800436 gFields.stateException.init, env->NewStringUTF(msg), static_cast<int>(jerr),
437 err.getCdmErr(), err.getOemErr(), err.getContext());
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700438 env->Throw(static_cast<jthrowable>(exception));
439}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700440
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530441static void throwSessionException(JNIEnv *env, const char *msg, const DrmStatus &err) {
442 ALOGE("Session exception: %s (%d)", msg, static_cast<status_t>(err));
Jeff Tinker20594d82018-12-12 08:31:22 -0800443
444 jint jErrorCode = 0;
445 switch(err) {
446 case ERROR_DRM_RESOURCE_CONTENTION:
447 jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
448 break;
449 default:
450 break;
451 }
452
453 jobject exception = env->NewObject(gFields.sessionException.classId,
Robert Shih46849832022-12-15 10:30:51 -0800454 gFields.sessionException.init,
455 env->NewStringUTF(msg),
456 jErrorCode,
457 err.getCdmErr(),
458 err.getOemErr(),
459 err.getContext());
Jeff Tinker20594d82018-12-12 08:31:22 -0800460
Jeff Tinker20594d82018-12-12 08:31:22 -0800461 env->Throw(static_cast<jthrowable>(exception));
462}
463
464static bool isSessionException(status_t err) {
465 return err == ERROR_DRM_RESOURCE_CONTENTION;
466}
467
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800468static bool throwExceptionAsNecessary(
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530469 JNIEnv *env, const sp<IDrm> &drm, const DrmStatus &err, const char *msg = NULL) {
Robert Shih60dab872021-02-13 11:24:59 -0800470 std::string msgStr;
Robert Shih13eb27b2021-02-20 00:08:16 -0800471 if (drm != NULL && err != OK) {
Robert Shih60dab872021-02-13 11:24:59 -0800472 msgStr = DrmUtils::GetExceptionMessage(err, msg, drm);
473 msg = msgStr.c_str();
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700474 }
475
Jeff Tinkereb13c762017-11-01 15:29:38 -0700476 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800477 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
478 return true;
Jeff Tinker5de2e902019-01-25 23:09:36 -0800479 } else if (err == ERROR_UNSUPPORTED) {
480 jniThrowException(env, "java/lang/UnsupportedOperationException", msg);
481 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700482 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
Robert Shih46849832022-12-15 10:30:51 -0800483 drmThrowException(env, "android/media/NotProvisionedException", err, msg);
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700484 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700485 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
Robert Shih46849832022-12-15 10:30:51 -0800486 drmThrowException(env, "android/media/ResourceBusyException", err, msg);
Jeff Tinker3ed38262013-08-02 23:24:51 -0700487 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700488 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
Robert Shih46849832022-12-15 10:30:51 -0800489 drmThrowException(env, "android/media/DeniedByServerException", err, msg);
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700490 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700491 } else if (err == DEAD_OBJECT) {
Robert Shih250f6a72021-02-26 08:20:31 -0800492 jniThrowException(env, "android/media/MediaDrmResetException", msg);
Jeff Tinker314b7f32015-06-15 17:45:43 -0700493 return true;
Jeff Tinker20594d82018-12-12 08:31:22 -0800494 } else if (isSessionException(err)) {
495 throwSessionException(env, msg, err);
496 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800497 } else if (err != OK) {
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700498 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800499 return true;
500 }
501 return false;
502}
503
504static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000505 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800506 return jdrm ? jdrm->getDrm() : NULL;
507}
508
509JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800510 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
511 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800512 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800513 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700514 if (mDrm != NULL) {
515 mDrm->setListener(this);
516 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800517}
518
519JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800520 JNIEnv *env = AndroidRuntime::getJNIEnv();
521
522 env->DeleteWeakGlobalRef(mObject);
523 mObject = NULL;
524}
525
526// static
527sp<IDrm> JDrm::MakeDrm() {
Robert Shih218b9532019-08-15 14:48:11 -0700528 return DrmUtils::MakeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800529}
530
531// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800532sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800533 sp<IDrm> drm = MakeDrm();
534
535 if (drm == NULL) {
536 return NULL;
537 }
538
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530539 DrmStatus err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800540
541 if (err != OK) {
542 return NULL;
543 }
544
545 return drm;
546}
547
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700548status_t JDrm::setListener(const sp<DrmListener>& listener) {
549 Mutex::Autolock lock(mLock);
550 mListener = listener;
551 return OK;
552}
553
Robert Shih9d4e2d42019-11-08 13:51:49 -0800554void JDrm::notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *args) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700555 sp<DrmListener> listener;
556 mLock.lock();
557 listener = mListener;
558 mLock.unlock();
559
560 if (listener != NULL) {
561 Mutex::Autolock lock(mNotifyLock);
Robert Shih9d4e2d42019-11-08 13:51:49 -0800562 listener->notify(eventType, extra, args);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700563 }
564}
565
Robert Shih3a523902019-08-15 14:48:11 -0700566void JDrm::sendEvent(
567 DrmPlugin::EventType eventType,
568 const hardware::hidl_vec<uint8_t> &sessionId,
569 const hardware::hidl_vec<uint8_t> &data) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800570 ListenerArgs args{
571 .jSessionId = hidlVectorToJByteArray(sessionId),
572 .jData = hidlVectorToJByteArray(data),
573 };
574 notify(eventType, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700575}
576
577void JDrm::sendExpirationUpdate(
578 const hardware::hidl_vec<uint8_t> &sessionId,
579 int64_t expiryTimeInMS) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800580 ListenerArgs args{
581 .jSessionId = hidlVectorToJByteArray(sessionId),
582 .jExpirationTime = expiryTimeInMS,
583 };
584 notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700585}
586
587void JDrm::sendKeysChange(
588 const hardware::hidl_vec<uint8_t> &sessionId,
589 const std::vector<DrmKeyStatus> &keyStatusList,
590 bool hasNewUsableKey) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800591 JNIEnv *env = AndroidRuntime::getJNIEnv();
592 jclass clazz = gFields.arraylistClassId;
593 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
594 clazz = gFields.keyStatus.classId;
595 for (const auto &keyStatus : keyStatusList) {
596 jbyteArray jKeyId(hidlVectorToJByteArray(keyStatus.keyId));
597 jint jStatusCode(keyStatus.type);
598 jobject jKeyStatus = env->NewObject(clazz, gFields.keyStatus.init, jKeyId, jStatusCode);
599 env->CallBooleanMethod(arrayList, gFields.arraylist.add, jKeyStatus);
600 }
601 ListenerArgs args{
602 .jSessionId = hidlVectorToJByteArray(sessionId),
603 .jKeyStatusList = arrayList,
604 .jHasNewUsableKey = hasNewUsableKey,
605 };
606 notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700607}
608
609void JDrm::sendSessionLostState(
610 const hardware::hidl_vec<uint8_t> &sessionId) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800611 ListenerArgs args{
612 .jSessionId = hidlVectorToJByteArray(sessionId),
613 };
614 notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700615}
616
Jeff Tinker600071c2014-04-11 16:11:15 -0700617void JDrm::disconnect() {
618 if (mDrm != NULL) {
619 mDrm->destroyPlugin();
620 mDrm.clear();
621 }
622}
623
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700624
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800625// static
Jeff Tinker5de2e902019-01-25 23:09:36 -0800626status_t JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
627 DrmPlugin::SecurityLevel securityLevel, bool *isSupported) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800628 sp<IDrm> drm = MakeDrm();
629
630 if (drm == NULL) {
Jeff Tinker5de2e902019-01-25 23:09:36 -0800631 return BAD_VALUE;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800632 }
633
Jeff Tinker5de2e902019-01-25 23:09:36 -0800634 return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel, isSupported);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800635}
636
637status_t JDrm::initCheck() const {
638 return mDrm == NULL ? NO_INIT : OK;
639}
640
641// JNI conversion utilities
642static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
643 Vector<uint8_t> vector;
644 size_t length = env->GetArrayLength(byteArray);
645 vector.insertAt((size_t)0, length);
646 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
647 return vector;
648}
649
650static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
651 size_t length = vector.size();
652 jbyteArray result = env->NewByteArray(length);
653 if (result != NULL) {
654 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
655 }
656 return result;
657}
658
659static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800660 String8 result;
661
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700662 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800663 if (s) {
664 result = s;
665 env->ReleaseStringUTFChars(jstr, s);
666 }
667 return result;
668}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700669
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800670/*
671 import java.util.HashMap;
672 import java.util.Set;
673 import java.Map.Entry;
674 import jav.util.Iterator;
675
676 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800677 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800678 Iterator i = s.iterator();
679 Entry e = s.next();
680*/
681
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200682static KeyedVector<String8, String8> HashMapToKeyedVector(
683 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800684 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800685 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200686 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800687
688 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
689 if (entrySet) {
690 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
691 if (iterator) {
692 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
693 while (hasNext) {
694 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
695 if (entry) {
696 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200697 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700698 jniThrowException(env, "java/lang/IllegalArgumentException",
699 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200700 env->DeleteLocalRef(entry);
701 *pIsOK = false;
702 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800703 }
704 jstring jkey = static_cast<jstring>(obj);
705
706 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200707 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700708 jniThrowException(env, "java/lang/IllegalArgumentException",
709 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200710 env->DeleteLocalRef(entry);
711 *pIsOK = false;
712 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800713 }
714 jstring jvalue = static_cast<jstring>(obj);
715
716 String8 key = JStringToString8(env, jkey);
717 String8 value = JStringToString8(env, jvalue);
718 keyedVector.add(key, value);
719
720 env->DeleteLocalRef(jkey);
721 env->DeleteLocalRef(jvalue);
722 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
723 }
724 env->DeleteLocalRef(entry);
725 }
726 env->DeleteLocalRef(iterator);
727 }
728 env->DeleteLocalRef(entrySet);
729 }
730 return keyedVector;
731}
732
733static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800734 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800735 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
736 for (size_t i = 0; i < map.size(); ++i) {
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +0000737 jstring jkey = env->NewStringUTF(map.keyAt(i).c_str());
738 jstring jvalue = env->NewStringUTF(map.valueAt(i).c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800739 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
740 env->DeleteLocalRef(jkey);
741 env->DeleteLocalRef(jvalue);
742 }
743 return hashMap;
744}
745
746static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800747 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800748 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800749 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800750 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800751 while (iter != list.end()) {
752 jbyteArray byteArray = VectorToJByteArray(env, *iter);
753 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
754 env->DeleteLocalRef(byteArray);
755 iter++;
756 }
757
758 return arrayList;
759}
760
761} // namespace android
762
763using namespace android;
764
765static sp<JDrm> setDrm(
766 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000767 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800768 if (drm != NULL) {
769 drm->incStrong(thiz);
770 }
771 if (old != NULL) {
772 old->decStrong(thiz);
773 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000774 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800775
776 return old;
777}
778
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800779static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800780 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700781 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800782 return false;
783 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800784 return true;
785}
786
787static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
788{
789 if (!CheckDrm(env, drm)) {
790 return false;
791 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800792
793 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700794 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800795 return false;
796 }
797 return true;
798}
799
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800800static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700801 sp<JDrm> drm = setDrm(env, thiz, NULL);
802 if (drm != NULL) {
803 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700804 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700805 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800806}
807
808static void android_media_MediaDrm_native_init(JNIEnv *env) {
809 jclass clazz;
810 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000811 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700812 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Robert Shih9d4e2d42019-11-08 13:51:49 -0800813 "(Ljava/lang/Object;III[B[BJLjava/util/List;Z)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700814
815 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700816 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700817 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700818 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700819 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700820 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700821 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700822 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700823 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800824 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
825 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800826
Jeff Tinker74797f82015-03-31 15:44:34 -0700827 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
828 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
829 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
830 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700831 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
832 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800833 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
834 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700835
Jeff Tinker17b89222013-05-21 12:35:06 -0700836 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
837 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
838 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
839 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
840 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
841 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
842
Jeff Tinkere4095a82014-03-04 13:17:11 -0800843 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
844 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
845 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
846 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
847
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800848 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
849 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
850 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
851 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
852 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
853 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
854 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
855 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
856 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
857 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
858 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
859 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800860 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
861 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800862 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
863 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
864
865 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
866 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700867 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800868 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700869 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800870 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700871 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800872 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700873 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800874 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700875 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800876 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
877
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800878 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_USABLE", "I");
Jeff Tinker55d26242018-10-10 16:10:43 -0700879 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800880 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_RELEASED", "I");
881 gOfflineLicenseStates.kOfflineLicenseStateReleased = env->GetStaticIntField(clazz, field);
Jeff Tinker55d26242018-10-10 16:10:43 -0700882 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
883 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
884
885 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
886
Jeff Tinker2bca5252018-02-11 18:59:14 +0000887 jmethodID getMaxSecurityLevel;
888 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
889 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
890
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700891 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700892 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
893 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700894 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800895
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700896 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
897 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
898 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
899 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
900 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
901 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800902 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
903 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
904 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
905 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700906
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800907 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700908 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
909 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800910
Jeff Tinkere4095a82014-03-04 13:17:11 -0800911 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
912 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
913 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700914 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800915
Adam Stone94395c92018-01-30 12:07:00 -0800916 // Metrics-related fields and classes.
917 FIND_CLASS(clazz, "android/os/PersistableBundle");
918 jfieldID bundleCreatorId;
919 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
920 "Landroid/os/Parcelable$Creator;");
921 jobject bundleCreator;
922 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
923 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
924 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
925 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
926 "(Landroid/os/Parcel;)Ljava/lang/Object;");
927 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
928
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800929 FIND_CLASS(clazz, "java/util/ArrayList");
930 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
931 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
932
933 FIND_CLASS(clazz, "java/util/HashMap");
934 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
935 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
936 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
937 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
938 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
939
940 FIND_CLASS(clazz, "java/util/Set");
941 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
942
943 FIND_CLASS(clazz, "java/util/Iterator");
944 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
945 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
946
947 FIND_CLASS(clazz, "java/util/Map$Entry");
948 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
949 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800950
951 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700952 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800953
954 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700955 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800956
957 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700958 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700959
960 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
Robert Shih46849832022-12-15 10:30:51 -0800961 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(Ljava/lang/String;IIII)V");
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700962 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800963
964 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
Robert Shih46849832022-12-15 10:30:51 -0800965 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(Ljava/lang/String;IIII)V");
Jeff Tinker20594d82018-12-12 08:31:22 -0800966 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
967 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
968
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800969 GET_STATIC_FIELD_ID(field, clazz, "ERROR_UNKNOWN", "I");
970 gSessionExceptionErrorCodes.kErrorUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800971 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
972 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Robert Shih9d4e2d42019-11-08 13:51:49 -0800973
974 FIND_CLASS(clazz, "android/media/MediaDrm$KeyStatus");
975 gFields.keyStatus.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
976 GET_METHOD_ID(gFields.keyStatus.init, clazz, "<init>", "([BI)V");
Robert Shih696989f2021-02-12 23:25:16 -0800977
978 FIND_CLASS(clazz, "android/media/MediaDrm$LogMessage");
979 gFields.logMessage.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
980 GET_METHOD_ID(gFields.logMessage.init, clazz, "<init>", "(JILjava/lang/String;)V");
Kyle Zhangb61d8022023-10-04 00:14:59 +0000981
982 resolveDrmExceptionCtor(env, "android/media/NotProvisionedException");
983 resolveDrmExceptionCtor(env, "android/media/ResourceBusyException");
984 resolveDrmExceptionCtor(env, "android/media/DeniedByServerException");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800985}
986
987static void android_media_MediaDrm_native_setup(
988 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800989 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800990
991 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700992 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800993 return;
994 }
995
996 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
997
998 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700999 jniThrowException(env, "java/lang/IllegalArgumentException",
1000 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001001 return;
1002 }
1003
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001004 String8 packageName;
1005 if (jappPackageName == NULL) {
1006 jniThrowException(env, "java/lang/IllegalArgumentException",
1007 "application package name cannot be null");
1008 return;
1009 }
1010
1011 packageName = JStringToString8(env, jappPackageName);
1012 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001013
1014 status_t err = drm->initCheck();
1015
1016 if (err != OK) {
Robert Shih250f6a72021-02-26 08:20:31 -08001017 auto logs(DrmUtils::gLogBuf.getLogs());
1018 auto msg(DrmUtils::GetExceptionMessage(err, "Failed to instantiate drm object", logs));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001019 jniThrowException(
1020 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -07001021 "android/media/UnsupportedSchemeException",
Robert Shih250f6a72021-02-26 08:20:31 -08001022 msg.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001023 return;
1024 }
1025
Jeff Tinker54cfbd62013-04-02 13:14:59 -07001026 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
1027 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001028 setDrm(env, thiz, drm);
1029}
1030
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001031DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
1032 DrmPlugin::SecurityLevel level;
1033
1034 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
1035 level = DrmPlugin::kSecurityLevelMax;
1036 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
1037 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
1038 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
1039 level = DrmPlugin::kSecurityLevelSwSecureDecode;
1040 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
1041 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
1042 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
1043 level = DrmPlugin::kSecurityLevelHwSecureDecode;
1044 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
1045 level = DrmPlugin::kSecurityLevelHwSecureAll;
1046 } else {
1047 level = DrmPlugin::kSecurityLevelUnknown;
1048 }
1049 return level;
1050}
1051
Marvin Ramin00c82542024-03-18 16:03:03 +01001052std::vector<int> getVirtualDeviceIds() {
1053 if (!virtualdevice_flags::device_aware_drm()) {
1054 ALOGW("Device-aware DRM flag disabled.");
1055 return std::vector<int>();
1056 }
1057
1058 sp<IBinder> binder =
1059 defaultServiceManager()->checkService(String16("virtualdevice_native"));
1060 if (binder != nullptr) {
1061 auto vdm = interface_cast<IVirtualDeviceManagerNative>(binder);
1062 std::vector<int> deviceIds;
1063 const uid_t uid = IPCThreadState::self()->getCallingUid();
1064 vdm->getDeviceIdsForUid(uid, &deviceIds);
1065 return deviceIds;
1066 } else {
1067 ALOGW("Cannot get virtualdevice_native service");
1068 return std::vector<int>();
1069 }
1070}
1071
Robert Shihd2e8b432019-11-21 20:27:56 -08001072static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
Kyle Zhang621af3e2022-03-17 23:39:05 +00001073 sp<IDrm> drm = android::DrmUtils::MakeDrm();
Kyle Zhang452bc552023-01-23 22:37:45 +00001074 if (drm == NULL) return env->NewByteArray(0);
1075
Robert Shihd2e8b432019-11-21 20:27:56 -08001076 std::vector<uint8_t> bv;
Kyle Zhang621af3e2022-03-17 23:39:05 +00001077 drm->getSupportedSchemes(bv);
Robert Shihd2e8b432019-11-21 20:27:56 -08001078 jbyteArray jUuidBytes = env->NewByteArray(bv.size());
1079 env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
1080 return jUuidBytes;
1081}
1082
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001083static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001084 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
1085 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001086
1087 if (uuidObj == NULL) {
1088 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1089 return false;
1090 }
1091
1092 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
1093
1094 if (uuid.size() != 16) {
1095 jniThrowException(
1096 env,
1097 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -07001098 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001099 return false;
1100 }
1101
Jeff Tinker7cda4912013-08-21 11:52:34 -07001102 String8 mimeType;
1103 if (jmimeType != NULL) {
1104 mimeType = JStringToString8(env, jmimeType);
1105 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001106 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -07001107
Marvin Ramin00c82542024-03-18 16:03:03 +01001108 if (getVirtualDeviceIds().size() > 0) {
1109 // Cap security level at max SECURITY_LEVEL_SW_SECURE_CRYPTO because at
1110 // higher security levels decode output cannot be captured and
1111 // streamed to virtual devices rendered on virtual displays.
1112 if (securityLevel > DrmPlugin::kSecurityLevelSwSecureCrypto) {
1113 return false;
1114 }
1115 }
1116
Jeff Tinker5de2e902019-01-25 23:09:36 -08001117 bool isSupported;
1118 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
1119 securityLevel, &isSupported);
1120
Robert Shih60dab872021-02-13 11:24:59 -08001121 if (throwExceptionAsNecessary(env, NULL, err, "Failed to query crypto scheme support")) {
Jeff Tinker5de2e902019-01-25 23:09:36 -08001122 return false;
1123 }
1124 return isSupported;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001125}
1126
1127static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +00001128 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001129 sp<IDrm> drm = GetDrm(env, thiz);
1130
Jeff Tinker55d26242018-10-10 16:10:43 -07001131 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001132 return NULL;
1133 }
1134
1135 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001136 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1137 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +00001138 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1139 return NULL;
1140 }
1141
Marvin Ramin00c82542024-03-18 16:03:03 +01001142 if (getVirtualDeviceIds().size() > 0) {
1143 // Cap security level at max SECURITY_LEVEL_SW_SECURE_CRYPTO because at
1144 // higher security levels decode output cannot be captured and
1145 // streamed to virtual devices rendered on virtual displays.
1146 if (level == DrmPlugin::kSecurityLevelMax ||
1147 level > DrmPlugin::kSecurityLevelSwSecureCrypto) {
1148 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
1149 }
1150 }
1151
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301152 DrmStatus err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001153
Robert Shih60dab872021-02-13 11:24:59 -08001154 if (throwExceptionAsNecessary(env, drm, err, "Failed to open session")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001155 return NULL;
1156 }
1157
1158 return VectorToJByteArray(env, sessionId);
1159}
1160
1161static void android_media_MediaDrm_closeSession(
1162 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1163 sp<IDrm> drm = GetDrm(env, thiz);
1164
1165 if (!CheckSession(env, drm, jsessionId)) {
1166 return;
1167 }
1168
1169 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1170
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301171 DrmStatus err = drm->closeSession(sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001172
Robert Shih60dab872021-02-13 11:24:59 -08001173 throwExceptionAsNecessary(env, drm, err, "Failed to close session");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001174}
1175
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001176static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001177 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001178 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001179 sp<IDrm> drm = GetDrm(env, thiz);
1180
1181 if (!CheckSession(env, drm, jsessionId)) {
1182 return NULL;
1183 }
1184
1185 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1186
1187 Vector<uint8_t> initData;
1188 if (jinitData != NULL) {
1189 initData = JByteArrayToVector(env, jinitData);
1190 }
1191
1192 String8 mimeType;
1193 if (jmimeType != NULL) {
1194 mimeType = JStringToString8(env, jmimeType);
1195 }
1196
Jeff Tinker17b89222013-05-21 12:35:06 -07001197 DrmPlugin::KeyType keyType;
1198 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1199 keyType = DrmPlugin::kKeyType_Streaming;
1200 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1201 keyType = DrmPlugin::kKeyType_Offline;
1202 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1203 keyType = DrmPlugin::kKeyType_Release;
1204 } else {
1205 jniThrowException(env, "java/lang/IllegalArgumentException",
1206 "invalid keyType");
1207 return NULL;
1208 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001209
1210 KeyedVector<String8, String8> optParams;
1211 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001212 bool isOK;
1213 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1214 if (!isOK) {
1215 return NULL;
1216 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001217 }
1218
1219 Vector<uint8_t> request;
1220 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001221 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001222
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301223 DrmStatus err = drm->getKeyRequest(sessionId, initData, mimeType, keyType, optParams, request,
1224 defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001225
Robert Shih60dab872021-02-13 11:24:59 -08001226 if (throwExceptionAsNecessary(env, drm, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001227 return NULL;
1228 }
1229
1230 // Fill out return obj
1231 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001232 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001233
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001234 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001235
1236 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001237 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001238 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001239 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001240
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001241 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.c_str());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001242 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001243
1244 switch (keyRequestType) {
1245 case DrmPlugin::kKeyRequestType_Initial:
1246 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1247 gKeyRequestTypes.kKeyRequestTypeInitial);
1248 break;
1249 case DrmPlugin::kKeyRequestType_Renewal:
1250 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1251 gKeyRequestTypes.kKeyRequestTypeRenewal);
1252 break;
1253 case DrmPlugin::kKeyRequestType_Release:
1254 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1255 gKeyRequestTypes.kKeyRequestTypeRelease);
1256 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001257 case DrmPlugin::kKeyRequestType_None:
1258 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1259 gKeyRequestTypes.kKeyRequestTypeNone);
1260 break;
1261 case DrmPlugin::kKeyRequestType_Update:
1262 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1263 gKeyRequestTypes.kKeyRequestTypeUpdate);
1264 break;
1265
Jeff Tinker74797f82015-03-31 15:44:34 -07001266 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001267 throwStateException(env, "DRM plugin failure: unknown key request type",
1268 ERROR_DRM_UNKNOWN);
1269 break;
1270 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001271 }
1272
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001273 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001274}
1275
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001276static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001277 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1278 sp<IDrm> drm = GetDrm(env, thiz);
1279
1280 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001281 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001282 }
1283
1284 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1285
1286 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001287 jniThrowException(env, "java/lang/IllegalArgumentException",
1288 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001289 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001290 }
1291 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001292 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001293
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301294 DrmStatus err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001295
Robert Shih60dab872021-02-13 11:24:59 -08001296 if (throwExceptionAsNecessary(env, drm, err, "Failed to handle key response")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001297 return NULL;
1298 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001299 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001300}
1301
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001302static void android_media_MediaDrm_removeKeys(
1303 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1304 sp<IDrm> drm = GetDrm(env, thiz);
1305
Jeff Tinker55d26242018-10-10 16:10:43 -07001306 if (!CheckDrm(env, drm)) {
1307 return;
1308 }
1309
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001310 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001311 jniThrowException(env, "java/lang/IllegalArgumentException",
1312 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001313 return;
1314 }
1315
1316 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1317
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301318 DrmStatus err = drm->removeKeys(keySetId);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001319
Robert Shih60dab872021-02-13 11:24:59 -08001320 throwExceptionAsNecessary(env, drm, err, "Failed to remove keys");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001321}
1322
1323static void android_media_MediaDrm_restoreKeys(
1324 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1325 jbyteArray jkeysetId) {
1326
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001327 sp<IDrm> drm = GetDrm(env, thiz);
1328
1329 if (!CheckSession(env, drm, jsessionId)) {
1330 return;
1331 }
1332
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001333 if (jkeysetId == NULL) {
1334 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1335 return;
1336 }
1337
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001338 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001339 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001340
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301341 DrmStatus err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001342
Robert Shih60dab872021-02-13 11:24:59 -08001343 throwExceptionAsNecessary(env, drm, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001344}
1345
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001346static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001347 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1348 sp<IDrm> drm = GetDrm(env, thiz);
1349
1350 if (!CheckSession(env, drm, jsessionId)) {
1351 return NULL;
1352 }
1353 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1354
1355 KeyedVector<String8, String8> infoMap;
1356
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301357 DrmStatus err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001358
Robert Shih60dab872021-02-13 11:24:59 -08001359 if (throwExceptionAsNecessary(env, drm, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001360 return NULL;
1361 }
1362
1363 return KeyedVectorToHashMap(env, infoMap);
1364}
1365
Jeff Tinkere4095a82014-03-04 13:17:11 -08001366static jobject android_media_MediaDrm_getProvisionRequestNative(
1367 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001368 sp<IDrm> drm = GetDrm(env, thiz);
1369
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001370 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001371 return NULL;
1372 }
1373
1374 Vector<uint8_t> request;
1375 String8 defaultUrl;
1376
Jeff Tinkere4095a82014-03-04 13:17:11 -08001377 String8 certType;
1378 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1379 certType = "X.509";
1380 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1381 certType = "none";
1382 } else {
1383 certType = "invalid";
1384 }
1385
1386 String8 certAuthority = JStringToString8(env, jcertAuthority);
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301387 DrmStatus err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001388
Robert Shih60dab872021-02-13 11:24:59 -08001389 if (throwExceptionAsNecessary(env, drm, err, "Failed to get provision request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001390 return NULL;
1391 }
1392
1393 // Fill out return obj
1394 jclass clazz;
1395 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1396
1397 jobject provisionObj = NULL;
1398
1399 if (clazz) {
1400 provisionObj = env->AllocObject(clazz);
1401 jbyteArray jrequest = VectorToJByteArray(env, request);
1402 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1403
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001404 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001405 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1406 }
1407
1408 return provisionObj;
1409}
1410
Jeff Tinkere4095a82014-03-04 13:17:11 -08001411static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001412 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1413 sp<IDrm> drm = GetDrm(env, thiz);
1414
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001415 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001416 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001417 }
1418
1419 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001420 jniThrowException(env, "java/lang/IllegalArgumentException",
1421 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001422 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001423 }
1424
1425 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001426 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001427
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301428 DrmStatus err = drm->provideProvisionResponse(response, certificate, wrappedKey);
Jeff Tinkere4095a82014-03-04 13:17:11 -08001429
1430 // Fill out return obj
1431 jclass clazz = gFields.certificateClassId;
1432
1433 jobject certificateObj = NULL;
1434
1435 if (clazz && certificate.size() && wrappedKey.size()) {
1436 certificateObj = env->AllocObject(clazz);
1437 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1438 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1439
1440 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1441 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1442 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001443
Robert Shih60dab872021-02-13 11:24:59 -08001444 throwExceptionAsNecessary(env, drm, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001445 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001446}
1447
1448static jobject android_media_MediaDrm_getSecureStops(
1449 JNIEnv *env, jobject thiz) {
1450 sp<IDrm> drm = GetDrm(env, thiz);
1451
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001452 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001453 return NULL;
1454 }
1455
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001456 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001457
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301458 DrmStatus err = drm->getSecureStops(secureStops);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001459
Robert Shih60dab872021-02-13 11:24:59 -08001460 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stops")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001461 return NULL;
1462 }
1463
1464 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1465}
1466
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001467static jobject android_media_MediaDrm_getSecureStopIds(
1468 JNIEnv *env, jobject thiz) {
1469 sp<IDrm> drm = GetDrm(env, thiz);
1470
Jeff Tinker55d26242018-10-10 16:10:43 -07001471 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001472 return NULL;
1473 }
1474
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001475 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001476
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301477 DrmStatus err = drm->getSecureStopIds(secureStopIds);
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001478
Robert Shih60dab872021-02-13 11:24:59 -08001479 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop Ids")) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001480 return NULL;
1481 }
1482
1483 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1484}
1485
Jeff Tinker1b51c722014-10-31 00:54:26 -07001486static jbyteArray android_media_MediaDrm_getSecureStop(
1487 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1488 sp<IDrm> drm = GetDrm(env, thiz);
1489
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001490 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001491 return NULL;
1492 }
1493
1494 Vector<uint8_t> secureStop;
1495
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301496 DrmStatus err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
Jeff Tinker1b51c722014-10-31 00:54:26 -07001497
Robert Shih60dab872021-02-13 11:24:59 -08001498 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop")) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001499 return NULL;
1500 }
1501
1502 return VectorToJByteArray(env, secureStop);
1503}
1504
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001505static void android_media_MediaDrm_releaseSecureStops(
1506 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1507 sp<IDrm> drm = GetDrm(env, thiz);
1508
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001509 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001510 return;
1511 }
1512
1513 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1514
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301515 DrmStatus err = drm->releaseSecureStops(ssRelease);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001516
Robert Shih60dab872021-02-13 11:24:59 -08001517 throwExceptionAsNecessary(env, drm, err, "Failed to release secure stops");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001518}
1519
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001520static void android_media_MediaDrm_removeSecureStop(
1521 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1522 sp<IDrm> drm = GetDrm(env, thiz);
1523
Jeff Tinker55d26242018-10-10 16:10:43 -07001524 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001525 return;
1526 }
1527
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301528 DrmStatus err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001529
Robert Shih60dab872021-02-13 11:24:59 -08001530 throwExceptionAsNecessary(env, drm, err, "Failed to remove secure stop");
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001531}
1532
1533static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001534 JNIEnv *env, jobject thiz) {
1535 sp<IDrm> drm = GetDrm(env, thiz);
1536
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001537 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001538 return;
1539 }
1540
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301541 DrmStatus err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001542
Robert Shih60dab872021-02-13 11:24:59 -08001543 throwExceptionAsNecessary(env, drm, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001544}
1545
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001546
1547static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1548 switch(level) {
1549 case DrmPlugin::kHdcpLevelUnknown:
1550 return gHdcpLevels.kHdcpLevelUnknown;
1551 case DrmPlugin::kHdcpNone:
1552 return gHdcpLevels.kHdcpNone;
1553 case DrmPlugin::kHdcpV1:
1554 return gHdcpLevels.kHdcpV1;
1555 case DrmPlugin::kHdcpV2:
1556 return gHdcpLevels.kHdcpV2;
1557 case DrmPlugin::kHdcpV2_1:
1558 return gHdcpLevels.kHdcpV2_1;
1559 case DrmPlugin::kHdcpV2_2:
1560 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001561 case DrmPlugin::kHdcpV2_3:
1562 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001563 case DrmPlugin::kHdcpNoOutput:
1564 return gHdcpLevels.kHdcpNoOutput;
1565 }
1566 return gHdcpLevels.kHdcpNone;
1567}
1568
1569static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1570 jobject thiz) {
1571 sp<IDrm> drm = GetDrm(env, thiz);
1572
1573 if (!CheckDrm(env, drm)) {
1574 return gHdcpLevels.kHdcpNone;
1575 }
1576
1577 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1578 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1579
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301580 DrmStatus err = drm->getHdcpLevels(&connected, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001581
Robert Shih60dab872021-02-13 11:24:59 -08001582 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001583 return gHdcpLevels.kHdcpLevelUnknown;
1584 }
1585 return HdcpLevelTojint(connected);
1586}
1587
1588static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1589 jobject thiz) {
1590 sp<IDrm> drm = GetDrm(env, thiz);
1591
1592 if (!CheckDrm(env, drm)) {
1593 return gHdcpLevels.kHdcpLevelUnknown;
1594 }
1595
1596 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1597 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1598
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301599 DrmStatus err = drm->getHdcpLevels(&connected, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001600
Robert Shih60dab872021-02-13 11:24:59 -08001601 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001602 return gHdcpLevels.kHdcpLevelUnknown;
1603 }
1604 return HdcpLevelTojint(max);
1605}
1606
1607static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1608 jobject thiz) {
1609 sp<IDrm> drm = GetDrm(env, thiz);
1610
1611 if (!CheckDrm(env, drm)) {
1612 return 0;
1613 }
1614
1615 uint32_t open = 0, max = 0;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301616 DrmStatus err = drm->getNumberOfSessions(&open, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001617
Robert Shih60dab872021-02-13 11:24:59 -08001618 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001619 return 0;
1620 }
1621 return open;
1622}
1623
1624static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1625 jobject thiz) {
1626 sp<IDrm> drm = GetDrm(env, thiz);
1627
1628 if (!CheckDrm(env, drm)) {
1629 return 0;
1630 }
1631
1632 uint32_t open = 0, max = 0;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301633 DrmStatus err = drm->getNumberOfSessions(&open, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001634
Robert Shih60dab872021-02-13 11:24:59 -08001635 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001636 return 0;
1637 }
1638 return max;
1639}
1640
1641static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1642 jobject thiz, jbyteArray jsessionId) {
1643 sp<IDrm> drm = GetDrm(env, thiz);
1644
1645 if (!CheckSession(env, drm, jsessionId)) {
1646 return gSecurityLevels.kSecurityLevelUnknown;
1647 }
1648
1649 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1650
1651 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1652
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301653 DrmStatus err = drm->getSecurityLevel(sessionId, &level);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001654
Robert Shih60dab872021-02-13 11:24:59 -08001655 if (throwExceptionAsNecessary(env, drm, err, "Failed to get security level")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001656 return gSecurityLevels.kSecurityLevelUnknown;
1657 }
1658
1659 switch(level) {
1660 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1661 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1662 case DrmPlugin::kSecurityLevelSwSecureDecode:
1663 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1664 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1665 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1666 case DrmPlugin::kSecurityLevelHwSecureDecode:
1667 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1668 case DrmPlugin::kSecurityLevelHwSecureAll:
1669 return gSecurityLevels.kSecurityLevelHwSecureAll;
1670 default:
1671 return gSecurityLevels.kSecurityLevelUnknown;
1672 }
1673}
1674
Jeff Tinker55d26242018-10-10 16:10:43 -07001675static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1676 JNIEnv *env, jobject thiz) {
1677 sp<IDrm> drm = GetDrm(env, thiz);
1678
1679 if (!CheckDrm(env, drm)) {
1680 return NULL;
1681 }
1682
1683 List<Vector<uint8_t> > keySetIds;
1684
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301685 DrmStatus err = drm->getOfflineLicenseKeySetIds(keySetIds);
Jeff Tinker55d26242018-10-10 16:10:43 -07001686
Robert Shih60dab872021-02-13 11:24:59 -08001687 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline key set Ids")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001688 return NULL;
1689 }
1690
1691 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1692}
1693
1694static void android_media_MediaDrm_removeOfflineLicense(
1695 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1696 sp<IDrm> drm = GetDrm(env, thiz);
1697
1698 if (!CheckDrm(env, drm)) {
1699 return;
1700 }
1701
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301702 DrmStatus err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
Jeff Tinker55d26242018-10-10 16:10:43 -07001703
Robert Shih60dab872021-02-13 11:24:59 -08001704 throwExceptionAsNecessary(env, drm, err, "Failed to remove offline license");
Jeff Tinker55d26242018-10-10 16:10:43 -07001705}
1706
1707static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1708 jobject thiz, jbyteArray jkeySetId) {
1709 sp<IDrm> drm = GetDrm(env, thiz);
1710
1711 if (!CheckDrm(env, drm)) {
1712 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1713 }
1714
1715 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1716
1717 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1718
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301719 DrmStatus err = drm->getOfflineLicenseState(keySetId, &state);
Jeff Tinker55d26242018-10-10 16:10:43 -07001720
Robert Shih60dab872021-02-13 11:24:59 -08001721 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline license state")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001722 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1723 }
1724
1725 switch(state) {
1726 case DrmPlugin::kOfflineLicenseStateUsable:
1727 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -08001728 case DrmPlugin::kOfflineLicenseStateReleased:
1729 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -07001730 default:
1731 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1732 }
1733}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001734
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001735static jstring android_media_MediaDrm_getPropertyString(
1736 JNIEnv *env, jobject thiz, jstring jname) {
1737 sp<IDrm> drm = GetDrm(env, thiz);
1738
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001739 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001740 return NULL;
1741 }
1742
1743 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001744 jniThrowException(env, "java/lang/IllegalArgumentException",
1745 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001746 return NULL;
1747 }
1748
1749 String8 name = JStringToString8(env, jname);
1750 String8 value;
1751
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301752 DrmStatus err = drm->getPropertyString(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001753
Robert Shih60dab872021-02-13 11:24:59 -08001754 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001755 return NULL;
1756 }
1757
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001758 return env->NewStringUTF(value.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001759}
1760
1761static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1762 JNIEnv *env, jobject thiz, jstring jname) {
1763 sp<IDrm> drm = GetDrm(env, thiz);
1764
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001765 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001766 return NULL;
1767 }
1768
1769 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001770 jniThrowException(env, "java/lang/IllegalArgumentException",
1771 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001772 return NULL;
1773 }
1774
1775 String8 name = JStringToString8(env, jname);
1776 Vector<uint8_t> value;
1777
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301778 DrmStatus err = drm->getPropertyByteArray(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001779
Robert Shih60dab872021-02-13 11:24:59 -08001780 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001781 return NULL;
1782 }
1783
1784 return VectorToJByteArray(env, value);
1785}
1786
1787static void android_media_MediaDrm_setPropertyString(
1788 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1789 sp<IDrm> drm = GetDrm(env, thiz);
1790
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001791 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001792 return;
1793 }
1794
Jeff Tinkereada5372013-05-21 12:48:14 -07001795 if (jname == NULL) {
1796 jniThrowException(env, "java/lang/IllegalArgumentException",
1797 "property name String is null");
1798 return;
1799 }
1800
1801 if (jvalue == NULL) {
1802 jniThrowException(env, "java/lang/IllegalArgumentException",
1803 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001804 return;
1805 }
1806
1807 String8 name = JStringToString8(env, jname);
1808 String8 value = JStringToString8(env, jvalue);
1809
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301810 DrmStatus err = drm->setPropertyString(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001811
Robert Shih60dab872021-02-13 11:24:59 -08001812 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001813}
1814
1815static void android_media_MediaDrm_setPropertyByteArray(
1816 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1817 sp<IDrm> drm = GetDrm(env, thiz);
1818
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001819 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001820 return;
1821 }
1822
Jeff Tinkereada5372013-05-21 12:48:14 -07001823 if (jname == NULL) {
1824 jniThrowException(env, "java/lang/IllegalArgumentException",
1825 "property name String is null");
1826 return;
1827 }
1828
1829 if (jvalue == NULL) {
1830 jniThrowException(env, "java/lang/IllegalArgumentException",
1831 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001832 return;
1833 }
1834
1835 String8 name = JStringToString8(env, jname);
1836 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1837
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301838 DrmStatus err = drm->setPropertyByteArray(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001839
Robert Shih60dab872021-02-13 11:24:59 -08001840 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001841}
1842
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001843static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001844 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001845 jstring jalgorithm) {
1846
1847 sp<IDrm> drm = GetDrm(env, jdrm);
1848
1849 if (!CheckSession(env, drm, jsessionId)) {
1850 return;
1851 }
1852
1853 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001854 jniThrowException(env, "java/lang/IllegalArgumentException",
1855 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001856 return;
1857 }
1858
1859 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1860 String8 algorithm = JStringToString8(env, jalgorithm);
1861
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301862 DrmStatus err = drm->setCipherAlgorithm(sessionId, algorithm);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001863
Robert Shih60dab872021-02-13 11:24:59 -08001864 throwExceptionAsNecessary(env, drm, err, "Failed to set cipher algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001865}
1866
1867static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001868 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001869 jstring jalgorithm) {
1870
1871 sp<IDrm> drm = GetDrm(env, jdrm);
1872
1873 if (!CheckSession(env, drm, jsessionId)) {
1874 return;
1875 }
1876
1877 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001878 jniThrowException(env, "java/lang/IllegalArgumentException",
1879 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001880 return;
1881 }
1882
1883 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1884 String8 algorithm = JStringToString8(env, jalgorithm);
1885
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301886 DrmStatus err = drm->setMacAlgorithm(sessionId, algorithm);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001887
Robert Shih60dab872021-02-13 11:24:59 -08001888 throwExceptionAsNecessary(env, drm, err, "Failed to set mac algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001889}
1890
1891
1892static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001893 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001894 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1895
1896 sp<IDrm> drm = GetDrm(env, jdrm);
1897
1898 if (!CheckSession(env, drm, jsessionId)) {
1899 return NULL;
1900 }
1901
1902 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001903 jniThrowException(env, "java/lang/IllegalArgumentException",
1904 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001905 return NULL;
1906 }
1907
1908 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1909 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1910 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1911 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1912 Vector<uint8_t> output;
1913
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301914 DrmStatus err = drm->encrypt(sessionId, keyId, input, iv, output);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001915
Robert Shih60dab872021-02-13 11:24:59 -08001916 if (throwExceptionAsNecessary(env, drm, err, "Failed to encrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001917 return NULL;
1918 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001919
1920 return VectorToJByteArray(env, output);
1921}
1922
1923static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001924 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001925 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1926
1927 sp<IDrm> drm = GetDrm(env, jdrm);
1928
1929 if (!CheckSession(env, drm, jsessionId)) {
1930 return NULL;
1931 }
1932
1933 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001934 jniThrowException(env, "java/lang/IllegalArgumentException",
1935 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001936 return NULL;
1937 }
1938
1939 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1940 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1941 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1942 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1943 Vector<uint8_t> output;
1944
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301945 DrmStatus err = drm->decrypt(sessionId, keyId, input, iv, output);
Robert Shih60dab872021-02-13 11:24:59 -08001946 if (throwExceptionAsNecessary(env, drm, err, "Failed to decrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001947 return NULL;
1948 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001949
1950 return VectorToJByteArray(env, output);
1951}
1952
1953static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001954 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001955 jbyteArray jkeyId, jbyteArray jmessage) {
1956
1957 sp<IDrm> drm = GetDrm(env, jdrm);
1958
1959 if (!CheckSession(env, drm, jsessionId)) {
1960 return NULL;
1961 }
1962
1963 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001964 jniThrowException(env, "java/lang/IllegalArgumentException",
1965 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001966 return NULL;
1967 }
1968
1969 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1970 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1971 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1972 Vector<uint8_t> signature;
1973
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301974 DrmStatus err = drm->sign(sessionId, keyId, message, signature);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001975
Robert Shih60dab872021-02-13 11:24:59 -08001976 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001977 return NULL;
1978 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001979
1980 return VectorToJByteArray(env, signature);
1981}
1982
1983static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001984 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001985 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1986
1987 sp<IDrm> drm = GetDrm(env, jdrm);
1988
1989 if (!CheckSession(env, drm, jsessionId)) {
1990 return false;
1991 }
1992
1993 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001994 jniThrowException(env, "java/lang/IllegalArgumentException",
1995 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001996 return false;
1997 }
1998
1999 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2000 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
2001 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
2002 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
2003 bool match;
2004
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302005 DrmStatus err = drm->verify(sessionId, keyId, message, signature, match);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002006
Robert Shih60dab872021-02-13 11:24:59 -08002007 throwExceptionAsNecessary(env, drm, err, "Failed to verify");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002008 return match;
2009}
2010
Adam Stonec06e10e2017-12-19 12:54:33 -08002011static jobject
2012android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
2013{
2014 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07002015
2016 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08002017 return NULL;
2018 }
2019
2020 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08002021 PersistableBundle metrics;
Robert Shihba6777e2019-11-12 13:04:59 -08002022 sp<IDrmMetricsConsumer> consumer(new DrmMetricsConsumer(&metrics));
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302023 DrmStatus err = drm->getMetrics(consumer);
Adam Stonec06e10e2017-12-19 12:54:33 -08002024 if (err != OK) {
2025 ALOGE("getMetrics failed: %d", (int)err);
2026 return (jobject) NULL;
2027 }
2028
Robert Shih4354a962019-11-10 12:09:08 -08002029 return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08002030}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002031
Jeff Tinkere4095a82014-03-04 13:17:11 -08002032static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08002033 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08002034 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
2035
2036 sp<IDrm> drm = GetDrm(env, jdrm);
2037
2038 if (!CheckSession(env, drm, jsessionId)) {
2039 return NULL;
2040 }
2041
2042 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
2043 jniThrowException(env, "java/lang/IllegalArgumentException",
2044 "required argument is null");
2045 return NULL;
2046 }
2047
2048 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2049 String8 algorithm = JStringToString8(env, jalgorithm);
2050 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
2051 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
2052 Vector<uint8_t> signature;
2053
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302054 DrmStatus err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
Jeff Tinkere4095a82014-03-04 13:17:11 -08002055
Robert Shih60dab872021-02-13 11:24:59 -08002056 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08002057 return NULL;
2058 }
2059
2060 return VectorToJByteArray(env, signature);
2061}
2062
Robert Shih205f7a92021-01-19 21:12:10 -08002063static jboolean android_media_MediaDrm_requiresSecureDecoder(
2064 JNIEnv *env, jobject thiz, jstring jmimeType,
2065 jint jSecurityLevel) {
2066 sp<IDrm> drm = GetDrm(env, thiz);
2067 if (!CheckDrm(env, drm)) {
2068 return JNI_FALSE;
2069 }
2070
2071 String8 mimeType;
2072 if (jmimeType != NULL) {
2073 mimeType = JStringToString8(env, jmimeType);
2074 }
2075
2076 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
2077 if (securityLevel == DrmPlugin::kSecurityLevelUnknown) {
2078 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
2079 return JNI_FALSE;
2080 }
2081
Robert Shih5bb242a2021-04-28 10:04:51 -07002082 bool required = false;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302083 DrmStatus err = OK;
Robert Shih205f7a92021-01-19 21:12:10 -08002084 if (securityLevel == DrmPlugin::kSecurityLevelMax) {
Robert Shih5bb242a2021-04-28 10:04:51 -07002085 err = drm->requiresSecureDecoder(mimeType.c_str(), &required);
2086 } else {
2087 err = drm->requiresSecureDecoder(mimeType.c_str(), securityLevel, &required);
Robert Shih205f7a92021-01-19 21:12:10 -08002088 }
Robert Shih5bb242a2021-04-28 10:04:51 -07002089 if (throwExceptionAsNecessary(env, drm, err, "Failed to query secure decoder requirement")) {
2090 return false;
2091 }
2092 return required;
Robert Shih205f7a92021-01-19 21:12:10 -08002093}
Jeff Tinkere4095a82014-03-04 13:17:11 -08002094
Robert Shih02937122021-01-20 00:05:20 -08002095static void android_media_MediaDrm_setPlaybackId(
2096 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
2097 jstring jplaybackId) {
2098 sp<IDrm> drm = GetDrm(env, thiz);
2099 if (!CheckSession(env, drm, jsessionId)) {
2100 return;
2101 }
2102
2103 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2104
2105 String8 playbackId;
2106 if (jplaybackId != NULL) {
2107 playbackId = JStringToString8(env, jplaybackId);
2108 }
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302109 DrmStatus err = drm->setPlaybackId(sessionId, playbackId.c_str());
Robert Shih60dab872021-02-13 11:24:59 -08002110 throwExceptionAsNecessary(env, drm, err, "Failed to set playbackId");
Robert Shih02937122021-01-20 00:05:20 -08002111}
2112
Robert Shih696989f2021-02-12 23:25:16 -08002113static jobject android_media_MediaDrm_getLogMessages(
2114 JNIEnv *env, jobject thiz) {
2115 sp<IDrm> drm = GetDrm(env, thiz);
2116 if (!CheckDrm(env, drm)) {
2117 return NULL;
2118 }
2119
2120 Vector<drm::V1_4::LogMessage> logs;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302121 DrmStatus err = drm->getLogMessages(logs);
Robert Shih696989f2021-02-12 23:25:16 -08002122 ALOGI("drm->getLogMessages %zu logs", logs.size());
Robert Shih60dab872021-02-13 11:24:59 -08002123 if (throwExceptionAsNecessary(env, drm, err, "Failed to get log messages")) {
Robert Shih696989f2021-02-12 23:25:16 -08002124 return NULL;
2125 }
2126 return hidlLogMessagesToJavaList(env, logs);
2127}
2128
Daniel Micay76f6a862015-09-19 17:31:01 -04002129static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002130 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
2131
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002132 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
2133
Edwin Wong4d1d84e2017-01-04 09:37:49 -08002134 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002135 (void *)android_media_MediaDrm_native_setup },
2136
Robert Shihd2e8b432019-11-21 20:27:56 -08002137 { "getSupportedCryptoSchemesNative", "()[B",
2138 (void *)android_media_MediaDrm_getSupportedCryptoSchemesNative },
2139
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08002140 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002141 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
2142
Robert Shih02937122021-01-20 00:05:20 -08002143 { "openSessionNative", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002144 (void *)android_media_MediaDrm_openSession },
2145
Robert Shih02937122021-01-20 00:05:20 -08002146 { "closeSessionNative", "([B)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002147 (void *)android_media_MediaDrm_closeSession },
2148
Robert Shih890eb572021-01-19 08:16:39 -08002149 { "getKeyRequestNative", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002150 "Landroid/media/MediaDrm$KeyRequest;",
2151 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002152
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002153 { "provideKeyResponse", "([B[B)[B",
2154 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002155
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002156 { "removeKeys", "([B)V",
2157 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002158
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002159 { "restoreKeys", "([B[B)V",
2160 (void *)android_media_MediaDrm_restoreKeys },
2161
2162 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
2163 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002164
Jeff Tinkere4095a82014-03-04 13:17:11 -08002165 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
2166 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002167
Jeff Tinkere4095a82014-03-04 13:17:11 -08002168 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
2169 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002170
2171 { "getSecureStops", "()Ljava/util/List;",
2172 (void *)android_media_MediaDrm_getSecureStops },
2173
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002174 { "getSecureStopIds", "()Ljava/util/List;",
2175 (void *)android_media_MediaDrm_getSecureStopIds },
2176
Jeff Tinker1b51c722014-10-31 00:54:26 -07002177 { "getSecureStop", "([B)[B",
2178 (void *)android_media_MediaDrm_getSecureStop },
2179
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002180 { "releaseSecureStops", "([B)V",
2181 (void *)android_media_MediaDrm_releaseSecureStops },
2182
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002183 { "removeSecureStop", "([B)V",
2184 (void *)android_media_MediaDrm_removeSecureStop },
2185
2186 { "removeAllSecureStops", "()V",
2187 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07002188
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002189 { "getConnectedHdcpLevel", "()I",
2190 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
2191
2192 { "getMaxHdcpLevel", "()I",
2193 (void *)android_media_MediaDrm_getMaxHdcpLevel },
2194
2195 { "getOpenSessionCount", "()I",
2196 (void *)android_media_MediaDrm_getOpenSessionCount },
2197
2198 { "getMaxSessionCount", "()I",
2199 (void *)android_media_MediaDrm_getMaxSessionCount },
2200
2201 { "getSecurityLevel", "([B)I",
2202 (void *)android_media_MediaDrm_getSecurityLevel },
2203
Jeff Tinker55d26242018-10-10 16:10:43 -07002204 { "removeOfflineLicense", "([B)V",
2205 (void *)android_media_MediaDrm_removeOfflineLicense },
2206
2207 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
2208 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
2209
2210 { "getOfflineLicenseState", "([B)I",
2211 (void *)android_media_MediaDrm_getOfflineLicenseState },
2212
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002213 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2214 (void *)android_media_MediaDrm_getPropertyString },
2215
2216 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2217 (void *)android_media_MediaDrm_getPropertyByteArray },
2218
2219 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2220 (void *)android_media_MediaDrm_setPropertyString },
2221
2222 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2223 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002224
2225 { "setCipherAlgorithmNative",
2226 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2227 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2228
2229 { "setMacAlgorithmNative",
2230 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2231 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2232
2233 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2234 (void *)android_media_MediaDrm_encryptNative },
2235
2236 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2237 (void *)android_media_MediaDrm_decryptNative },
2238
2239 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2240 (void *)android_media_MediaDrm_signNative },
2241
2242 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2243 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002244
2245 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2246 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002247
2248 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2249 (void *)android_media_MediaDrm_native_getMetrics },
Robert Shih205f7a92021-01-19 21:12:10 -08002250
2251 { "requiresSecureDecoder", "(Ljava/lang/String;I)Z",
2252 (void *)android_media_MediaDrm_requiresSecureDecoder },
Robert Shih02937122021-01-20 00:05:20 -08002253
2254 { "setPlaybackId", "([BLjava/lang/String;)V",
2255 (void *)android_media_MediaDrm_setPlaybackId },
Robert Shih696989f2021-02-12 23:25:16 -08002256
2257 { "getLogMessages", "()Ljava/util/List;",
2258 (void *)android_media_MediaDrm_getLogMessages },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002259};
2260
2261int register_android_media_Drm(JNIEnv *env) {
2262 return AndroidRuntime::registerNativeMethods(env,
2263 "android/media/MediaDrm", gMethods, NELEM(gMethods));
Kyle Zhangb61d8022023-10-04 00:14:59 +00002264}