blob: 1c25080939da880228453dd53b10e850115e09c2 [file] [log] [blame]
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001/*
2 * Copyright 2013, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaDrm-JNI"
19#include <utils/Log.h>
20
21#include "android_media_MediaDrm.h"
Adam Stonec06e10e2017-12-19 12:54:33 -080022#include "android_media_MediaMetricsJNI.h"
Adam Stone94395c92018-01-30 12:07:00 -080023#include "android_os_Parcel.h"
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080024#include "android_runtime/AndroidRuntime.h"
Ruben Brunk87eac992013-09-09 17:44:59 -070025#include "android_runtime/Log.h"
Jeff Tinker54cfbd62013-04-02 13:14:59 -070026#include "android_os_Parcel.h"
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080027#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070028#include <nativehelper/JNIHelp.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080029
Robert Shihd2e8b432019-11-21 20:27:56 -080030#include <android/hardware/drm/1.3/IDrmFactory.h>
Jeff Tinker54cfbd62013-04-02 13:14:59 -070031#include <binder/Parcel.h>
Adam Stone94395c92018-01-30 12:07:00 -080032#include <binder/PersistableBundle.h>
Jeff Tinkerdc614f82016-02-12 08:58:32 -080033#include <cutils/properties.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080034#include <media/stagefright/foundation/ADebug.h>
Jeff Tinkerf7568b52013-04-17 14:24:40 -070035#include <media/stagefright/MediaErrors.h>
Robert Shihba6777e2019-11-12 13:04:59 -080036#include <mediadrm/DrmMetricsConsumer.h>
Robert Shih218b9532019-08-15 14:48:11 -070037#include <mediadrm/DrmUtils.h>
Robert Shihba6777e2019-11-12 13:04:59 -080038#include <mediadrm/IDrmMetricsConsumer.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080039#include <mediadrm/IDrm.h>
Robert Shih696989f2021-02-12 23:25:16 -080040#include <utils/Vector.h>
Kyle Zhangb61d8022023-10-04 00:14:59 +000041#include <map>
42#include <string>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080043
Adam Stone94395c92018-01-30 12:07:00 -080044using ::android::os::PersistableBundle;
Robert Shihd2e8b432019-11-21 20:27:56 -080045namespace drm = ::android::hardware::drm;
Adam Stone94395c92018-01-30 12:07:00 -080046
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080047namespace android {
48
49#define FIND_CLASS(var, className) \
50 var = env->FindClass(className); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070051 LOG_FATAL_IF(! (var), "Unable to find class %s", className);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080052
53#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
54 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070055 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080056
57#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
58 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070059 LOG_FATAL_IF(! (var), "Unable to find method %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080060
Jeff Tinker54cfbd62013-04-02 13:14:59 -070061#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
62 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070063 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070064
65#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
66 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070067 LOG_FATAL_IF(! (var), "Unable to find static method %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070068
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070069#define GET_STATIC_OBJECT_FIELD(var, clazz, fieldId) \
70 var = env->GetStaticObjectField(clazz, fieldId); \
71 LOG_FATAL_IF(! (var), "Unable to find static object field %p", fieldId);
Adam Stone94395c92018-01-30 12:07:00 -080072
Jeff Tinker54cfbd62013-04-02 13:14:59 -070073
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080074struct RequestFields {
75 jfieldID data;
76 jfieldID defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -070077 jfieldID requestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080078};
79
80struct ArrayListFields {
81 jmethodID init;
82 jmethodID add;
83};
84
85struct HashmapFields {
86 jmethodID init;
87 jmethodID get;
88 jmethodID put;
89 jmethodID entrySet;
90};
91
92struct SetFields {
93 jmethodID iterator;
94};
95
96struct IteratorFields {
97 jmethodID next;
98 jmethodID hasNext;
99};
100
101struct EntryFields {
102 jmethodID getKey;
103 jmethodID getValue;
104};
105
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700106struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -0700107 jint kEventProvisionRequired;
108 jint kEventKeyRequired;
109 jint kEventKeyExpired;
110 jint kEventVendorDefined;
Ronghua Wua6d72092015-03-04 11:16:02 -0800111 jint kEventSessionReclaimed;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700112} gEventTypes;
113
Jeff Tinker74797f82015-03-31 15:44:34 -0700114struct EventWhat {
115 jint kWhatDrmEvent;
116 jint kWhatExpirationUpdate;
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700117 jint kWhatKeyStatusChange;
Jeff Tinker20594d82018-12-12 08:31:22 -0800118 jint kWhatSessionLostState;
Jeff Tinker74797f82015-03-31 15:44:34 -0700119} gEventWhat;
120
Jeff Tinker17b89222013-05-21 12:35:06 -0700121struct KeyTypes {
122 jint kKeyTypeStreaming;
123 jint kKeyTypeOffline;
124 jint kKeyTypeRelease;
125} gKeyTypes;
126
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700127struct KeyRequestTypes {
128 jint kKeyRequestTypeInitial;
129 jint kKeyRequestTypeRenewal;
130 jint kKeyRequestTypeRelease;
Rahul Frias8f761ba2018-01-22 23:43:54 -0800131 jint kKeyRequestTypeNone;
132 jint kKeyRequestTypeUpdate;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700133} gKeyRequestTypes;
134
Jeff Tinkere4095a82014-03-04 13:17:11 -0800135struct CertificateTypes {
136 jint kCertificateTypeNone;
137 jint kCertificateTypeX509;
138} gCertificateTypes;
139
140struct CertificateFields {
141 jfieldID wrappedPrivateKey;
142 jfieldID certificateData;
143};
144
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700145struct StateExceptionFields {
146 jmethodID init;
147 jclass classId;
148};
149
Jeff Tinker20594d82018-12-12 08:31:22 -0800150struct SessionExceptionFields {
151 jmethodID init;
152 jclass classId;
153 jfieldID errorCode;
154};
155
156struct SessionExceptionErrorCodes {
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800157 jint kErrorUnknown;
Jeff Tinker20594d82018-12-12 08:31:22 -0800158 jint kResourceContention;
159} gSessionExceptionErrorCodes;
160
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800161struct HDCPLevels {
162 jint kHdcpLevelUnknown;
163 jint kHdcpNone;
164 jint kHdcpV1;
165 jint kHdcpV2;
166 jint kHdcpV2_1;
167 jint kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800168 jint kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800169 jint kHdcpNoOutput;
170} gHdcpLevels;
171
172struct SecurityLevels {
173 jint kSecurityLevelUnknown;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000174 jint kSecurityLevelMax;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800175 jint kSecurityLevelSwSecureCrypto;
176 jint kSecurityLevelSwSecureDecode;
177 jint kSecurityLevelHwSecureCrypto;
178 jint kSecurityLevelHwSecureDecode;
179 jint kSecurityLevelHwSecureAll;
180} gSecurityLevels;
181
Jeff Tinker55d26242018-10-10 16:10:43 -0700182struct OfflineLicenseState {
183 jint kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800184 jint kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -0700185 jint kOfflineLicenseStateUnknown;
186} gOfflineLicenseStates;
187
Robert Shih9d4e2d42019-11-08 13:51:49 -0800188struct KeyStatusFields {
189 jmethodID init;
190 jclass classId;
191};
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800192
Robert Shih696989f2021-02-12 23:25:16 -0800193struct LogMessageFields {
194 jmethodID init;
195 jclass classId;
196};
197
Kyle Zhangb61d8022023-10-04 00:14:59 +0000198struct DrmExceptionFields {
199 jmethodID init;
200 jclass classId;
201};
202
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800203struct fields_t {
204 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700205 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700206 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800207 RequestFields provisionRequest;
208 ArrayListFields arraylist;
209 HashmapFields hashmap;
210 SetFields set;
211 IteratorFields iterator;
212 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800213 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700214 StateExceptionFields stateException;
Jeff Tinker20594d82018-12-12 08:31:22 -0800215 SessionExceptionFields sessionException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800216 jclass certificateClassId;
217 jclass hashmapClassId;
218 jclass arraylistClassId;
219 jclass stringClassId;
Adam Stone94395c92018-01-30 12:07:00 -0800220 jobject bundleCreator;
221 jmethodID createFromParcelId;
222 jclass parcelCreatorClassId;
Robert Shih9d4e2d42019-11-08 13:51:49 -0800223 KeyStatusFields keyStatus;
Robert Shih696989f2021-02-12 23:25:16 -0800224 LogMessageFields logMessage;
Kyle Zhangb61d8022023-10-04 00:14:59 +0000225 std::map<std::string, DrmExceptionFields> exceptionCtors;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800226};
227
228static fields_t gFields;
229
Adam Stone94395c92018-01-30 12:07:00 -0800230namespace {
231
Robert Shih9d4e2d42019-11-08 13:51:49 -0800232jbyteArray hidlVectorToJByteArray(const hardware::hidl_vec<uint8_t> &vector) {
233 JNIEnv *env = AndroidRuntime::getJNIEnv();
234 size_t length = vector.size();
235 jbyteArray result = env->NewByteArray(length);
236 if (result != NULL) {
237 env->SetByteArrayRegion(result, 0, length, reinterpret_cast<const jbyte *>(vector.data()));
238 }
239 return result;
240}
241
Robert Shih696989f2021-02-12 23:25:16 -0800242jobject hidlLogMessagesToJavaList(JNIEnv *env, const Vector<drm::V1_4::LogMessage> &logs) {
243 jclass clazz = gFields.arraylistClassId;
244 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
245 clazz = gFields.logMessage.classId;
246 for (auto log: logs) {
247 jobject jLog = env->NewObject(clazz, gFields.logMessage.init,
248 static_cast<jlong>(log.timeMs),
249 static_cast<jint>(log.priority),
250 env->NewStringUTF(log.message.c_str()));
251 env->CallBooleanMethod(arrayList, gFields.arraylist.add, jLog);
252 }
253 return arrayList;
254}
Robert Shih46849832022-12-15 10:30:51 -0800255
Kyle Zhangb61d8022023-10-04 00:14:59 +0000256void resolveDrmExceptionCtor(JNIEnv *env, const char *className) {
257 jclass clazz;
258 jmethodID init;
259 FIND_CLASS(clazz, className);
260 GET_METHOD_ID(init, clazz, "<init>", "(Ljava/lang/String;III)V");
261 gFields.exceptionCtors[std::string(className)] = {
262 .init = init,
263 .classId = static_cast<jclass>(env->NewGlobalRef(clazz))
264 };
265}
266
267void drmThrowException(JNIEnv* env, const char *className, const DrmStatus &err, const char *msg) {
Robert Shih46849832022-12-15 10:30:51 -0800268 using namespace android::jnihelp;
Kyle Zhangb61d8022023-10-04 00:14:59 +0000269
270 if (gFields.exceptionCtors.count(std::string(className)) == 0) {
271 jniThrowException(env, className, msg);
272 } else {
273 jstring _detailMessage = CreateExceptionMsg(env, msg);
274 jobject exception = env->NewObject(gFields.exceptionCtors[std::string(className)].classId,
275 gFields.exceptionCtors[std::string(className)].init, _detailMessage,
276 err.getCdmErr(), err.getOemErr(), err.getContext());
277 env->Throw(static_cast<jthrowable>(exception));
278 if (_detailMessage != NULL) {
279 env->DeleteLocalRef(_detailMessage);
280 }
Robert Shih46849832022-12-15 10:30:51 -0800281 }
Robert Shih46849832022-12-15 10:30:51 -0800282}
Adam Stone94395c92018-01-30 12:07:00 -0800283} // namespace anonymous
284
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700285// ----------------------------------------------------------------------------
286// ref-counted object for callbacks
287class JNIDrmListener: public DrmListener
288{
289public:
290 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
291 ~JNIDrmListener();
Robert Shih9d4e2d42019-11-08 13:51:49 -0800292 virtual void notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *arg = NULL);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700293private:
294 JNIDrmListener();
295 jclass mClass; // Reference to MediaDrm class
296 jobject mObject; // Weak ref to MediaDrm Java object to call on
297};
298
299JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
300{
301 // Hold onto the MediaDrm class for use in calling the static method
302 // that posts events to the application thread.
303 jclass clazz = env->GetObjectClass(thiz);
304 if (clazz == NULL) {
305 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700306 jniThrowException(env, "java/lang/Exception",
307 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700308 return;
309 }
310 mClass = (jclass)env->NewGlobalRef(clazz);
311
312 // We use a weak reference so the MediaDrm object can be garbage collected.
313 // The reference is only used as a proxy for callbacks.
314 mObject = env->NewGlobalRef(weak_thiz);
315}
316
317JNIDrmListener::~JNIDrmListener()
318{
319 // remove global references
320 JNIEnv *env = AndroidRuntime::getJNIEnv();
321 env->DeleteGlobalRef(mObject);
322 env->DeleteGlobalRef(mClass);
323}
324
325void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
Robert Shih9d4e2d42019-11-08 13:51:49 -0800326 const ListenerArgs *args)
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700327{
Jeff Tinker74797f82015-03-31 15:44:34 -0700328 jint jwhat;
329 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700330
331 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700332 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700333 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700334 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700335 jeventType = gEventTypes.kEventProvisionRequired;
336 break;
337 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700338 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700339 jeventType = gEventTypes.kEventKeyRequired;
340 break;
341 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700342 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700343 jeventType = gEventTypes.kEventKeyExpired;
344 break;
345 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700346 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700347 jeventType = gEventTypes.kEventVendorDefined;
348 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800349 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700350 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800351 jeventType = gEventTypes.kEventSessionReclaimed;
352 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700353 case DrmPlugin::kDrmPluginEventExpirationUpdate:
354 jwhat = gEventWhat.kWhatExpirationUpdate;
355 break;
356 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700357 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700358 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800359 case DrmPlugin::kDrmPluginEventSessionLostState:
360 jwhat = gEventWhat.kWhatSessionLostState;
361 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700362 default:
363 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
364 return;
365 }
366
367 JNIEnv *env = AndroidRuntime::getJNIEnv();
Robert Shih9d4e2d42019-11-08 13:51:49 -0800368 if (args) {
369 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
370 jwhat, jeventType, extra,
371 args->jSessionId, args->jData, args->jExpirationTime,
372 args->jKeyStatusList, args->jHasNewUsableKey);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700373 }
374
375 if (env->ExceptionCheck()) {
376 ALOGW("An exception occurred while notifying an event.");
377 LOGW_EX(env);
378 env->ExceptionClear();
379 }
380}
381
Robert Shih620f4a62021-02-15 03:28:42 -0800382jint MediaErrorToJavaError(status_t err) {
383#define STATUS_CASE(status) \
384 case status: \
385 return J##status
386
387 switch (err) {
388 STATUS_CASE(ERROR_DRM_UNKNOWN);
389 STATUS_CASE(ERROR_DRM_NO_LICENSE);
390 STATUS_CASE(ERROR_DRM_LICENSE_EXPIRED);
391 STATUS_CASE(ERROR_DRM_RESOURCE_BUSY);
392 STATUS_CASE(ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION);
393 STATUS_CASE(ERROR_DRM_SESSION_NOT_OPENED);
394 STATUS_CASE(ERROR_DRM_CANNOT_HANDLE);
395 STATUS_CASE(ERROR_DRM_INSUFFICIENT_SECURITY);
396 STATUS_CASE(ERROR_DRM_FRAME_TOO_LARGE);
397 STATUS_CASE(ERROR_DRM_SESSION_LOST_STATE);
398 STATUS_CASE(ERROR_DRM_CERTIFICATE_MALFORMED);
399 STATUS_CASE(ERROR_DRM_CERTIFICATE_MISSING);
400 STATUS_CASE(ERROR_DRM_CRYPTO_LIBRARY);
401 STATUS_CASE(ERROR_DRM_GENERIC_OEM);
402 STATUS_CASE(ERROR_DRM_GENERIC_PLUGIN);
403 STATUS_CASE(ERROR_DRM_INIT_DATA);
404 STATUS_CASE(ERROR_DRM_KEY_NOT_LOADED);
405 STATUS_CASE(ERROR_DRM_LICENSE_PARSE);
406 STATUS_CASE(ERROR_DRM_LICENSE_POLICY);
407 STATUS_CASE(ERROR_DRM_LICENSE_RELEASE);
408 STATUS_CASE(ERROR_DRM_LICENSE_REQUEST_REJECTED);
409 STATUS_CASE(ERROR_DRM_LICENSE_RESTORE);
410 STATUS_CASE(ERROR_DRM_LICENSE_STATE);
411 STATUS_CASE(ERROR_DRM_MEDIA_FRAMEWORK);
412 STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE);
413 STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG);
414 STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE);
Robert Shiha37ae8e2021-03-03 03:35:12 -0800415 STATUS_CASE(ERROR_DRM_PROVISIONING_REQUEST_REJECTED);
Robert Shih620f4a62021-02-15 03:28:42 -0800416 STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY);
417 STATUS_CASE(ERROR_DRM_RESOURCE_CONTENTION);
418 STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE);
419 STATUS_CASE(ERROR_DRM_STORAGE_READ);
420 STATUS_CASE(ERROR_DRM_STORAGE_WRITE);
421 STATUS_CASE(ERROR_DRM_ZERO_SUBSAMPLES);
422#undef STATUS_CASE
423 }
424 return static_cast<jint>(err);
425}
426
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530427static void throwStateException(JNIEnv *env, const char *msg, const DrmStatus &err) {
428 ALOGE("Illegal state exception: %s (%d)", msg, static_cast<status_t>(err));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700429
Robert Shih620f4a62021-02-15 03:28:42 -0800430 jint jerr = MediaErrorToJavaError(err);
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700431 jobject exception = env->NewObject(gFields.stateException.classId,
Robert Shih46849832022-12-15 10:30:51 -0800432 gFields.stateException.init, env->NewStringUTF(msg), static_cast<int>(jerr),
433 err.getCdmErr(), err.getOemErr(), err.getContext());
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700434 env->Throw(static_cast<jthrowable>(exception));
435}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700436
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530437static void throwSessionException(JNIEnv *env, const char *msg, const DrmStatus &err) {
438 ALOGE("Session exception: %s (%d)", msg, static_cast<status_t>(err));
Jeff Tinker20594d82018-12-12 08:31:22 -0800439
440 jint jErrorCode = 0;
441 switch(err) {
442 case ERROR_DRM_RESOURCE_CONTENTION:
443 jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
444 break;
445 default:
446 break;
447 }
448
449 jobject exception = env->NewObject(gFields.sessionException.classId,
Robert Shih46849832022-12-15 10:30:51 -0800450 gFields.sessionException.init,
451 env->NewStringUTF(msg),
452 jErrorCode,
453 err.getCdmErr(),
454 err.getOemErr(),
455 err.getContext());
Jeff Tinker20594d82018-12-12 08:31:22 -0800456
Jeff Tinker20594d82018-12-12 08:31:22 -0800457 env->Throw(static_cast<jthrowable>(exception));
458}
459
460static bool isSessionException(status_t err) {
461 return err == ERROR_DRM_RESOURCE_CONTENTION;
462}
463
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800464static bool throwExceptionAsNecessary(
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530465 JNIEnv *env, const sp<IDrm> &drm, const DrmStatus &err, const char *msg = NULL) {
Robert Shih60dab872021-02-13 11:24:59 -0800466 std::string msgStr;
Robert Shih13eb27b2021-02-20 00:08:16 -0800467 if (drm != NULL && err != OK) {
Robert Shih60dab872021-02-13 11:24:59 -0800468 msgStr = DrmUtils::GetExceptionMessage(err, msg, drm);
469 msg = msgStr.c_str();
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700470 }
471
Jeff Tinkereb13c762017-11-01 15:29:38 -0700472 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800473 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
474 return true;
Jeff Tinker5de2e902019-01-25 23:09:36 -0800475 } else if (err == ERROR_UNSUPPORTED) {
476 jniThrowException(env, "java/lang/UnsupportedOperationException", msg);
477 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700478 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
Robert Shih46849832022-12-15 10:30:51 -0800479 drmThrowException(env, "android/media/NotProvisionedException", err, msg);
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700480 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700481 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
Robert Shih46849832022-12-15 10:30:51 -0800482 drmThrowException(env, "android/media/ResourceBusyException", err, msg);
Jeff Tinker3ed38262013-08-02 23:24:51 -0700483 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700484 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
Robert Shih46849832022-12-15 10:30:51 -0800485 drmThrowException(env, "android/media/DeniedByServerException", err, msg);
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700486 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700487 } else if (err == DEAD_OBJECT) {
Robert Shih250f6a72021-02-26 08:20:31 -0800488 jniThrowException(env, "android/media/MediaDrmResetException", msg);
Jeff Tinker314b7f32015-06-15 17:45:43 -0700489 return true;
Jeff Tinker20594d82018-12-12 08:31:22 -0800490 } else if (isSessionException(err)) {
491 throwSessionException(env, msg, err);
492 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800493 } else if (err != OK) {
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700494 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800495 return true;
496 }
497 return false;
498}
499
500static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000501 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800502 return jdrm ? jdrm->getDrm() : NULL;
503}
504
505JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800506 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
507 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800508 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800509 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700510 if (mDrm != NULL) {
511 mDrm->setListener(this);
512 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800513}
514
515JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800516 JNIEnv *env = AndroidRuntime::getJNIEnv();
517
518 env->DeleteWeakGlobalRef(mObject);
519 mObject = NULL;
520}
521
522// static
523sp<IDrm> JDrm::MakeDrm() {
Robert Shih218b9532019-08-15 14:48:11 -0700524 return DrmUtils::MakeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800525}
526
527// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800528sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800529 sp<IDrm> drm = MakeDrm();
530
531 if (drm == NULL) {
532 return NULL;
533 }
534
Sohail Nagarajc7e8e372022-12-14 11:25:58 +0530535 DrmStatus err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800536
537 if (err != OK) {
538 return NULL;
539 }
540
541 return drm;
542}
543
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700544status_t JDrm::setListener(const sp<DrmListener>& listener) {
545 Mutex::Autolock lock(mLock);
546 mListener = listener;
547 return OK;
548}
549
Robert Shih9d4e2d42019-11-08 13:51:49 -0800550void JDrm::notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *args) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700551 sp<DrmListener> listener;
552 mLock.lock();
553 listener = mListener;
554 mLock.unlock();
555
556 if (listener != NULL) {
557 Mutex::Autolock lock(mNotifyLock);
Robert Shih9d4e2d42019-11-08 13:51:49 -0800558 listener->notify(eventType, extra, args);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700559 }
560}
561
Robert Shih3a523902019-08-15 14:48:11 -0700562void JDrm::sendEvent(
563 DrmPlugin::EventType eventType,
564 const hardware::hidl_vec<uint8_t> &sessionId,
565 const hardware::hidl_vec<uint8_t> &data) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800566 ListenerArgs args{
567 .jSessionId = hidlVectorToJByteArray(sessionId),
568 .jData = hidlVectorToJByteArray(data),
569 };
570 notify(eventType, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700571}
572
573void JDrm::sendExpirationUpdate(
574 const hardware::hidl_vec<uint8_t> &sessionId,
575 int64_t expiryTimeInMS) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800576 ListenerArgs args{
577 .jSessionId = hidlVectorToJByteArray(sessionId),
578 .jExpirationTime = expiryTimeInMS,
579 };
580 notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700581}
582
583void JDrm::sendKeysChange(
584 const hardware::hidl_vec<uint8_t> &sessionId,
585 const std::vector<DrmKeyStatus> &keyStatusList,
586 bool hasNewUsableKey) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800587 JNIEnv *env = AndroidRuntime::getJNIEnv();
588 jclass clazz = gFields.arraylistClassId;
589 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
590 clazz = gFields.keyStatus.classId;
591 for (const auto &keyStatus : keyStatusList) {
592 jbyteArray jKeyId(hidlVectorToJByteArray(keyStatus.keyId));
593 jint jStatusCode(keyStatus.type);
594 jobject jKeyStatus = env->NewObject(clazz, gFields.keyStatus.init, jKeyId, jStatusCode);
595 env->CallBooleanMethod(arrayList, gFields.arraylist.add, jKeyStatus);
596 }
597 ListenerArgs args{
598 .jSessionId = hidlVectorToJByteArray(sessionId),
599 .jKeyStatusList = arrayList,
600 .jHasNewUsableKey = hasNewUsableKey,
601 };
602 notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700603}
604
605void JDrm::sendSessionLostState(
606 const hardware::hidl_vec<uint8_t> &sessionId) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800607 ListenerArgs args{
608 .jSessionId = hidlVectorToJByteArray(sessionId),
609 };
610 notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700611}
612
Jeff Tinker600071c2014-04-11 16:11:15 -0700613void JDrm::disconnect() {
614 if (mDrm != NULL) {
615 mDrm->destroyPlugin();
616 mDrm.clear();
617 }
618}
619
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700620
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800621// static
Jeff Tinker5de2e902019-01-25 23:09:36 -0800622status_t JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
623 DrmPlugin::SecurityLevel securityLevel, bool *isSupported) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800624 sp<IDrm> drm = MakeDrm();
625
626 if (drm == NULL) {
Jeff Tinker5de2e902019-01-25 23:09:36 -0800627 return BAD_VALUE;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800628 }
629
Jeff Tinker5de2e902019-01-25 23:09:36 -0800630 return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel, isSupported);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800631}
632
633status_t JDrm::initCheck() const {
634 return mDrm == NULL ? NO_INIT : OK;
635}
636
637// JNI conversion utilities
638static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
639 Vector<uint8_t> vector;
640 size_t length = env->GetArrayLength(byteArray);
641 vector.insertAt((size_t)0, length);
642 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
643 return vector;
644}
645
646static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
647 size_t length = vector.size();
648 jbyteArray result = env->NewByteArray(length);
649 if (result != NULL) {
650 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
651 }
652 return result;
653}
654
655static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800656 String8 result;
657
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700658 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800659 if (s) {
660 result = s;
661 env->ReleaseStringUTFChars(jstr, s);
662 }
663 return result;
664}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700665
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800666/*
667 import java.util.HashMap;
668 import java.util.Set;
669 import java.Map.Entry;
670 import jav.util.Iterator;
671
672 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800673 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800674 Iterator i = s.iterator();
675 Entry e = s.next();
676*/
677
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200678static KeyedVector<String8, String8> HashMapToKeyedVector(
679 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800680 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800681 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200682 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800683
684 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
685 if (entrySet) {
686 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
687 if (iterator) {
688 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
689 while (hasNext) {
690 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
691 if (entry) {
692 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200693 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700694 jniThrowException(env, "java/lang/IllegalArgumentException",
695 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200696 env->DeleteLocalRef(entry);
697 *pIsOK = false;
698 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800699 }
700 jstring jkey = static_cast<jstring>(obj);
701
702 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200703 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700704 jniThrowException(env, "java/lang/IllegalArgumentException",
705 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200706 env->DeleteLocalRef(entry);
707 *pIsOK = false;
708 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800709 }
710 jstring jvalue = static_cast<jstring>(obj);
711
712 String8 key = JStringToString8(env, jkey);
713 String8 value = JStringToString8(env, jvalue);
714 keyedVector.add(key, value);
715
716 env->DeleteLocalRef(jkey);
717 env->DeleteLocalRef(jvalue);
718 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
719 }
720 env->DeleteLocalRef(entry);
721 }
722 env->DeleteLocalRef(iterator);
723 }
724 env->DeleteLocalRef(entrySet);
725 }
726 return keyedVector;
727}
728
729static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800730 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800731 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
732 for (size_t i = 0; i < map.size(); ++i) {
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +0000733 jstring jkey = env->NewStringUTF(map.keyAt(i).c_str());
734 jstring jvalue = env->NewStringUTF(map.valueAt(i).c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800735 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
736 env->DeleteLocalRef(jkey);
737 env->DeleteLocalRef(jvalue);
738 }
739 return hashMap;
740}
741
742static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800743 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800744 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800745 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800746 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800747 while (iter != list.end()) {
748 jbyteArray byteArray = VectorToJByteArray(env, *iter);
749 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
750 env->DeleteLocalRef(byteArray);
751 iter++;
752 }
753
754 return arrayList;
755}
756
757} // namespace android
758
759using namespace android;
760
761static sp<JDrm> setDrm(
762 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000763 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800764 if (drm != NULL) {
765 drm->incStrong(thiz);
766 }
767 if (old != NULL) {
768 old->decStrong(thiz);
769 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000770 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800771
772 return old;
773}
774
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800775static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800776 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700777 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800778 return false;
779 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800780 return true;
781}
782
783static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
784{
785 if (!CheckDrm(env, drm)) {
786 return false;
787 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800788
789 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700790 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800791 return false;
792 }
793 return true;
794}
795
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800796static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700797 sp<JDrm> drm = setDrm(env, thiz, NULL);
798 if (drm != NULL) {
799 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700800 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700801 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800802}
803
804static void android_media_MediaDrm_native_init(JNIEnv *env) {
805 jclass clazz;
806 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000807 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700808 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Robert Shih9d4e2d42019-11-08 13:51:49 -0800809 "(Ljava/lang/Object;III[B[BJLjava/util/List;Z)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700810
811 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700812 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700813 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700814 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700815 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700816 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700817 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700818 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700819 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800820 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
821 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800822
Jeff Tinker74797f82015-03-31 15:44:34 -0700823 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
824 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
825 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
826 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700827 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
828 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800829 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
830 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700831
Jeff Tinker17b89222013-05-21 12:35:06 -0700832 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
833 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
834 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
835 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
836 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
837 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
838
Jeff Tinkere4095a82014-03-04 13:17:11 -0800839 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
840 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
841 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
842 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
843
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800844 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
845 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
846 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
847 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
848 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
849 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
850 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
851 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
852 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
853 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
854 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
855 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800856 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
857 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800858 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
859 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
860
861 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
862 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700863 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800864 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700865 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800866 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700867 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800868 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700869 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800870 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700871 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800872 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
873
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800874 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_USABLE", "I");
Jeff Tinker55d26242018-10-10 16:10:43 -0700875 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800876 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_RELEASED", "I");
877 gOfflineLicenseStates.kOfflineLicenseStateReleased = env->GetStaticIntField(clazz, field);
Jeff Tinker55d26242018-10-10 16:10:43 -0700878 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
879 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
880
881 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
882
Jeff Tinker2bca5252018-02-11 18:59:14 +0000883 jmethodID getMaxSecurityLevel;
884 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
885 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
886
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700887 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700888 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
889 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700890 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800891
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700892 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
893 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
894 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
895 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
896 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
897 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800898 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
899 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
900 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
901 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700902
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800903 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700904 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
905 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800906
Jeff Tinkere4095a82014-03-04 13:17:11 -0800907 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
908 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
909 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700910 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800911
Adam Stone94395c92018-01-30 12:07:00 -0800912 // Metrics-related fields and classes.
913 FIND_CLASS(clazz, "android/os/PersistableBundle");
914 jfieldID bundleCreatorId;
915 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
916 "Landroid/os/Parcelable$Creator;");
917 jobject bundleCreator;
918 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
919 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
920 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
921 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
922 "(Landroid/os/Parcel;)Ljava/lang/Object;");
923 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
924
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800925 FIND_CLASS(clazz, "java/util/ArrayList");
926 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
927 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
928
929 FIND_CLASS(clazz, "java/util/HashMap");
930 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
931 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
932 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
933 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
934 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
935
936 FIND_CLASS(clazz, "java/util/Set");
937 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
938
939 FIND_CLASS(clazz, "java/util/Iterator");
940 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
941 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
942
943 FIND_CLASS(clazz, "java/util/Map$Entry");
944 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
945 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800946
947 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700948 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800949
950 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700951 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800952
953 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700954 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700955
956 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
Robert Shih46849832022-12-15 10:30:51 -0800957 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(Ljava/lang/String;IIII)V");
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700958 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800959
960 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
Robert Shih46849832022-12-15 10:30:51 -0800961 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(Ljava/lang/String;IIII)V");
Jeff Tinker20594d82018-12-12 08:31:22 -0800962 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
963 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
964
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800965 GET_STATIC_FIELD_ID(field, clazz, "ERROR_UNKNOWN", "I");
966 gSessionExceptionErrorCodes.kErrorUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800967 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
968 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Robert Shih9d4e2d42019-11-08 13:51:49 -0800969
970 FIND_CLASS(clazz, "android/media/MediaDrm$KeyStatus");
971 gFields.keyStatus.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
972 GET_METHOD_ID(gFields.keyStatus.init, clazz, "<init>", "([BI)V");
Robert Shih696989f2021-02-12 23:25:16 -0800973
974 FIND_CLASS(clazz, "android/media/MediaDrm$LogMessage");
975 gFields.logMessage.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
976 GET_METHOD_ID(gFields.logMessage.init, clazz, "<init>", "(JILjava/lang/String;)V");
Kyle Zhangb61d8022023-10-04 00:14:59 +0000977
978 resolveDrmExceptionCtor(env, "android/media/NotProvisionedException");
979 resolveDrmExceptionCtor(env, "android/media/ResourceBusyException");
980 resolveDrmExceptionCtor(env, "android/media/DeniedByServerException");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800981}
982
983static void android_media_MediaDrm_native_setup(
984 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800985 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800986
987 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700988 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800989 return;
990 }
991
992 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
993
994 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700995 jniThrowException(env, "java/lang/IllegalArgumentException",
996 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800997 return;
998 }
999
Edwin Wong4d1d84e2017-01-04 09:37:49 -08001000 String8 packageName;
1001 if (jappPackageName == NULL) {
1002 jniThrowException(env, "java/lang/IllegalArgumentException",
1003 "application package name cannot be null");
1004 return;
1005 }
1006
1007 packageName = JStringToString8(env, jappPackageName);
1008 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001009
1010 status_t err = drm->initCheck();
1011
1012 if (err != OK) {
Robert Shih250f6a72021-02-26 08:20:31 -08001013 auto logs(DrmUtils::gLogBuf.getLogs());
1014 auto msg(DrmUtils::GetExceptionMessage(err, "Failed to instantiate drm object", logs));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001015 jniThrowException(
1016 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -07001017 "android/media/UnsupportedSchemeException",
Robert Shih250f6a72021-02-26 08:20:31 -08001018 msg.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001019 return;
1020 }
1021
Jeff Tinker54cfbd62013-04-02 13:14:59 -07001022 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
1023 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001024 setDrm(env, thiz, drm);
1025}
1026
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001027DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
1028 DrmPlugin::SecurityLevel level;
1029
1030 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
1031 level = DrmPlugin::kSecurityLevelMax;
1032 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
1033 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
1034 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
1035 level = DrmPlugin::kSecurityLevelSwSecureDecode;
1036 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
1037 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
1038 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
1039 level = DrmPlugin::kSecurityLevelHwSecureDecode;
1040 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
1041 level = DrmPlugin::kSecurityLevelHwSecureAll;
1042 } else {
1043 level = DrmPlugin::kSecurityLevelUnknown;
1044 }
1045 return level;
1046}
1047
Robert Shihd2e8b432019-11-21 20:27:56 -08001048static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
Kyle Zhang621af3e2022-03-17 23:39:05 +00001049 sp<IDrm> drm = android::DrmUtils::MakeDrm();
Kyle Zhang452bc552023-01-23 22:37:45 +00001050 if (drm == NULL) return env->NewByteArray(0);
1051
Robert Shihd2e8b432019-11-21 20:27:56 -08001052 std::vector<uint8_t> bv;
Kyle Zhang621af3e2022-03-17 23:39:05 +00001053 drm->getSupportedSchemes(bv);
Robert Shihd2e8b432019-11-21 20:27:56 -08001054 jbyteArray jUuidBytes = env->NewByteArray(bv.size());
1055 env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
1056 return jUuidBytes;
1057}
1058
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001059static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001060 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
1061 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001062
1063 if (uuidObj == NULL) {
1064 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1065 return false;
1066 }
1067
1068 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
1069
1070 if (uuid.size() != 16) {
1071 jniThrowException(
1072 env,
1073 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -07001074 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001075 return false;
1076 }
1077
Jeff Tinker7cda4912013-08-21 11:52:34 -07001078 String8 mimeType;
1079 if (jmimeType != NULL) {
1080 mimeType = JStringToString8(env, jmimeType);
1081 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001082 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -07001083
Jeff Tinker5de2e902019-01-25 23:09:36 -08001084 bool isSupported;
1085 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
1086 securityLevel, &isSupported);
1087
Robert Shih60dab872021-02-13 11:24:59 -08001088 if (throwExceptionAsNecessary(env, NULL, err, "Failed to query crypto scheme support")) {
Jeff Tinker5de2e902019-01-25 23:09:36 -08001089 return false;
1090 }
1091 return isSupported;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001092}
1093
1094static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +00001095 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001096 sp<IDrm> drm = GetDrm(env, thiz);
1097
Jeff Tinker55d26242018-10-10 16:10:43 -07001098 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001099 return NULL;
1100 }
1101
1102 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001103 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1104 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +00001105 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1106 return NULL;
1107 }
1108
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301109 DrmStatus err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001110
Robert Shih60dab872021-02-13 11:24:59 -08001111 if (throwExceptionAsNecessary(env, drm, err, "Failed to open session")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001112 return NULL;
1113 }
1114
1115 return VectorToJByteArray(env, sessionId);
1116}
1117
1118static void android_media_MediaDrm_closeSession(
1119 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1120 sp<IDrm> drm = GetDrm(env, thiz);
1121
1122 if (!CheckSession(env, drm, jsessionId)) {
1123 return;
1124 }
1125
1126 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1127
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301128 DrmStatus err = drm->closeSession(sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001129
Robert Shih60dab872021-02-13 11:24:59 -08001130 throwExceptionAsNecessary(env, drm, err, "Failed to close session");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001131}
1132
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001133static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001134 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001135 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001136 sp<IDrm> drm = GetDrm(env, thiz);
1137
1138 if (!CheckSession(env, drm, jsessionId)) {
1139 return NULL;
1140 }
1141
1142 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1143
1144 Vector<uint8_t> initData;
1145 if (jinitData != NULL) {
1146 initData = JByteArrayToVector(env, jinitData);
1147 }
1148
1149 String8 mimeType;
1150 if (jmimeType != NULL) {
1151 mimeType = JStringToString8(env, jmimeType);
1152 }
1153
Jeff Tinker17b89222013-05-21 12:35:06 -07001154 DrmPlugin::KeyType keyType;
1155 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1156 keyType = DrmPlugin::kKeyType_Streaming;
1157 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1158 keyType = DrmPlugin::kKeyType_Offline;
1159 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1160 keyType = DrmPlugin::kKeyType_Release;
1161 } else {
1162 jniThrowException(env, "java/lang/IllegalArgumentException",
1163 "invalid keyType");
1164 return NULL;
1165 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001166
1167 KeyedVector<String8, String8> optParams;
1168 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001169 bool isOK;
1170 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1171 if (!isOK) {
1172 return NULL;
1173 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001174 }
1175
1176 Vector<uint8_t> request;
1177 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001178 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001179
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301180 DrmStatus err = drm->getKeyRequest(sessionId, initData, mimeType, keyType, optParams, request,
1181 defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001182
Robert Shih60dab872021-02-13 11:24:59 -08001183 if (throwExceptionAsNecessary(env, drm, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001184 return NULL;
1185 }
1186
1187 // Fill out return obj
1188 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001189 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001190
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001191 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001192
1193 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001194 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001195 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001196 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001197
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001198 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.c_str());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001199 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001200
1201 switch (keyRequestType) {
1202 case DrmPlugin::kKeyRequestType_Initial:
1203 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1204 gKeyRequestTypes.kKeyRequestTypeInitial);
1205 break;
1206 case DrmPlugin::kKeyRequestType_Renewal:
1207 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1208 gKeyRequestTypes.kKeyRequestTypeRenewal);
1209 break;
1210 case DrmPlugin::kKeyRequestType_Release:
1211 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1212 gKeyRequestTypes.kKeyRequestTypeRelease);
1213 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001214 case DrmPlugin::kKeyRequestType_None:
1215 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1216 gKeyRequestTypes.kKeyRequestTypeNone);
1217 break;
1218 case DrmPlugin::kKeyRequestType_Update:
1219 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1220 gKeyRequestTypes.kKeyRequestTypeUpdate);
1221 break;
1222
Jeff Tinker74797f82015-03-31 15:44:34 -07001223 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001224 throwStateException(env, "DRM plugin failure: unknown key request type",
1225 ERROR_DRM_UNKNOWN);
1226 break;
1227 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001228 }
1229
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001230 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001231}
1232
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001233static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001234 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1235 sp<IDrm> drm = GetDrm(env, thiz);
1236
1237 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001238 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001239 }
1240
1241 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1242
1243 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001244 jniThrowException(env, "java/lang/IllegalArgumentException",
1245 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001246 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001247 }
1248 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001249 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001250
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301251 DrmStatus err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001252
Robert Shih60dab872021-02-13 11:24:59 -08001253 if (throwExceptionAsNecessary(env, drm, err, "Failed to handle key response")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001254 return NULL;
1255 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001256 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001257}
1258
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001259static void android_media_MediaDrm_removeKeys(
1260 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1261 sp<IDrm> drm = GetDrm(env, thiz);
1262
Jeff Tinker55d26242018-10-10 16:10:43 -07001263 if (!CheckDrm(env, drm)) {
1264 return;
1265 }
1266
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001267 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001268 jniThrowException(env, "java/lang/IllegalArgumentException",
1269 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001270 return;
1271 }
1272
1273 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1274
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301275 DrmStatus err = drm->removeKeys(keySetId);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001276
Robert Shih60dab872021-02-13 11:24:59 -08001277 throwExceptionAsNecessary(env, drm, err, "Failed to remove keys");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001278}
1279
1280static void android_media_MediaDrm_restoreKeys(
1281 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1282 jbyteArray jkeysetId) {
1283
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001284 sp<IDrm> drm = GetDrm(env, thiz);
1285
1286 if (!CheckSession(env, drm, jsessionId)) {
1287 return;
1288 }
1289
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001290 if (jkeysetId == NULL) {
1291 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1292 return;
1293 }
1294
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001295 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001296 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001297
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301298 DrmStatus err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001299
Robert Shih60dab872021-02-13 11:24:59 -08001300 throwExceptionAsNecessary(env, drm, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001301}
1302
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001303static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001304 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1305 sp<IDrm> drm = GetDrm(env, thiz);
1306
1307 if (!CheckSession(env, drm, jsessionId)) {
1308 return NULL;
1309 }
1310 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1311
1312 KeyedVector<String8, String8> infoMap;
1313
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301314 DrmStatus err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001315
Robert Shih60dab872021-02-13 11:24:59 -08001316 if (throwExceptionAsNecessary(env, drm, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001317 return NULL;
1318 }
1319
1320 return KeyedVectorToHashMap(env, infoMap);
1321}
1322
Jeff Tinkere4095a82014-03-04 13:17:11 -08001323static jobject android_media_MediaDrm_getProvisionRequestNative(
1324 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001325 sp<IDrm> drm = GetDrm(env, thiz);
1326
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001327 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001328 return NULL;
1329 }
1330
1331 Vector<uint8_t> request;
1332 String8 defaultUrl;
1333
Jeff Tinkere4095a82014-03-04 13:17:11 -08001334 String8 certType;
1335 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1336 certType = "X.509";
1337 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1338 certType = "none";
1339 } else {
1340 certType = "invalid";
1341 }
1342
1343 String8 certAuthority = JStringToString8(env, jcertAuthority);
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301344 DrmStatus err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001345
Robert Shih60dab872021-02-13 11:24:59 -08001346 if (throwExceptionAsNecessary(env, drm, err, "Failed to get provision request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001347 return NULL;
1348 }
1349
1350 // Fill out return obj
1351 jclass clazz;
1352 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1353
1354 jobject provisionObj = NULL;
1355
1356 if (clazz) {
1357 provisionObj = env->AllocObject(clazz);
1358 jbyteArray jrequest = VectorToJByteArray(env, request);
1359 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1360
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001361 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001362 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1363 }
1364
1365 return provisionObj;
1366}
1367
Jeff Tinkere4095a82014-03-04 13:17:11 -08001368static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001369 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1370 sp<IDrm> drm = GetDrm(env, thiz);
1371
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001372 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001373 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001374 }
1375
1376 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001377 jniThrowException(env, "java/lang/IllegalArgumentException",
1378 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001379 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001380 }
1381
1382 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001383 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001384
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301385 DrmStatus err = drm->provideProvisionResponse(response, certificate, wrappedKey);
Jeff Tinkere4095a82014-03-04 13:17:11 -08001386
1387 // Fill out return obj
1388 jclass clazz = gFields.certificateClassId;
1389
1390 jobject certificateObj = NULL;
1391
1392 if (clazz && certificate.size() && wrappedKey.size()) {
1393 certificateObj = env->AllocObject(clazz);
1394 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1395 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1396
1397 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1398 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1399 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001400
Robert Shih60dab872021-02-13 11:24:59 -08001401 throwExceptionAsNecessary(env, drm, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001402 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001403}
1404
1405static jobject android_media_MediaDrm_getSecureStops(
1406 JNIEnv *env, jobject thiz) {
1407 sp<IDrm> drm = GetDrm(env, thiz);
1408
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001409 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001410 return NULL;
1411 }
1412
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001413 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001414
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301415 DrmStatus err = drm->getSecureStops(secureStops);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001416
Robert Shih60dab872021-02-13 11:24:59 -08001417 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stops")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001418 return NULL;
1419 }
1420
1421 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1422}
1423
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001424static jobject android_media_MediaDrm_getSecureStopIds(
1425 JNIEnv *env, jobject thiz) {
1426 sp<IDrm> drm = GetDrm(env, thiz);
1427
Jeff Tinker55d26242018-10-10 16:10:43 -07001428 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001429 return NULL;
1430 }
1431
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001432 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001433
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301434 DrmStatus err = drm->getSecureStopIds(secureStopIds);
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001435
Robert Shih60dab872021-02-13 11:24:59 -08001436 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop Ids")) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001437 return NULL;
1438 }
1439
1440 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1441}
1442
Jeff Tinker1b51c722014-10-31 00:54:26 -07001443static jbyteArray android_media_MediaDrm_getSecureStop(
1444 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1445 sp<IDrm> drm = GetDrm(env, thiz);
1446
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001447 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001448 return NULL;
1449 }
1450
1451 Vector<uint8_t> secureStop;
1452
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301453 DrmStatus err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
Jeff Tinker1b51c722014-10-31 00:54:26 -07001454
Robert Shih60dab872021-02-13 11:24:59 -08001455 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop")) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001456 return NULL;
1457 }
1458
1459 return VectorToJByteArray(env, secureStop);
1460}
1461
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001462static void android_media_MediaDrm_releaseSecureStops(
1463 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1464 sp<IDrm> drm = GetDrm(env, thiz);
1465
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001466 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001467 return;
1468 }
1469
1470 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1471
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301472 DrmStatus err = drm->releaseSecureStops(ssRelease);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001473
Robert Shih60dab872021-02-13 11:24:59 -08001474 throwExceptionAsNecessary(env, drm, err, "Failed to release secure stops");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001475}
1476
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001477static void android_media_MediaDrm_removeSecureStop(
1478 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1479 sp<IDrm> drm = GetDrm(env, thiz);
1480
Jeff Tinker55d26242018-10-10 16:10:43 -07001481 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001482 return;
1483 }
1484
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301485 DrmStatus err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001486
Robert Shih60dab872021-02-13 11:24:59 -08001487 throwExceptionAsNecessary(env, drm, err, "Failed to remove secure stop");
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001488}
1489
1490static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001491 JNIEnv *env, jobject thiz) {
1492 sp<IDrm> drm = GetDrm(env, thiz);
1493
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001494 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001495 return;
1496 }
1497
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301498 DrmStatus err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001499
Robert Shih60dab872021-02-13 11:24:59 -08001500 throwExceptionAsNecessary(env, drm, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001501}
1502
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001503
1504static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1505 switch(level) {
1506 case DrmPlugin::kHdcpLevelUnknown:
1507 return gHdcpLevels.kHdcpLevelUnknown;
1508 case DrmPlugin::kHdcpNone:
1509 return gHdcpLevels.kHdcpNone;
1510 case DrmPlugin::kHdcpV1:
1511 return gHdcpLevels.kHdcpV1;
1512 case DrmPlugin::kHdcpV2:
1513 return gHdcpLevels.kHdcpV2;
1514 case DrmPlugin::kHdcpV2_1:
1515 return gHdcpLevels.kHdcpV2_1;
1516 case DrmPlugin::kHdcpV2_2:
1517 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001518 case DrmPlugin::kHdcpV2_3:
1519 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001520 case DrmPlugin::kHdcpNoOutput:
1521 return gHdcpLevels.kHdcpNoOutput;
1522 }
1523 return gHdcpLevels.kHdcpNone;
1524}
1525
1526static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1527 jobject thiz) {
1528 sp<IDrm> drm = GetDrm(env, thiz);
1529
1530 if (!CheckDrm(env, drm)) {
1531 return gHdcpLevels.kHdcpNone;
1532 }
1533
1534 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1535 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1536
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301537 DrmStatus err = drm->getHdcpLevels(&connected, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001538
Robert Shih60dab872021-02-13 11:24:59 -08001539 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001540 return gHdcpLevels.kHdcpLevelUnknown;
1541 }
1542 return HdcpLevelTojint(connected);
1543}
1544
1545static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1546 jobject thiz) {
1547 sp<IDrm> drm = GetDrm(env, thiz);
1548
1549 if (!CheckDrm(env, drm)) {
1550 return gHdcpLevels.kHdcpLevelUnknown;
1551 }
1552
1553 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1554 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1555
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301556 DrmStatus err = drm->getHdcpLevels(&connected, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001557
Robert Shih60dab872021-02-13 11:24:59 -08001558 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001559 return gHdcpLevels.kHdcpLevelUnknown;
1560 }
1561 return HdcpLevelTojint(max);
1562}
1563
1564static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1565 jobject thiz) {
1566 sp<IDrm> drm = GetDrm(env, thiz);
1567
1568 if (!CheckDrm(env, drm)) {
1569 return 0;
1570 }
1571
1572 uint32_t open = 0, max = 0;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301573 DrmStatus err = drm->getNumberOfSessions(&open, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001574
Robert Shih60dab872021-02-13 11:24:59 -08001575 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001576 return 0;
1577 }
1578 return open;
1579}
1580
1581static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1582 jobject thiz) {
1583 sp<IDrm> drm = GetDrm(env, thiz);
1584
1585 if (!CheckDrm(env, drm)) {
1586 return 0;
1587 }
1588
1589 uint32_t open = 0, max = 0;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301590 DrmStatus err = drm->getNumberOfSessions(&open, &max);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001591
Robert Shih60dab872021-02-13 11:24:59 -08001592 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001593 return 0;
1594 }
1595 return max;
1596}
1597
1598static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1599 jobject thiz, jbyteArray jsessionId) {
1600 sp<IDrm> drm = GetDrm(env, thiz);
1601
1602 if (!CheckSession(env, drm, jsessionId)) {
1603 return gSecurityLevels.kSecurityLevelUnknown;
1604 }
1605
1606 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1607
1608 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1609
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301610 DrmStatus err = drm->getSecurityLevel(sessionId, &level);
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001611
Robert Shih60dab872021-02-13 11:24:59 -08001612 if (throwExceptionAsNecessary(env, drm, err, "Failed to get security level")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001613 return gSecurityLevels.kSecurityLevelUnknown;
1614 }
1615
1616 switch(level) {
1617 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1618 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1619 case DrmPlugin::kSecurityLevelSwSecureDecode:
1620 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1621 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1622 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1623 case DrmPlugin::kSecurityLevelHwSecureDecode:
1624 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1625 case DrmPlugin::kSecurityLevelHwSecureAll:
1626 return gSecurityLevels.kSecurityLevelHwSecureAll;
1627 default:
1628 return gSecurityLevels.kSecurityLevelUnknown;
1629 }
1630}
1631
Jeff Tinker55d26242018-10-10 16:10:43 -07001632static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1633 JNIEnv *env, jobject thiz) {
1634 sp<IDrm> drm = GetDrm(env, thiz);
1635
1636 if (!CheckDrm(env, drm)) {
1637 return NULL;
1638 }
1639
1640 List<Vector<uint8_t> > keySetIds;
1641
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301642 DrmStatus err = drm->getOfflineLicenseKeySetIds(keySetIds);
Jeff Tinker55d26242018-10-10 16:10:43 -07001643
Robert Shih60dab872021-02-13 11:24:59 -08001644 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline key set Ids")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001645 return NULL;
1646 }
1647
1648 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1649}
1650
1651static void android_media_MediaDrm_removeOfflineLicense(
1652 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1653 sp<IDrm> drm = GetDrm(env, thiz);
1654
1655 if (!CheckDrm(env, drm)) {
1656 return;
1657 }
1658
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301659 DrmStatus err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
Jeff Tinker55d26242018-10-10 16:10:43 -07001660
Robert Shih60dab872021-02-13 11:24:59 -08001661 throwExceptionAsNecessary(env, drm, err, "Failed to remove offline license");
Jeff Tinker55d26242018-10-10 16:10:43 -07001662}
1663
1664static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1665 jobject thiz, jbyteArray jkeySetId) {
1666 sp<IDrm> drm = GetDrm(env, thiz);
1667
1668 if (!CheckDrm(env, drm)) {
1669 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1670 }
1671
1672 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1673
1674 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1675
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301676 DrmStatus err = drm->getOfflineLicenseState(keySetId, &state);
Jeff Tinker55d26242018-10-10 16:10:43 -07001677
Robert Shih60dab872021-02-13 11:24:59 -08001678 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline license state")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001679 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1680 }
1681
1682 switch(state) {
1683 case DrmPlugin::kOfflineLicenseStateUsable:
1684 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -08001685 case DrmPlugin::kOfflineLicenseStateReleased:
1686 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -07001687 default:
1688 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1689 }
1690}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001691
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001692static jstring android_media_MediaDrm_getPropertyString(
1693 JNIEnv *env, jobject thiz, jstring jname) {
1694 sp<IDrm> drm = GetDrm(env, thiz);
1695
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001696 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001697 return NULL;
1698 }
1699
1700 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001701 jniThrowException(env, "java/lang/IllegalArgumentException",
1702 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001703 return NULL;
1704 }
1705
1706 String8 name = JStringToString8(env, jname);
1707 String8 value;
1708
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301709 DrmStatus err = drm->getPropertyString(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001710
Robert Shih60dab872021-02-13 11:24:59 -08001711 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001712 return NULL;
1713 }
1714
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +00001715 return env->NewStringUTF(value.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001716}
1717
1718static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1719 JNIEnv *env, jobject thiz, jstring jname) {
1720 sp<IDrm> drm = GetDrm(env, thiz);
1721
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001722 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001723 return NULL;
1724 }
1725
1726 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001727 jniThrowException(env, "java/lang/IllegalArgumentException",
1728 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001729 return NULL;
1730 }
1731
1732 String8 name = JStringToString8(env, jname);
1733 Vector<uint8_t> value;
1734
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301735 DrmStatus err = drm->getPropertyByteArray(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001736
Robert Shih60dab872021-02-13 11:24:59 -08001737 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001738 return NULL;
1739 }
1740
1741 return VectorToJByteArray(env, value);
1742}
1743
1744static void android_media_MediaDrm_setPropertyString(
1745 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1746 sp<IDrm> drm = GetDrm(env, thiz);
1747
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001748 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001749 return;
1750 }
1751
Jeff Tinkereada5372013-05-21 12:48:14 -07001752 if (jname == NULL) {
1753 jniThrowException(env, "java/lang/IllegalArgumentException",
1754 "property name String is null");
1755 return;
1756 }
1757
1758 if (jvalue == NULL) {
1759 jniThrowException(env, "java/lang/IllegalArgumentException",
1760 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001761 return;
1762 }
1763
1764 String8 name = JStringToString8(env, jname);
1765 String8 value = JStringToString8(env, jvalue);
1766
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301767 DrmStatus err = drm->setPropertyString(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001768
Robert Shih60dab872021-02-13 11:24:59 -08001769 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001770}
1771
1772static void android_media_MediaDrm_setPropertyByteArray(
1773 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1774 sp<IDrm> drm = GetDrm(env, thiz);
1775
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001776 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001777 return;
1778 }
1779
Jeff Tinkereada5372013-05-21 12:48:14 -07001780 if (jname == NULL) {
1781 jniThrowException(env, "java/lang/IllegalArgumentException",
1782 "property name String is null");
1783 return;
1784 }
1785
1786 if (jvalue == NULL) {
1787 jniThrowException(env, "java/lang/IllegalArgumentException",
1788 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001789 return;
1790 }
1791
1792 String8 name = JStringToString8(env, jname);
1793 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1794
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301795 DrmStatus err = drm->setPropertyByteArray(name, value);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001796
Robert Shih60dab872021-02-13 11:24:59 -08001797 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001798}
1799
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001800static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001801 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001802 jstring jalgorithm) {
1803
1804 sp<IDrm> drm = GetDrm(env, jdrm);
1805
1806 if (!CheckSession(env, drm, jsessionId)) {
1807 return;
1808 }
1809
1810 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001811 jniThrowException(env, "java/lang/IllegalArgumentException",
1812 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001813 return;
1814 }
1815
1816 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1817 String8 algorithm = JStringToString8(env, jalgorithm);
1818
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301819 DrmStatus err = drm->setCipherAlgorithm(sessionId, algorithm);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001820
Robert Shih60dab872021-02-13 11:24:59 -08001821 throwExceptionAsNecessary(env, drm, err, "Failed to set cipher algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001822}
1823
1824static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001825 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001826 jstring jalgorithm) {
1827
1828 sp<IDrm> drm = GetDrm(env, jdrm);
1829
1830 if (!CheckSession(env, drm, jsessionId)) {
1831 return;
1832 }
1833
1834 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001835 jniThrowException(env, "java/lang/IllegalArgumentException",
1836 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001837 return;
1838 }
1839
1840 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1841 String8 algorithm = JStringToString8(env, jalgorithm);
1842
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301843 DrmStatus err = drm->setMacAlgorithm(sessionId, algorithm);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001844
Robert Shih60dab872021-02-13 11:24:59 -08001845 throwExceptionAsNecessary(env, drm, err, "Failed to set mac algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001846}
1847
1848
1849static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001850 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001851 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1852
1853 sp<IDrm> drm = GetDrm(env, jdrm);
1854
1855 if (!CheckSession(env, drm, jsessionId)) {
1856 return NULL;
1857 }
1858
1859 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001860 jniThrowException(env, "java/lang/IllegalArgumentException",
1861 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001862 return NULL;
1863 }
1864
1865 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1866 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1867 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1868 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1869 Vector<uint8_t> output;
1870
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301871 DrmStatus err = drm->encrypt(sessionId, keyId, input, iv, output);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001872
Robert Shih60dab872021-02-13 11:24:59 -08001873 if (throwExceptionAsNecessary(env, drm, err, "Failed to encrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001874 return NULL;
1875 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001876
1877 return VectorToJByteArray(env, output);
1878}
1879
1880static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001881 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001882 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1883
1884 sp<IDrm> drm = GetDrm(env, jdrm);
1885
1886 if (!CheckSession(env, drm, jsessionId)) {
1887 return NULL;
1888 }
1889
1890 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001891 jniThrowException(env, "java/lang/IllegalArgumentException",
1892 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001893 return NULL;
1894 }
1895
1896 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1897 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1898 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1899 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1900 Vector<uint8_t> output;
1901
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301902 DrmStatus err = drm->decrypt(sessionId, keyId, input, iv, output);
Robert Shih60dab872021-02-13 11:24:59 -08001903 if (throwExceptionAsNecessary(env, drm, err, "Failed to decrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001904 return NULL;
1905 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001906
1907 return VectorToJByteArray(env, output);
1908}
1909
1910static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001911 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001912 jbyteArray jkeyId, jbyteArray jmessage) {
1913
1914 sp<IDrm> drm = GetDrm(env, jdrm);
1915
1916 if (!CheckSession(env, drm, jsessionId)) {
1917 return NULL;
1918 }
1919
1920 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001921 jniThrowException(env, "java/lang/IllegalArgumentException",
1922 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001923 return NULL;
1924 }
1925
1926 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1927 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1928 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1929 Vector<uint8_t> signature;
1930
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301931 DrmStatus err = drm->sign(sessionId, keyId, message, signature);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001932
Robert Shih60dab872021-02-13 11:24:59 -08001933 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001934 return NULL;
1935 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001936
1937 return VectorToJByteArray(env, signature);
1938}
1939
1940static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001941 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001942 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1943
1944 sp<IDrm> drm = GetDrm(env, jdrm);
1945
1946 if (!CheckSession(env, drm, jsessionId)) {
1947 return false;
1948 }
1949
1950 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001951 jniThrowException(env, "java/lang/IllegalArgumentException",
1952 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001953 return false;
1954 }
1955
1956 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1957 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1958 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1959 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1960 bool match;
1961
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301962 DrmStatus err = drm->verify(sessionId, keyId, message, signature, match);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001963
Robert Shih60dab872021-02-13 11:24:59 -08001964 throwExceptionAsNecessary(env, drm, err, "Failed to verify");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001965 return match;
1966}
1967
Adam Stonec06e10e2017-12-19 12:54:33 -08001968static jobject
1969android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1970{
1971 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001972
1973 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001974 return NULL;
1975 }
1976
1977 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001978 PersistableBundle metrics;
Robert Shihba6777e2019-11-12 13:04:59 -08001979 sp<IDrmMetricsConsumer> consumer(new DrmMetricsConsumer(&metrics));
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05301980 DrmStatus err = drm->getMetrics(consumer);
Adam Stonec06e10e2017-12-19 12:54:33 -08001981 if (err != OK) {
1982 ALOGE("getMetrics failed: %d", (int)err);
1983 return (jobject) NULL;
1984 }
1985
Robert Shih4354a962019-11-10 12:09:08 -08001986 return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001987}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001988
Jeff Tinkere4095a82014-03-04 13:17:11 -08001989static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001990 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001991 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1992
1993 sp<IDrm> drm = GetDrm(env, jdrm);
1994
1995 if (!CheckSession(env, drm, jsessionId)) {
1996 return NULL;
1997 }
1998
1999 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
2000 jniThrowException(env, "java/lang/IllegalArgumentException",
2001 "required argument is null");
2002 return NULL;
2003 }
2004
2005 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2006 String8 algorithm = JStringToString8(env, jalgorithm);
2007 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
2008 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
2009 Vector<uint8_t> signature;
2010
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302011 DrmStatus err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
Jeff Tinkere4095a82014-03-04 13:17:11 -08002012
Robert Shih60dab872021-02-13 11:24:59 -08002013 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08002014 return NULL;
2015 }
2016
2017 return VectorToJByteArray(env, signature);
2018}
2019
Robert Shih205f7a92021-01-19 21:12:10 -08002020static jboolean android_media_MediaDrm_requiresSecureDecoder(
2021 JNIEnv *env, jobject thiz, jstring jmimeType,
2022 jint jSecurityLevel) {
2023 sp<IDrm> drm = GetDrm(env, thiz);
2024 if (!CheckDrm(env, drm)) {
2025 return JNI_FALSE;
2026 }
2027
2028 String8 mimeType;
2029 if (jmimeType != NULL) {
2030 mimeType = JStringToString8(env, jmimeType);
2031 }
2032
2033 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
2034 if (securityLevel == DrmPlugin::kSecurityLevelUnknown) {
2035 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
2036 return JNI_FALSE;
2037 }
2038
Robert Shih5bb242a2021-04-28 10:04:51 -07002039 bool required = false;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302040 DrmStatus err = OK;
Robert Shih205f7a92021-01-19 21:12:10 -08002041 if (securityLevel == DrmPlugin::kSecurityLevelMax) {
Robert Shih5bb242a2021-04-28 10:04:51 -07002042 err = drm->requiresSecureDecoder(mimeType.c_str(), &required);
2043 } else {
2044 err = drm->requiresSecureDecoder(mimeType.c_str(), securityLevel, &required);
Robert Shih205f7a92021-01-19 21:12:10 -08002045 }
Robert Shih5bb242a2021-04-28 10:04:51 -07002046 if (throwExceptionAsNecessary(env, drm, err, "Failed to query secure decoder requirement")) {
2047 return false;
2048 }
2049 return required;
Robert Shih205f7a92021-01-19 21:12:10 -08002050}
Jeff Tinkere4095a82014-03-04 13:17:11 -08002051
Robert Shih02937122021-01-20 00:05:20 -08002052static void android_media_MediaDrm_setPlaybackId(
2053 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
2054 jstring jplaybackId) {
2055 sp<IDrm> drm = GetDrm(env, thiz);
2056 if (!CheckSession(env, drm, jsessionId)) {
2057 return;
2058 }
2059
2060 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2061
2062 String8 playbackId;
2063 if (jplaybackId != NULL) {
2064 playbackId = JStringToString8(env, jplaybackId);
2065 }
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302066 DrmStatus err = drm->setPlaybackId(sessionId, playbackId.c_str());
Robert Shih60dab872021-02-13 11:24:59 -08002067 throwExceptionAsNecessary(env, drm, err, "Failed to set playbackId");
Robert Shih02937122021-01-20 00:05:20 -08002068}
2069
Robert Shih696989f2021-02-12 23:25:16 -08002070static jobject android_media_MediaDrm_getLogMessages(
2071 JNIEnv *env, jobject thiz) {
2072 sp<IDrm> drm = GetDrm(env, thiz);
2073 if (!CheckDrm(env, drm)) {
2074 return NULL;
2075 }
2076
2077 Vector<drm::V1_4::LogMessage> logs;
Sohail Nagarajc7e8e372022-12-14 11:25:58 +05302078 DrmStatus err = drm->getLogMessages(logs);
Robert Shih696989f2021-02-12 23:25:16 -08002079 ALOGI("drm->getLogMessages %zu logs", logs.size());
Robert Shih60dab872021-02-13 11:24:59 -08002080 if (throwExceptionAsNecessary(env, drm, err, "Failed to get log messages")) {
Robert Shih696989f2021-02-12 23:25:16 -08002081 return NULL;
2082 }
2083 return hidlLogMessagesToJavaList(env, logs);
2084}
2085
Daniel Micay76f6a862015-09-19 17:31:01 -04002086static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002087 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
2088
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002089 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
2090
Edwin Wong4d1d84e2017-01-04 09:37:49 -08002091 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002092 (void *)android_media_MediaDrm_native_setup },
2093
Robert Shihd2e8b432019-11-21 20:27:56 -08002094 { "getSupportedCryptoSchemesNative", "()[B",
2095 (void *)android_media_MediaDrm_getSupportedCryptoSchemesNative },
2096
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08002097 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002098 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
2099
Robert Shih02937122021-01-20 00:05:20 -08002100 { "openSessionNative", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002101 (void *)android_media_MediaDrm_openSession },
2102
Robert Shih02937122021-01-20 00:05:20 -08002103 { "closeSessionNative", "([B)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002104 (void *)android_media_MediaDrm_closeSession },
2105
Robert Shih890eb572021-01-19 08:16:39 -08002106 { "getKeyRequestNative", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002107 "Landroid/media/MediaDrm$KeyRequest;",
2108 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002109
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002110 { "provideKeyResponse", "([B[B)[B",
2111 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002112
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002113 { "removeKeys", "([B)V",
2114 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002115
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002116 { "restoreKeys", "([B[B)V",
2117 (void *)android_media_MediaDrm_restoreKeys },
2118
2119 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
2120 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002121
Jeff Tinkere4095a82014-03-04 13:17:11 -08002122 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
2123 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002124
Jeff Tinkere4095a82014-03-04 13:17:11 -08002125 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
2126 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002127
2128 { "getSecureStops", "()Ljava/util/List;",
2129 (void *)android_media_MediaDrm_getSecureStops },
2130
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002131 { "getSecureStopIds", "()Ljava/util/List;",
2132 (void *)android_media_MediaDrm_getSecureStopIds },
2133
Jeff Tinker1b51c722014-10-31 00:54:26 -07002134 { "getSecureStop", "([B)[B",
2135 (void *)android_media_MediaDrm_getSecureStop },
2136
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002137 { "releaseSecureStops", "([B)V",
2138 (void *)android_media_MediaDrm_releaseSecureStops },
2139
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002140 { "removeSecureStop", "([B)V",
2141 (void *)android_media_MediaDrm_removeSecureStop },
2142
2143 { "removeAllSecureStops", "()V",
2144 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07002145
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002146 { "getConnectedHdcpLevel", "()I",
2147 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
2148
2149 { "getMaxHdcpLevel", "()I",
2150 (void *)android_media_MediaDrm_getMaxHdcpLevel },
2151
2152 { "getOpenSessionCount", "()I",
2153 (void *)android_media_MediaDrm_getOpenSessionCount },
2154
2155 { "getMaxSessionCount", "()I",
2156 (void *)android_media_MediaDrm_getMaxSessionCount },
2157
2158 { "getSecurityLevel", "([B)I",
2159 (void *)android_media_MediaDrm_getSecurityLevel },
2160
Jeff Tinker55d26242018-10-10 16:10:43 -07002161 { "removeOfflineLicense", "([B)V",
2162 (void *)android_media_MediaDrm_removeOfflineLicense },
2163
2164 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
2165 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
2166
2167 { "getOfflineLicenseState", "([B)I",
2168 (void *)android_media_MediaDrm_getOfflineLicenseState },
2169
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002170 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2171 (void *)android_media_MediaDrm_getPropertyString },
2172
2173 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2174 (void *)android_media_MediaDrm_getPropertyByteArray },
2175
2176 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2177 (void *)android_media_MediaDrm_setPropertyString },
2178
2179 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2180 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002181
2182 { "setCipherAlgorithmNative",
2183 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2184 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2185
2186 { "setMacAlgorithmNative",
2187 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2188 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2189
2190 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2191 (void *)android_media_MediaDrm_encryptNative },
2192
2193 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2194 (void *)android_media_MediaDrm_decryptNative },
2195
2196 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2197 (void *)android_media_MediaDrm_signNative },
2198
2199 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2200 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002201
2202 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2203 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002204
2205 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2206 (void *)android_media_MediaDrm_native_getMetrics },
Robert Shih205f7a92021-01-19 21:12:10 -08002207
2208 { "requiresSecureDecoder", "(Ljava/lang/String;I)Z",
2209 (void *)android_media_MediaDrm_requiresSecureDecoder },
Robert Shih02937122021-01-20 00:05:20 -08002210
2211 { "setPlaybackId", "([BLjava/lang/String;)V",
2212 (void *)android_media_MediaDrm_setPlaybackId },
Robert Shih696989f2021-02-12 23:25:16 -08002213
2214 { "getLogMessages", "()Ljava/util/List;",
2215 (void *)android_media_MediaDrm_getLogMessages },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002216};
2217
2218int register_android_media_Drm(JNIEnv *env) {
2219 return AndroidRuntime::registerNativeMethods(env,
2220 "android/media/MediaDrm", gMethods, NELEM(gMethods));
Kyle Zhangb61d8022023-10-04 00:14:59 +00002221}