blob: 2f4dd8fad8bbf57fcce860d8567e285badd3e43e [file] [log] [blame]
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001/*
2 * Copyright 2013, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaDrm-JNI"
19#include <utils/Log.h>
20
21#include "android_media_MediaDrm.h"
Adam Stonec06e10e2017-12-19 12:54:33 -080022#include "android_media_MediaMetricsJNI.h"
Adam Stone94395c92018-01-30 12:07:00 -080023#include "android_os_Parcel.h"
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080024#include "android_runtime/AndroidRuntime.h"
Ruben Brunk87eac992013-09-09 17:44:59 -070025#include "android_runtime/Log.h"
Jeff Tinker54cfbd62013-04-02 13:14:59 -070026#include "android_os_Parcel.h"
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080027#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070028#include <nativehelper/JNIHelp.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080029
Robert Shihd2e8b432019-11-21 20:27:56 -080030#include <android/hardware/drm/1.3/IDrmFactory.h>
Jeff Tinker54cfbd62013-04-02 13:14:59 -070031#include <binder/Parcel.h>
Adam Stone94395c92018-01-30 12:07:00 -080032#include <binder/PersistableBundle.h>
Jeff Tinkerdc614f82016-02-12 08:58:32 -080033#include <cutils/properties.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080034#include <media/stagefright/foundation/ADebug.h>
Jeff Tinkerf7568b52013-04-17 14:24:40 -070035#include <media/stagefright/MediaErrors.h>
Robert Shihba6777e2019-11-12 13:04:59 -080036#include <mediadrm/DrmMetricsConsumer.h>
Robert Shih218b9532019-08-15 14:48:11 -070037#include <mediadrm/DrmUtils.h>
Robert Shihba6777e2019-11-12 13:04:59 -080038#include <mediadrm/IDrmMetricsConsumer.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080039#include <mediadrm/IDrm.h>
Robert Shih696989f2021-02-12 23:25:16 -080040#include <utils/Vector.h>
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080041
Adam Stone94395c92018-01-30 12:07:00 -080042using ::android::os::PersistableBundle;
Robert Shihd2e8b432019-11-21 20:27:56 -080043namespace drm = ::android::hardware::drm;
Adam Stone94395c92018-01-30 12:07:00 -080044
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080045namespace android {
46
47#define FIND_CLASS(var, className) \
48 var = env->FindClass(className); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070049 LOG_FATAL_IF(! (var), "Unable to find class %s", className);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080050
51#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
52 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070053 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080054
55#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
56 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070057 LOG_FATAL_IF(! (var), "Unable to find method %s", fieldName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080058
Jeff Tinker54cfbd62013-04-02 13:14:59 -070059#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
60 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070061 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070062
63#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
64 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070065 LOG_FATAL_IF(! (var), "Unable to find static method %s", fieldName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -070066
Chih-Hung Hsiehacb1de82018-07-26 15:40:45 -070067#define GET_STATIC_OBJECT_FIELD(var, clazz, fieldId) \
68 var = env->GetStaticObjectField(clazz, fieldId); \
69 LOG_FATAL_IF(! (var), "Unable to find static object field %p", fieldId);
Adam Stone94395c92018-01-30 12:07:00 -080070
Jeff Tinker54cfbd62013-04-02 13:14:59 -070071
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080072struct RequestFields {
73 jfieldID data;
74 jfieldID defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -070075 jfieldID requestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -080076};
77
78struct ArrayListFields {
79 jmethodID init;
80 jmethodID add;
81};
82
83struct HashmapFields {
84 jmethodID init;
85 jmethodID get;
86 jmethodID put;
87 jmethodID entrySet;
88};
89
90struct SetFields {
91 jmethodID iterator;
92};
93
94struct IteratorFields {
95 jmethodID next;
96 jmethodID hasNext;
97};
98
99struct EntryFields {
100 jmethodID getKey;
101 jmethodID getValue;
102};
103
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700104struct EventTypes {
Jeff Tinker17b89222013-05-21 12:35:06 -0700105 jint kEventProvisionRequired;
106 jint kEventKeyRequired;
107 jint kEventKeyExpired;
108 jint kEventVendorDefined;
Ronghua Wua6d72092015-03-04 11:16:02 -0800109 jint kEventSessionReclaimed;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700110} gEventTypes;
111
Jeff Tinker74797f82015-03-31 15:44:34 -0700112struct EventWhat {
113 jint kWhatDrmEvent;
114 jint kWhatExpirationUpdate;
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700115 jint kWhatKeyStatusChange;
Jeff Tinker20594d82018-12-12 08:31:22 -0800116 jint kWhatSessionLostState;
Jeff Tinker74797f82015-03-31 15:44:34 -0700117} gEventWhat;
118
Jeff Tinker17b89222013-05-21 12:35:06 -0700119struct KeyTypes {
120 jint kKeyTypeStreaming;
121 jint kKeyTypeOffline;
122 jint kKeyTypeRelease;
123} gKeyTypes;
124
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700125struct KeyRequestTypes {
126 jint kKeyRequestTypeInitial;
127 jint kKeyRequestTypeRenewal;
128 jint kKeyRequestTypeRelease;
Rahul Frias8f761ba2018-01-22 23:43:54 -0800129 jint kKeyRequestTypeNone;
130 jint kKeyRequestTypeUpdate;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700131} gKeyRequestTypes;
132
Jeff Tinkere4095a82014-03-04 13:17:11 -0800133struct CertificateTypes {
134 jint kCertificateTypeNone;
135 jint kCertificateTypeX509;
136} gCertificateTypes;
137
138struct CertificateFields {
139 jfieldID wrappedPrivateKey;
140 jfieldID certificateData;
141};
142
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700143struct StateExceptionFields {
144 jmethodID init;
145 jclass classId;
146};
147
Jeff Tinker20594d82018-12-12 08:31:22 -0800148struct SessionExceptionFields {
149 jmethodID init;
150 jclass classId;
151 jfieldID errorCode;
152};
153
154struct SessionExceptionErrorCodes {
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800155 jint kErrorUnknown;
Jeff Tinker20594d82018-12-12 08:31:22 -0800156 jint kResourceContention;
157} gSessionExceptionErrorCodes;
158
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800159struct HDCPLevels {
160 jint kHdcpLevelUnknown;
161 jint kHdcpNone;
162 jint kHdcpV1;
163 jint kHdcpV2;
164 jint kHdcpV2_1;
165 jint kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800166 jint kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800167 jint kHdcpNoOutput;
168} gHdcpLevels;
169
170struct SecurityLevels {
171 jint kSecurityLevelUnknown;
Jeff Tinker2bca5252018-02-11 18:59:14 +0000172 jint kSecurityLevelMax;
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800173 jint kSecurityLevelSwSecureCrypto;
174 jint kSecurityLevelSwSecureDecode;
175 jint kSecurityLevelHwSecureCrypto;
176 jint kSecurityLevelHwSecureDecode;
177 jint kSecurityLevelHwSecureAll;
178} gSecurityLevels;
179
Jeff Tinker55d26242018-10-10 16:10:43 -0700180struct OfflineLicenseState {
181 jint kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800182 jint kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -0700183 jint kOfflineLicenseStateUnknown;
184} gOfflineLicenseStates;
185
Robert Shih9d4e2d42019-11-08 13:51:49 -0800186struct KeyStatusFields {
187 jmethodID init;
188 jclass classId;
189};
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800190
Robert Shih696989f2021-02-12 23:25:16 -0800191struct LogMessageFields {
192 jmethodID init;
193 jclass classId;
194};
195
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800196struct fields_t {
197 jfieldID context;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700198 jmethodID post_event;
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700199 RequestFields keyRequest;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800200 RequestFields provisionRequest;
201 ArrayListFields arraylist;
202 HashmapFields hashmap;
203 SetFields set;
204 IteratorFields iterator;
205 EntryFields entry;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800206 CertificateFields certificate;
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700207 StateExceptionFields stateException;
Jeff Tinker20594d82018-12-12 08:31:22 -0800208 SessionExceptionFields sessionException;
Jeff Tinkere4095a82014-03-04 13:17:11 -0800209 jclass certificateClassId;
210 jclass hashmapClassId;
211 jclass arraylistClassId;
212 jclass stringClassId;
Adam Stone94395c92018-01-30 12:07:00 -0800213 jobject bundleCreator;
214 jmethodID createFromParcelId;
215 jclass parcelCreatorClassId;
Robert Shih9d4e2d42019-11-08 13:51:49 -0800216 KeyStatusFields keyStatus;
Robert Shih696989f2021-02-12 23:25:16 -0800217 LogMessageFields logMessage;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800218};
219
220static fields_t gFields;
221
Adam Stone94395c92018-01-30 12:07:00 -0800222namespace {
223
Robert Shih9d4e2d42019-11-08 13:51:49 -0800224jbyteArray hidlVectorToJByteArray(const hardware::hidl_vec<uint8_t> &vector) {
225 JNIEnv *env = AndroidRuntime::getJNIEnv();
226 size_t length = vector.size();
227 jbyteArray result = env->NewByteArray(length);
228 if (result != NULL) {
229 env->SetByteArrayRegion(result, 0, length, reinterpret_cast<const jbyte *>(vector.data()));
230 }
231 return result;
232}
233
Robert Shih696989f2021-02-12 23:25:16 -0800234jobject hidlLogMessagesToJavaList(JNIEnv *env, const Vector<drm::V1_4::LogMessage> &logs) {
235 jclass clazz = gFields.arraylistClassId;
236 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
237 clazz = gFields.logMessage.classId;
238 for (auto log: logs) {
239 jobject jLog = env->NewObject(clazz, gFields.logMessage.init,
240 static_cast<jlong>(log.timeMs),
241 static_cast<jint>(log.priority),
242 env->NewStringUTF(log.message.c_str()));
243 env->CallBooleanMethod(arrayList, gFields.arraylist.add, jLog);
244 }
245 return arrayList;
246}
Adam Stone94395c92018-01-30 12:07:00 -0800247} // namespace anonymous
248
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700249// ----------------------------------------------------------------------------
250// ref-counted object for callbacks
251class JNIDrmListener: public DrmListener
252{
253public:
254 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
255 ~JNIDrmListener();
Robert Shih9d4e2d42019-11-08 13:51:49 -0800256 virtual void notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *arg = NULL);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700257private:
258 JNIDrmListener();
259 jclass mClass; // Reference to MediaDrm class
260 jobject mObject; // Weak ref to MediaDrm Java object to call on
261};
262
263JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
264{
265 // Hold onto the MediaDrm class for use in calling the static method
266 // that posts events to the application thread.
267 jclass clazz = env->GetObjectClass(thiz);
268 if (clazz == NULL) {
269 ALOGE("Can't find android/media/MediaDrm");
Jeff Tinkereada5372013-05-21 12:48:14 -0700270 jniThrowException(env, "java/lang/Exception",
271 "Can't find android/media/MediaDrm");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700272 return;
273 }
274 mClass = (jclass)env->NewGlobalRef(clazz);
275
276 // We use a weak reference so the MediaDrm object can be garbage collected.
277 // The reference is only used as a proxy for callbacks.
278 mObject = env->NewGlobalRef(weak_thiz);
279}
280
281JNIDrmListener::~JNIDrmListener()
282{
283 // remove global references
284 JNIEnv *env = AndroidRuntime::getJNIEnv();
285 env->DeleteGlobalRef(mObject);
286 env->DeleteGlobalRef(mClass);
287}
288
289void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
Robert Shih9d4e2d42019-11-08 13:51:49 -0800290 const ListenerArgs *args)
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700291{
Jeff Tinker74797f82015-03-31 15:44:34 -0700292 jint jwhat;
293 jint jeventType = 0;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700294
295 // translate DrmPlugin event types into their java equivalents
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700296 switch (eventType) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700297 case DrmPlugin::kDrmPluginEventProvisionRequired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700298 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700299 jeventType = gEventTypes.kEventProvisionRequired;
300 break;
301 case DrmPlugin::kDrmPluginEventKeyNeeded:
Jeff Tinker74797f82015-03-31 15:44:34 -0700302 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700303 jeventType = gEventTypes.kEventKeyRequired;
304 break;
305 case DrmPlugin::kDrmPluginEventKeyExpired:
Jeff Tinker74797f82015-03-31 15:44:34 -0700306 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700307 jeventType = gEventTypes.kEventKeyExpired;
308 break;
309 case DrmPlugin::kDrmPluginEventVendorDefined:
Jeff Tinker74797f82015-03-31 15:44:34 -0700310 jwhat = gEventWhat.kWhatDrmEvent;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700311 jeventType = gEventTypes.kEventVendorDefined;
312 break;
Ronghua Wua6d72092015-03-04 11:16:02 -0800313 case DrmPlugin::kDrmPluginEventSessionReclaimed:
Jeff Tinker74797f82015-03-31 15:44:34 -0700314 jwhat = gEventWhat.kWhatDrmEvent;
Ronghua Wua6d72092015-03-04 11:16:02 -0800315 jeventType = gEventTypes.kEventSessionReclaimed;
316 break;
Jeff Tinker74797f82015-03-31 15:44:34 -0700317 case DrmPlugin::kDrmPluginEventExpirationUpdate:
318 jwhat = gEventWhat.kWhatExpirationUpdate;
319 break;
320 case DrmPlugin::kDrmPluginEventKeysChange:
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700321 jwhat = gEventWhat.kWhatKeyStatusChange;
Jeff Tinker74797f82015-03-31 15:44:34 -0700322 break;
Jeff Tinker20594d82018-12-12 08:31:22 -0800323 case DrmPlugin::kDrmPluginEventSessionLostState:
324 jwhat = gEventWhat.kWhatSessionLostState;
325 break;
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700326 default:
327 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
328 return;
329 }
330
331 JNIEnv *env = AndroidRuntime::getJNIEnv();
Robert Shih9d4e2d42019-11-08 13:51:49 -0800332 if (args) {
333 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
334 jwhat, jeventType, extra,
335 args->jSessionId, args->jData, args->jExpirationTime,
336 args->jKeyStatusList, args->jHasNewUsableKey);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700337 }
338
339 if (env->ExceptionCheck()) {
340 ALOGW("An exception occurred while notifying an event.");
341 LOGW_EX(env);
342 env->ExceptionClear();
343 }
344}
345
Robert Shih620f4a62021-02-15 03:28:42 -0800346jint MediaErrorToJavaError(status_t err) {
347#define STATUS_CASE(status) \
348 case status: \
349 return J##status
350
351 switch (err) {
352 STATUS_CASE(ERROR_DRM_UNKNOWN);
353 STATUS_CASE(ERROR_DRM_NO_LICENSE);
354 STATUS_CASE(ERROR_DRM_LICENSE_EXPIRED);
355 STATUS_CASE(ERROR_DRM_RESOURCE_BUSY);
356 STATUS_CASE(ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION);
357 STATUS_CASE(ERROR_DRM_SESSION_NOT_OPENED);
358 STATUS_CASE(ERROR_DRM_CANNOT_HANDLE);
359 STATUS_CASE(ERROR_DRM_INSUFFICIENT_SECURITY);
360 STATUS_CASE(ERROR_DRM_FRAME_TOO_LARGE);
361 STATUS_CASE(ERROR_DRM_SESSION_LOST_STATE);
362 STATUS_CASE(ERROR_DRM_CERTIFICATE_MALFORMED);
363 STATUS_CASE(ERROR_DRM_CERTIFICATE_MISSING);
364 STATUS_CASE(ERROR_DRM_CRYPTO_LIBRARY);
365 STATUS_CASE(ERROR_DRM_GENERIC_OEM);
366 STATUS_CASE(ERROR_DRM_GENERIC_PLUGIN);
367 STATUS_CASE(ERROR_DRM_INIT_DATA);
368 STATUS_CASE(ERROR_DRM_KEY_NOT_LOADED);
369 STATUS_CASE(ERROR_DRM_LICENSE_PARSE);
370 STATUS_CASE(ERROR_DRM_LICENSE_POLICY);
371 STATUS_CASE(ERROR_DRM_LICENSE_RELEASE);
372 STATUS_CASE(ERROR_DRM_LICENSE_REQUEST_REJECTED);
373 STATUS_CASE(ERROR_DRM_LICENSE_RESTORE);
374 STATUS_CASE(ERROR_DRM_LICENSE_STATE);
375 STATUS_CASE(ERROR_DRM_MEDIA_FRAMEWORK);
376 STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE);
377 STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG);
378 STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE);
Robert Shiha37ae8e2021-03-03 03:35:12 -0800379 STATUS_CASE(ERROR_DRM_PROVISIONING_REQUEST_REJECTED);
Robert Shih620f4a62021-02-15 03:28:42 -0800380 STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY);
381 STATUS_CASE(ERROR_DRM_RESOURCE_CONTENTION);
382 STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE);
383 STATUS_CASE(ERROR_DRM_STORAGE_READ);
384 STATUS_CASE(ERROR_DRM_STORAGE_WRITE);
385 STATUS_CASE(ERROR_DRM_ZERO_SUBSAMPLES);
386#undef STATUS_CASE
387 }
388 return static_cast<jint>(err);
389}
390
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700391static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
392 ALOGE("Illegal state exception: %s (%d)", msg, err);
393
Robert Shih620f4a62021-02-15 03:28:42 -0800394 jint jerr = MediaErrorToJavaError(err);
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700395 jobject exception = env->NewObject(gFields.stateException.classId,
Robert Shih620f4a62021-02-15 03:28:42 -0800396 gFields.stateException.init, static_cast<int>(jerr),
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700397 env->NewStringUTF(msg));
398 env->Throw(static_cast<jthrowable>(exception));
399}
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700400
Jeff Tinker20594d82018-12-12 08:31:22 -0800401static void throwSessionException(JNIEnv *env, const char *msg, status_t err) {
402 ALOGE("Session exception: %s (%d)", msg, err);
403
404 jint jErrorCode = 0;
405 switch(err) {
406 case ERROR_DRM_RESOURCE_CONTENTION:
407 jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
408 break;
409 default:
410 break;
411 }
412
413 jobject exception = env->NewObject(gFields.sessionException.classId,
414 gFields.sessionException.init, static_cast<int>(err),
415 env->NewStringUTF(msg));
416
417 env->SetIntField(exception, gFields.sessionException.errorCode, jErrorCode);
418 env->Throw(static_cast<jthrowable>(exception));
419}
420
421static bool isSessionException(status_t err) {
422 return err == ERROR_DRM_RESOURCE_CONTENTION;
423}
424
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800425static bool throwExceptionAsNecessary(
Robert Shih60dab872021-02-13 11:24:59 -0800426 JNIEnv *env, const sp<IDrm> &drm, status_t err, const char *msg = NULL) {
427 std::string msgStr;
Robert Shih13eb27b2021-02-20 00:08:16 -0800428 if (drm != NULL && err != OK) {
Robert Shih60dab872021-02-13 11:24:59 -0800429 msgStr = DrmUtils::GetExceptionMessage(err, msg, drm);
430 msg = msgStr.c_str();
Jeff Tinkerf7568b52013-04-17 14:24:40 -0700431 }
432
Jeff Tinkereb13c762017-11-01 15:29:38 -0700433 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800434 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
435 return true;
Jeff Tinker5de2e902019-01-25 23:09:36 -0800436 } else if (err == ERROR_UNSUPPORTED) {
437 jniThrowException(env, "java/lang/UnsupportedOperationException", msg);
438 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700439 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
440 jniThrowException(env, "android/media/NotProvisionedException", msg);
441 return true;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700442 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
443 jniThrowException(env, "android/media/ResourceBusyException", msg);
444 return true;
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700445 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
446 jniThrowException(env, "android/media/DeniedByServerException", msg);
447 return true;
Jeff Tinker314b7f32015-06-15 17:45:43 -0700448 } else if (err == DEAD_OBJECT) {
Robert Shih250f6a72021-02-26 08:20:31 -0800449 jniThrowException(env, "android/media/MediaDrmResetException", msg);
Jeff Tinker314b7f32015-06-15 17:45:43 -0700450 return true;
Jeff Tinker20594d82018-12-12 08:31:22 -0800451 } else if (isSessionException(err)) {
452 throwSessionException(env, msg, err);
453 return true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800454 } else if (err != OK) {
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700455 throwStateException(env, msg, err);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800456 return true;
457 }
458 return false;
459}
460
461static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000462 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800463 return jdrm ? jdrm->getDrm() : NULL;
464}
465
466JDrm::JDrm(
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800467 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
468 const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800469 mObject = env->NewWeakGlobalRef(thiz);
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800470 mDrm = MakeDrm(uuid, appPackageName);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700471 if (mDrm != NULL) {
472 mDrm->setListener(this);
473 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800474}
475
476JDrm::~JDrm() {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800477 JNIEnv *env = AndroidRuntime::getJNIEnv();
478
479 env->DeleteWeakGlobalRef(mObject);
480 mObject = NULL;
481}
482
483// static
484sp<IDrm> JDrm::MakeDrm() {
Robert Shih218b9532019-08-15 14:48:11 -0700485 return DrmUtils::MakeDrm();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800486}
487
488// static
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800489sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800490 sp<IDrm> drm = MakeDrm();
491
492 if (drm == NULL) {
493 return NULL;
494 }
495
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800496 status_t err = drm->createPlugin(uuid, appPackageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800497
498 if (err != OK) {
499 return NULL;
500 }
501
502 return drm;
503}
504
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700505status_t JDrm::setListener(const sp<DrmListener>& listener) {
506 Mutex::Autolock lock(mLock);
507 mListener = listener;
508 return OK;
509}
510
Robert Shih9d4e2d42019-11-08 13:51:49 -0800511void JDrm::notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *args) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700512 sp<DrmListener> listener;
513 mLock.lock();
514 listener = mListener;
515 mLock.unlock();
516
517 if (listener != NULL) {
518 Mutex::Autolock lock(mNotifyLock);
Robert Shih9d4e2d42019-11-08 13:51:49 -0800519 listener->notify(eventType, extra, args);
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700520 }
521}
522
Robert Shih3a523902019-08-15 14:48:11 -0700523void JDrm::sendEvent(
524 DrmPlugin::EventType eventType,
525 const hardware::hidl_vec<uint8_t> &sessionId,
526 const hardware::hidl_vec<uint8_t> &data) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800527 ListenerArgs args{
528 .jSessionId = hidlVectorToJByteArray(sessionId),
529 .jData = hidlVectorToJByteArray(data),
530 };
531 notify(eventType, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700532}
533
534void JDrm::sendExpirationUpdate(
535 const hardware::hidl_vec<uint8_t> &sessionId,
536 int64_t expiryTimeInMS) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800537 ListenerArgs args{
538 .jSessionId = hidlVectorToJByteArray(sessionId),
539 .jExpirationTime = expiryTimeInMS,
540 };
541 notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700542}
543
544void JDrm::sendKeysChange(
545 const hardware::hidl_vec<uint8_t> &sessionId,
546 const std::vector<DrmKeyStatus> &keyStatusList,
547 bool hasNewUsableKey) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800548 JNIEnv *env = AndroidRuntime::getJNIEnv();
549 jclass clazz = gFields.arraylistClassId;
550 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
551 clazz = gFields.keyStatus.classId;
552 for (const auto &keyStatus : keyStatusList) {
553 jbyteArray jKeyId(hidlVectorToJByteArray(keyStatus.keyId));
554 jint jStatusCode(keyStatus.type);
555 jobject jKeyStatus = env->NewObject(clazz, gFields.keyStatus.init, jKeyId, jStatusCode);
556 env->CallBooleanMethod(arrayList, gFields.arraylist.add, jKeyStatus);
557 }
558 ListenerArgs args{
559 .jSessionId = hidlVectorToJByteArray(sessionId),
560 .jKeyStatusList = arrayList,
561 .jHasNewUsableKey = hasNewUsableKey,
562 };
563 notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700564}
565
566void JDrm::sendSessionLostState(
567 const hardware::hidl_vec<uint8_t> &sessionId) {
Robert Shih9d4e2d42019-11-08 13:51:49 -0800568 ListenerArgs args{
569 .jSessionId = hidlVectorToJByteArray(sessionId),
570 };
571 notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &args);
Robert Shih3a523902019-08-15 14:48:11 -0700572}
573
Jeff Tinker600071c2014-04-11 16:11:15 -0700574void JDrm::disconnect() {
575 if (mDrm != NULL) {
576 mDrm->destroyPlugin();
577 mDrm.clear();
578 }
579}
580
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700581
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800582// static
Jeff Tinker5de2e902019-01-25 23:09:36 -0800583status_t JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
584 DrmPlugin::SecurityLevel securityLevel, bool *isSupported) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800585 sp<IDrm> drm = MakeDrm();
586
587 if (drm == NULL) {
Jeff Tinker5de2e902019-01-25 23:09:36 -0800588 return BAD_VALUE;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800589 }
590
Jeff Tinker5de2e902019-01-25 23:09:36 -0800591 return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel, isSupported);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800592}
593
594status_t JDrm::initCheck() const {
595 return mDrm == NULL ? NO_INIT : OK;
596}
597
598// JNI conversion utilities
599static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
600 Vector<uint8_t> vector;
601 size_t length = env->GetArrayLength(byteArray);
602 vector.insertAt((size_t)0, length);
603 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
604 return vector;
605}
606
607static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
608 size_t length = vector.size();
609 jbyteArray result = env->NewByteArray(length);
610 if (result != NULL) {
611 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
612 }
613 return result;
614}
615
616static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800617 String8 result;
618
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700619 const char *s = env->GetStringUTFChars(jstr, NULL);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800620 if (s) {
621 result = s;
622 env->ReleaseStringUTFChars(jstr, s);
623 }
624 return result;
625}
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700626
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800627/*
628 import java.util.HashMap;
629 import java.util.Set;
630 import java.Map.Entry;
631 import jav.util.Iterator;
632
633 HashMap<k, v> hm;
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800634 Set<Entry<k, v>> s = hm.entrySet();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800635 Iterator i = s.iterator();
636 Entry e = s.next();
637*/
638
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200639static KeyedVector<String8, String8> HashMapToKeyedVector(
640 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800641 jclass clazz = gFields.stringClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800642 KeyedVector<String8, String8> keyedVector;
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200643 *pIsOK = true;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800644
645 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
646 if (entrySet) {
647 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
648 if (iterator) {
649 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
650 while (hasNext) {
651 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
652 if (entry) {
653 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200654 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700655 jniThrowException(env, "java/lang/IllegalArgumentException",
656 "HashMap key is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200657 env->DeleteLocalRef(entry);
658 *pIsOK = false;
659 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800660 }
661 jstring jkey = static_cast<jstring>(obj);
662
663 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200664 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700665 jniThrowException(env, "java/lang/IllegalArgumentException",
666 "HashMap value is not a String");
Daniel Broms35d6a4f2014-09-29 15:32:03 +0200667 env->DeleteLocalRef(entry);
668 *pIsOK = false;
669 break;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800670 }
671 jstring jvalue = static_cast<jstring>(obj);
672
673 String8 key = JStringToString8(env, jkey);
674 String8 value = JStringToString8(env, jvalue);
675 keyedVector.add(key, value);
676
677 env->DeleteLocalRef(jkey);
678 env->DeleteLocalRef(jvalue);
679 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
680 }
681 env->DeleteLocalRef(entry);
682 }
683 env->DeleteLocalRef(iterator);
684 }
685 env->DeleteLocalRef(entrySet);
686 }
687 return keyedVector;
688}
689
690static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800691 jclass clazz = gFields.hashmapClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800692 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
693 for (size_t i = 0; i < map.size(); ++i) {
694 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
695 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
696 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
697 env->DeleteLocalRef(jkey);
698 env->DeleteLocalRef(jvalue);
699 }
700 return hashMap;
701}
702
703static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800704 List<Vector<uint8_t>> list) {
Jeff Tinkere4095a82014-03-04 13:17:11 -0800705 jclass clazz = gFields.arraylistClassId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800706 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
Jeff Tinkerb78ee402018-11-05 15:18:53 -0800707 List<Vector<uint8_t>>::iterator iter = list.begin();
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800708 while (iter != list.end()) {
709 jbyteArray byteArray = VectorToJByteArray(env, *iter);
710 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
711 env->DeleteLocalRef(byteArray);
712 iter++;
713 }
714
715 return arrayList;
716}
717
718} // namespace android
719
720using namespace android;
721
722static sp<JDrm> setDrm(
723 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
Ashok Bhat656fd042013-11-28 10:56:06 +0000724 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800725 if (drm != NULL) {
726 drm->incStrong(thiz);
727 }
728 if (old != NULL) {
729 old->decStrong(thiz);
730 }
Narayan Kamathf11dd632013-12-18 16:53:54 +0000731 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800732
733 return old;
734}
735
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800736static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800737 if (drm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700738 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800739 return false;
740 }
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800741 return true;
742}
743
744static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
745{
746 if (!CheckDrm(env, drm)) {
747 return false;
748 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800749
750 if (jsessionId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700751 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800752 return false;
753 }
754 return true;
755}
756
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800757static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700758 sp<JDrm> drm = setDrm(env, thiz, NULL);
759 if (drm != NULL) {
760 drm->setListener(NULL);
Jeff Tinker600071c2014-04-11 16:11:15 -0700761 drm->disconnect();
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700762 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800763}
764
765static void android_media_MediaDrm_native_init(JNIEnv *env) {
766 jclass clazz;
767 FIND_CLASS(clazz, "android/media/MediaDrm");
Ashok Bhat656fd042013-11-28 10:56:06 +0000768 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700769 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
Robert Shih9d4e2d42019-11-08 13:51:49 -0800770 "(Ljava/lang/Object;III[B[BJLjava/util/List;Z)V");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700771
772 jfieldID field;
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700773 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700774 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700775 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700776 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700777 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700778 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700779 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700780 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
Ronghua Wua6d72092015-03-04 11:16:02 -0800781 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
782 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800783
Jeff Tinker74797f82015-03-31 15:44:34 -0700784 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
785 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
786 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
787 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700788 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
789 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800790 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
791 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
Jeff Tinker74797f82015-03-31 15:44:34 -0700792
Jeff Tinker17b89222013-05-21 12:35:06 -0700793 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
794 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
795 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
796 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
797 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
798 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
799
Jeff Tinkere4095a82014-03-04 13:17:11 -0800800 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
801 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
802 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
803 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
804
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800805 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
806 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
807 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
808 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
809 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
810 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
811 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
812 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
813 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
814 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
815 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
816 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
Jeff Tinkerc71c0182019-01-14 10:26:06 -0800817 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
818 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800819 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
820 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
821
822 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
823 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700824 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800825 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700826 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800827 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700828 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800829 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700830 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800831 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
Jeff Tinkercbbab832018-03-28 17:16:50 -0700832 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
Jeff Tinker3eb07f42017-12-08 17:34:53 -0800833 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
834
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800835 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_USABLE", "I");
Jeff Tinker55d26242018-10-10 16:10:43 -0700836 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
Jeff Tinker8de43ee2018-12-11 01:00:09 -0800837 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_RELEASED", "I");
838 gOfflineLicenseStates.kOfflineLicenseStateReleased = env->GetStaticIntField(clazz, field);
Jeff Tinker55d26242018-10-10 16:10:43 -0700839 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
840 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
841
842 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
843
Jeff Tinker2bca5252018-02-11 18:59:14 +0000844 jmethodID getMaxSecurityLevel;
845 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
846 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
847
Jeff Tinker16b8cff2013-03-30 16:26:13 -0700848 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700849 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
850 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker4cdc2de2015-03-16 13:06:33 -0700851 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800852
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700853 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
854 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
855 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
856 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
857 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
858 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
Rahul Frias8f761ba2018-01-22 23:43:54 -0800859 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
860 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
861 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
862 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
Jeff Tinker5ffbae642015-05-13 16:53:52 -0700863
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800864 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
Jeff Tinkere1c76be2013-04-03 18:11:33 -0700865 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
866 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800867
Jeff Tinkere4095a82014-03-04 13:17:11 -0800868 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
869 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
870 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700871 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800872
Adam Stone94395c92018-01-30 12:07:00 -0800873 // Metrics-related fields and classes.
874 FIND_CLASS(clazz, "android/os/PersistableBundle");
875 jfieldID bundleCreatorId;
876 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
877 "Landroid/os/Parcelable$Creator;");
878 jobject bundleCreator;
879 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
880 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
881 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
882 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
883 "(Landroid/os/Parcel;)Ljava/lang/Object;");
884 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
885
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800886 FIND_CLASS(clazz, "java/util/ArrayList");
887 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
888 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
889
890 FIND_CLASS(clazz, "java/util/HashMap");
891 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
892 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
893 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
894 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
895 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
896
897 FIND_CLASS(clazz, "java/util/Set");
898 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
899
900 FIND_CLASS(clazz, "java/util/Iterator");
901 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
902 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
903
904 FIND_CLASS(clazz, "java/util/Map$Entry");
905 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
906 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
Jeff Tinkere4095a82014-03-04 13:17:11 -0800907
908 FIND_CLASS(clazz, "java/util/HashMap");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700909 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800910
911 FIND_CLASS(clazz, "java/lang/String");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700912 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkere4095a82014-03-04 13:17:11 -0800913
914 FIND_CLASS(clazz, "java/util/ArrayList");
Jeff Tinker65c94e62014-04-02 12:23:56 -0700915 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinkerd712e1a2014-06-19 13:58:12 -0700916
917 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
918 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
919 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Jeff Tinker20594d82018-12-12 08:31:22 -0800920
921 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
922 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
923 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
924 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
925
Jeff Tinkerf11261b2019-02-26 18:11:37 -0800926 GET_STATIC_FIELD_ID(field, clazz, "ERROR_UNKNOWN", "I");
927 gSessionExceptionErrorCodes.kErrorUnknown = env->GetStaticIntField(clazz, field);
Jeff Tinker20594d82018-12-12 08:31:22 -0800928 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
929 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
Robert Shih9d4e2d42019-11-08 13:51:49 -0800930
931 FIND_CLASS(clazz, "android/media/MediaDrm$KeyStatus");
932 gFields.keyStatus.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
933 GET_METHOD_ID(gFields.keyStatus.init, clazz, "<init>", "([BI)V");
Robert Shih696989f2021-02-12 23:25:16 -0800934
935 FIND_CLASS(clazz, "android/media/MediaDrm$LogMessage");
936 gFields.logMessage.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
937 GET_METHOD_ID(gFields.logMessage.init, clazz, "<init>", "(JILjava/lang/String;)V");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800938}
939
940static void android_media_MediaDrm_native_setup(
941 JNIEnv *env, jobject thiz,
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800942 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800943
944 if (uuidObj == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700945 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800946 return;
947 }
948
949 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
950
951 if (uuid.size() != 16) {
Jeff Tinkereada5372013-05-21 12:48:14 -0700952 jniThrowException(env, "java/lang/IllegalArgumentException",
953 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800954 return;
955 }
956
Edwin Wong4d1d84e2017-01-04 09:37:49 -0800957 String8 packageName;
958 if (jappPackageName == NULL) {
959 jniThrowException(env, "java/lang/IllegalArgumentException",
960 "application package name cannot be null");
961 return;
962 }
963
964 packageName = JStringToString8(env, jappPackageName);
965 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800966
967 status_t err = drm->initCheck();
968
969 if (err != OK) {
Robert Shih250f6a72021-02-26 08:20:31 -0800970 auto logs(DrmUtils::gLogBuf.getLogs());
971 auto msg(DrmUtils::GetExceptionMessage(err, "Failed to instantiate drm object", logs));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800972 jniThrowException(
973 env,
Jeff Tinker1d7c2182013-04-26 11:12:43 -0700974 "android/media/UnsupportedSchemeException",
Robert Shih250f6a72021-02-26 08:20:31 -0800975 msg.c_str());
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800976 return;
977 }
978
Jeff Tinker54cfbd62013-04-02 13:14:59 -0700979 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
980 drm->setListener(listener);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -0800981 setDrm(env, thiz, drm);
982}
983
Jeff Tinkerd571a7c2019-01-17 17:29:30 -0800984DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
985 DrmPlugin::SecurityLevel level;
986
987 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
988 level = DrmPlugin::kSecurityLevelMax;
989 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
990 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
991 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
992 level = DrmPlugin::kSecurityLevelSwSecureDecode;
993 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
994 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
995 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
996 level = DrmPlugin::kSecurityLevelHwSecureDecode;
997 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
998 level = DrmPlugin::kSecurityLevelHwSecureAll;
999 } else {
1000 level = DrmPlugin::kSecurityLevelUnknown;
1001 }
1002 return level;
1003}
1004
Robert Shihd2e8b432019-11-21 20:27:56 -08001005static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
Kyle Zhang621af3e2022-03-17 23:39:05 +00001006 sp<IDrm> drm = android::DrmUtils::MakeDrm();
Robert Shihd2e8b432019-11-21 20:27:56 -08001007 std::vector<uint8_t> bv;
Kyle Zhang621af3e2022-03-17 23:39:05 +00001008 drm->getSupportedSchemes(bv);
Robert Shihd2e8b432019-11-21 20:27:56 -08001009
1010 jbyteArray jUuidBytes = env->NewByteArray(bv.size());
1011 env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
1012 return jUuidBytes;
1013}
1014
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001015static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001016 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
1017 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001018
1019 if (uuidObj == NULL) {
1020 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1021 return false;
1022 }
1023
1024 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
1025
1026 if (uuid.size() != 16) {
1027 jniThrowException(
1028 env,
1029 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -07001030 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001031 return false;
1032 }
1033
Jeff Tinker7cda4912013-08-21 11:52:34 -07001034 String8 mimeType;
1035 if (jmimeType != NULL) {
1036 mimeType = JStringToString8(env, jmimeType);
1037 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001038 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -07001039
Jeff Tinker5de2e902019-01-25 23:09:36 -08001040 bool isSupported;
1041 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
1042 securityLevel, &isSupported);
1043
Robert Shih60dab872021-02-13 11:24:59 -08001044 if (throwExceptionAsNecessary(env, NULL, err, "Failed to query crypto scheme support")) {
Jeff Tinker5de2e902019-01-25 23:09:36 -08001045 return false;
1046 }
1047 return isSupported;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001048}
1049
1050static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +00001051 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001052 sp<IDrm> drm = GetDrm(env, thiz);
1053
Jeff Tinker55d26242018-10-10 16:10:43 -07001054 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001055 return NULL;
1056 }
1057
1058 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001059 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1060 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +00001061 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1062 return NULL;
1063 }
1064
1065 status_t err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001066
Robert Shih60dab872021-02-13 11:24:59 -08001067 if (throwExceptionAsNecessary(env, drm, err, "Failed to open session")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001068 return NULL;
1069 }
1070
1071 return VectorToJByteArray(env, sessionId);
1072}
1073
1074static void android_media_MediaDrm_closeSession(
1075 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1076 sp<IDrm> drm = GetDrm(env, thiz);
1077
1078 if (!CheckSession(env, drm, jsessionId)) {
1079 return;
1080 }
1081
1082 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1083
1084 status_t err = drm->closeSession(sessionId);
1085
Robert Shih60dab872021-02-13 11:24:59 -08001086 throwExceptionAsNecessary(env, drm, err, "Failed to close session");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001087}
1088
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001089static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001090 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001091 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001092 sp<IDrm> drm = GetDrm(env, thiz);
1093
1094 if (!CheckSession(env, drm, jsessionId)) {
1095 return NULL;
1096 }
1097
1098 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1099
1100 Vector<uint8_t> initData;
1101 if (jinitData != NULL) {
1102 initData = JByteArrayToVector(env, jinitData);
1103 }
1104
1105 String8 mimeType;
1106 if (jmimeType != NULL) {
1107 mimeType = JStringToString8(env, jmimeType);
1108 }
1109
Jeff Tinker17b89222013-05-21 12:35:06 -07001110 DrmPlugin::KeyType keyType;
1111 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1112 keyType = DrmPlugin::kKeyType_Streaming;
1113 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1114 keyType = DrmPlugin::kKeyType_Offline;
1115 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1116 keyType = DrmPlugin::kKeyType_Release;
1117 } else {
1118 jniThrowException(env, "java/lang/IllegalArgumentException",
1119 "invalid keyType");
1120 return NULL;
1121 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001122
1123 KeyedVector<String8, String8> optParams;
1124 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001125 bool isOK;
1126 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1127 if (!isOK) {
1128 return NULL;
1129 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001130 }
1131
1132 Vector<uint8_t> request;
1133 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001134 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001135
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001136 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001137 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001138
Robert Shih60dab872021-02-13 11:24:59 -08001139 if (throwExceptionAsNecessary(env, drm, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001140 return NULL;
1141 }
1142
1143 // Fill out return obj
1144 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001145 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001146
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001147 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001148
1149 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001150 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001151 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001152 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001153
1154 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001155 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001156
1157 switch (keyRequestType) {
1158 case DrmPlugin::kKeyRequestType_Initial:
1159 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1160 gKeyRequestTypes.kKeyRequestTypeInitial);
1161 break;
1162 case DrmPlugin::kKeyRequestType_Renewal:
1163 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1164 gKeyRequestTypes.kKeyRequestTypeRenewal);
1165 break;
1166 case DrmPlugin::kKeyRequestType_Release:
1167 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1168 gKeyRequestTypes.kKeyRequestTypeRelease);
1169 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001170 case DrmPlugin::kKeyRequestType_None:
1171 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1172 gKeyRequestTypes.kKeyRequestTypeNone);
1173 break;
1174 case DrmPlugin::kKeyRequestType_Update:
1175 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1176 gKeyRequestTypes.kKeyRequestTypeUpdate);
1177 break;
1178
Jeff Tinker74797f82015-03-31 15:44:34 -07001179 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001180 throwStateException(env, "DRM plugin failure: unknown key request type",
1181 ERROR_DRM_UNKNOWN);
1182 break;
1183 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001184 }
1185
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001186 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001187}
1188
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001189static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001190 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1191 sp<IDrm> drm = GetDrm(env, thiz);
1192
1193 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001194 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001195 }
1196
1197 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1198
1199 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001200 jniThrowException(env, "java/lang/IllegalArgumentException",
1201 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001202 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001203 }
1204 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001205 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001206
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001207 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001208
Robert Shih60dab872021-02-13 11:24:59 -08001209 if (throwExceptionAsNecessary(env, drm, err, "Failed to handle key response")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001210 return NULL;
1211 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001212 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001213}
1214
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001215static void android_media_MediaDrm_removeKeys(
1216 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1217 sp<IDrm> drm = GetDrm(env, thiz);
1218
Jeff Tinker55d26242018-10-10 16:10:43 -07001219 if (!CheckDrm(env, drm)) {
1220 return;
1221 }
1222
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001223 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001224 jniThrowException(env, "java/lang/IllegalArgumentException",
1225 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001226 return;
1227 }
1228
1229 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1230
1231 status_t err = drm->removeKeys(keySetId);
1232
Robert Shih60dab872021-02-13 11:24:59 -08001233 throwExceptionAsNecessary(env, drm, err, "Failed to remove keys");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001234}
1235
1236static void android_media_MediaDrm_restoreKeys(
1237 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1238 jbyteArray jkeysetId) {
1239
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001240 sp<IDrm> drm = GetDrm(env, thiz);
1241
1242 if (!CheckSession(env, drm, jsessionId)) {
1243 return;
1244 }
1245
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001246 if (jkeysetId == NULL) {
1247 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1248 return;
1249 }
1250
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001251 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001252 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001253
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001254 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001255
Robert Shih60dab872021-02-13 11:24:59 -08001256 throwExceptionAsNecessary(env, drm, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001257}
1258
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001259static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001260 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1261 sp<IDrm> drm = GetDrm(env, thiz);
1262
1263 if (!CheckSession(env, drm, jsessionId)) {
1264 return NULL;
1265 }
1266 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1267
1268 KeyedVector<String8, String8> infoMap;
1269
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001270 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001271
Robert Shih60dab872021-02-13 11:24:59 -08001272 if (throwExceptionAsNecessary(env, drm, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001273 return NULL;
1274 }
1275
1276 return KeyedVectorToHashMap(env, infoMap);
1277}
1278
Jeff Tinkere4095a82014-03-04 13:17:11 -08001279static jobject android_media_MediaDrm_getProvisionRequestNative(
1280 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001281 sp<IDrm> drm = GetDrm(env, thiz);
1282
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001283 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001284 return NULL;
1285 }
1286
1287 Vector<uint8_t> request;
1288 String8 defaultUrl;
1289
Jeff Tinkere4095a82014-03-04 13:17:11 -08001290 String8 certType;
1291 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1292 certType = "X.509";
1293 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1294 certType = "none";
1295 } else {
1296 certType = "invalid";
1297 }
1298
1299 String8 certAuthority = JStringToString8(env, jcertAuthority);
1300 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001301
Robert Shih60dab872021-02-13 11:24:59 -08001302 if (throwExceptionAsNecessary(env, drm, err, "Failed to get provision request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001303 return NULL;
1304 }
1305
1306 // Fill out return obj
1307 jclass clazz;
1308 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1309
1310 jobject provisionObj = NULL;
1311
1312 if (clazz) {
1313 provisionObj = env->AllocObject(clazz);
1314 jbyteArray jrequest = VectorToJByteArray(env, request);
1315 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1316
1317 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1318 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1319 }
1320
1321 return provisionObj;
1322}
1323
Jeff Tinkere4095a82014-03-04 13:17:11 -08001324static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001325 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1326 sp<IDrm> drm = GetDrm(env, thiz);
1327
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001328 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001329 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001330 }
1331
1332 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001333 jniThrowException(env, "java/lang/IllegalArgumentException",
1334 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001335 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001336 }
1337
1338 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001339 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001340
Jeff Tinkere4095a82014-03-04 13:17:11 -08001341 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1342
1343 // Fill out return obj
1344 jclass clazz = gFields.certificateClassId;
1345
1346 jobject certificateObj = NULL;
1347
1348 if (clazz && certificate.size() && wrappedKey.size()) {
1349 certificateObj = env->AllocObject(clazz);
1350 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1351 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1352
1353 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1354 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1355 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001356
Robert Shih60dab872021-02-13 11:24:59 -08001357 throwExceptionAsNecessary(env, drm, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001358 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001359}
1360
1361static jobject android_media_MediaDrm_getSecureStops(
1362 JNIEnv *env, jobject thiz) {
1363 sp<IDrm> drm = GetDrm(env, thiz);
1364
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001365 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001366 return NULL;
1367 }
1368
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001369 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001370
1371 status_t err = drm->getSecureStops(secureStops);
1372
Robert Shih60dab872021-02-13 11:24:59 -08001373 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stops")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001374 return NULL;
1375 }
1376
1377 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1378}
1379
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001380static jobject android_media_MediaDrm_getSecureStopIds(
1381 JNIEnv *env, jobject thiz) {
1382 sp<IDrm> drm = GetDrm(env, thiz);
1383
Jeff Tinker55d26242018-10-10 16:10:43 -07001384 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001385 return NULL;
1386 }
1387
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001388 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001389
1390 status_t err = drm->getSecureStopIds(secureStopIds);
1391
Robert Shih60dab872021-02-13 11:24:59 -08001392 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop Ids")) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001393 return NULL;
1394 }
1395
1396 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1397}
1398
Jeff Tinker1b51c722014-10-31 00:54:26 -07001399static jbyteArray android_media_MediaDrm_getSecureStop(
1400 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1401 sp<IDrm> drm = GetDrm(env, thiz);
1402
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001403 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001404 return NULL;
1405 }
1406
1407 Vector<uint8_t> secureStop;
1408
1409 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1410
Robert Shih60dab872021-02-13 11:24:59 -08001411 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop")) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001412 return NULL;
1413 }
1414
1415 return VectorToJByteArray(env, secureStop);
1416}
1417
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001418static void android_media_MediaDrm_releaseSecureStops(
1419 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1420 sp<IDrm> drm = GetDrm(env, thiz);
1421
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001422 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001423 return;
1424 }
1425
1426 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1427
1428 status_t err = drm->releaseSecureStops(ssRelease);
1429
Robert Shih60dab872021-02-13 11:24:59 -08001430 throwExceptionAsNecessary(env, drm, err, "Failed to release secure stops");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001431}
1432
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001433static void android_media_MediaDrm_removeSecureStop(
1434 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1435 sp<IDrm> drm = GetDrm(env, thiz);
1436
Jeff Tinker55d26242018-10-10 16:10:43 -07001437 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001438 return;
1439 }
1440
1441 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1442
Robert Shih60dab872021-02-13 11:24:59 -08001443 throwExceptionAsNecessary(env, drm, err, "Failed to remove secure stop");
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001444}
1445
1446static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001447 JNIEnv *env, jobject thiz) {
1448 sp<IDrm> drm = GetDrm(env, thiz);
1449
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001450 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001451 return;
1452 }
1453
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001454 status_t err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001455
Robert Shih60dab872021-02-13 11:24:59 -08001456 throwExceptionAsNecessary(env, drm, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001457}
1458
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001459
1460static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1461 switch(level) {
1462 case DrmPlugin::kHdcpLevelUnknown:
1463 return gHdcpLevels.kHdcpLevelUnknown;
1464 case DrmPlugin::kHdcpNone:
1465 return gHdcpLevels.kHdcpNone;
1466 case DrmPlugin::kHdcpV1:
1467 return gHdcpLevels.kHdcpV1;
1468 case DrmPlugin::kHdcpV2:
1469 return gHdcpLevels.kHdcpV2;
1470 case DrmPlugin::kHdcpV2_1:
1471 return gHdcpLevels.kHdcpV2_1;
1472 case DrmPlugin::kHdcpV2_2:
1473 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001474 case DrmPlugin::kHdcpV2_3:
1475 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001476 case DrmPlugin::kHdcpNoOutput:
1477 return gHdcpLevels.kHdcpNoOutput;
1478 }
1479 return gHdcpLevels.kHdcpNone;
1480}
1481
1482static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1483 jobject thiz) {
1484 sp<IDrm> drm = GetDrm(env, thiz);
1485
1486 if (!CheckDrm(env, drm)) {
1487 return gHdcpLevels.kHdcpNone;
1488 }
1489
1490 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1491 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1492
1493 status_t err = drm->getHdcpLevels(&connected, &max);
1494
Robert Shih60dab872021-02-13 11:24:59 -08001495 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001496 return gHdcpLevels.kHdcpLevelUnknown;
1497 }
1498 return HdcpLevelTojint(connected);
1499}
1500
1501static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1502 jobject thiz) {
1503 sp<IDrm> drm = GetDrm(env, thiz);
1504
1505 if (!CheckDrm(env, drm)) {
1506 return gHdcpLevels.kHdcpLevelUnknown;
1507 }
1508
1509 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1510 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1511
1512 status_t err = drm->getHdcpLevels(&connected, &max);
1513
Robert Shih60dab872021-02-13 11:24:59 -08001514 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001515 return gHdcpLevels.kHdcpLevelUnknown;
1516 }
1517 return HdcpLevelTojint(max);
1518}
1519
1520static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1521 jobject thiz) {
1522 sp<IDrm> drm = GetDrm(env, thiz);
1523
1524 if (!CheckDrm(env, drm)) {
1525 return 0;
1526 }
1527
1528 uint32_t open = 0, max = 0;
1529 status_t err = drm->getNumberOfSessions(&open, &max);
1530
Robert Shih60dab872021-02-13 11:24:59 -08001531 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001532 return 0;
1533 }
1534 return open;
1535}
1536
1537static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1538 jobject thiz) {
1539 sp<IDrm> drm = GetDrm(env, thiz);
1540
1541 if (!CheckDrm(env, drm)) {
1542 return 0;
1543 }
1544
1545 uint32_t open = 0, max = 0;
1546 status_t err = drm->getNumberOfSessions(&open, &max);
1547
Robert Shih60dab872021-02-13 11:24:59 -08001548 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001549 return 0;
1550 }
1551 return max;
1552}
1553
1554static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1555 jobject thiz, jbyteArray jsessionId) {
1556 sp<IDrm> drm = GetDrm(env, thiz);
1557
1558 if (!CheckSession(env, drm, jsessionId)) {
1559 return gSecurityLevels.kSecurityLevelUnknown;
1560 }
1561
1562 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1563
1564 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1565
1566 status_t err = drm->getSecurityLevel(sessionId, &level);
1567
Robert Shih60dab872021-02-13 11:24:59 -08001568 if (throwExceptionAsNecessary(env, drm, err, "Failed to get security level")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001569 return gSecurityLevels.kSecurityLevelUnknown;
1570 }
1571
1572 switch(level) {
1573 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1574 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1575 case DrmPlugin::kSecurityLevelSwSecureDecode:
1576 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1577 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1578 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1579 case DrmPlugin::kSecurityLevelHwSecureDecode:
1580 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1581 case DrmPlugin::kSecurityLevelHwSecureAll:
1582 return gSecurityLevels.kSecurityLevelHwSecureAll;
1583 default:
1584 return gSecurityLevels.kSecurityLevelUnknown;
1585 }
1586}
1587
Jeff Tinker55d26242018-10-10 16:10:43 -07001588static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1589 JNIEnv *env, jobject thiz) {
1590 sp<IDrm> drm = GetDrm(env, thiz);
1591
1592 if (!CheckDrm(env, drm)) {
1593 return NULL;
1594 }
1595
1596 List<Vector<uint8_t> > keySetIds;
1597
1598 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1599
Robert Shih60dab872021-02-13 11:24:59 -08001600 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline key set Ids")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001601 return NULL;
1602 }
1603
1604 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1605}
1606
1607static void android_media_MediaDrm_removeOfflineLicense(
1608 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1609 sp<IDrm> drm = GetDrm(env, thiz);
1610
1611 if (!CheckDrm(env, drm)) {
1612 return;
1613 }
1614
1615 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1616
Robert Shih60dab872021-02-13 11:24:59 -08001617 throwExceptionAsNecessary(env, drm, err, "Failed to remove offline license");
Jeff Tinker55d26242018-10-10 16:10:43 -07001618}
1619
1620static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1621 jobject thiz, jbyteArray jkeySetId) {
1622 sp<IDrm> drm = GetDrm(env, thiz);
1623
1624 if (!CheckDrm(env, drm)) {
1625 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1626 }
1627
1628 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1629
1630 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1631
1632 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1633
Robert Shih60dab872021-02-13 11:24:59 -08001634 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline license state")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001635 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1636 }
1637
1638 switch(state) {
1639 case DrmPlugin::kOfflineLicenseStateUsable:
1640 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -08001641 case DrmPlugin::kOfflineLicenseStateReleased:
1642 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -07001643 default:
1644 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1645 }
1646}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001647
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001648static jstring android_media_MediaDrm_getPropertyString(
1649 JNIEnv *env, jobject thiz, jstring jname) {
1650 sp<IDrm> drm = GetDrm(env, thiz);
1651
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001652 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001653 return NULL;
1654 }
1655
1656 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001657 jniThrowException(env, "java/lang/IllegalArgumentException",
1658 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001659 return NULL;
1660 }
1661
1662 String8 name = JStringToString8(env, jname);
1663 String8 value;
1664
1665 status_t err = drm->getPropertyString(name, value);
1666
Robert Shih60dab872021-02-13 11:24:59 -08001667 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001668 return NULL;
1669 }
1670
1671 return env->NewStringUTF(value.string());
1672}
1673
1674static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1675 JNIEnv *env, jobject thiz, jstring jname) {
1676 sp<IDrm> drm = GetDrm(env, thiz);
1677
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001678 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001679 return NULL;
1680 }
1681
1682 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001683 jniThrowException(env, "java/lang/IllegalArgumentException",
1684 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001685 return NULL;
1686 }
1687
1688 String8 name = JStringToString8(env, jname);
1689 Vector<uint8_t> value;
1690
1691 status_t err = drm->getPropertyByteArray(name, value);
1692
Robert Shih60dab872021-02-13 11:24:59 -08001693 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001694 return NULL;
1695 }
1696
1697 return VectorToJByteArray(env, value);
1698}
1699
1700static void android_media_MediaDrm_setPropertyString(
1701 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1702 sp<IDrm> drm = GetDrm(env, thiz);
1703
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001704 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001705 return;
1706 }
1707
Jeff Tinkereada5372013-05-21 12:48:14 -07001708 if (jname == NULL) {
1709 jniThrowException(env, "java/lang/IllegalArgumentException",
1710 "property name String is null");
1711 return;
1712 }
1713
1714 if (jvalue == NULL) {
1715 jniThrowException(env, "java/lang/IllegalArgumentException",
1716 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001717 return;
1718 }
1719
1720 String8 name = JStringToString8(env, jname);
1721 String8 value = JStringToString8(env, jvalue);
1722
1723 status_t err = drm->setPropertyString(name, value);
1724
Robert Shih60dab872021-02-13 11:24:59 -08001725 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001726}
1727
1728static void android_media_MediaDrm_setPropertyByteArray(
1729 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1730 sp<IDrm> drm = GetDrm(env, thiz);
1731
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001732 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001733 return;
1734 }
1735
Jeff Tinkereada5372013-05-21 12:48:14 -07001736 if (jname == NULL) {
1737 jniThrowException(env, "java/lang/IllegalArgumentException",
1738 "property name String is null");
1739 return;
1740 }
1741
1742 if (jvalue == NULL) {
1743 jniThrowException(env, "java/lang/IllegalArgumentException",
1744 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001745 return;
1746 }
1747
1748 String8 name = JStringToString8(env, jname);
1749 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1750
1751 status_t err = drm->setPropertyByteArray(name, value);
1752
Robert Shih60dab872021-02-13 11:24:59 -08001753 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001754}
1755
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001756static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001757 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001758 jstring jalgorithm) {
1759
1760 sp<IDrm> drm = GetDrm(env, jdrm);
1761
1762 if (!CheckSession(env, drm, jsessionId)) {
1763 return;
1764 }
1765
1766 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001767 jniThrowException(env, "java/lang/IllegalArgumentException",
1768 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001769 return;
1770 }
1771
1772 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1773 String8 algorithm = JStringToString8(env, jalgorithm);
1774
1775 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1776
Robert Shih60dab872021-02-13 11:24:59 -08001777 throwExceptionAsNecessary(env, drm, err, "Failed to set cipher algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001778}
1779
1780static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001781 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001782 jstring jalgorithm) {
1783
1784 sp<IDrm> drm = GetDrm(env, jdrm);
1785
1786 if (!CheckSession(env, drm, jsessionId)) {
1787 return;
1788 }
1789
1790 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001791 jniThrowException(env, "java/lang/IllegalArgumentException",
1792 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001793 return;
1794 }
1795
1796 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1797 String8 algorithm = JStringToString8(env, jalgorithm);
1798
1799 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1800
Robert Shih60dab872021-02-13 11:24:59 -08001801 throwExceptionAsNecessary(env, drm, err, "Failed to set mac algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001802}
1803
1804
1805static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001806 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001807 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1808
1809 sp<IDrm> drm = GetDrm(env, jdrm);
1810
1811 if (!CheckSession(env, drm, jsessionId)) {
1812 return NULL;
1813 }
1814
1815 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001816 jniThrowException(env, "java/lang/IllegalArgumentException",
1817 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001818 return NULL;
1819 }
1820
1821 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1822 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1823 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1824 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1825 Vector<uint8_t> output;
1826
1827 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1828
Robert Shih60dab872021-02-13 11:24:59 -08001829 if (throwExceptionAsNecessary(env, drm, err, "Failed to encrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001830 return NULL;
1831 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001832
1833 return VectorToJByteArray(env, output);
1834}
1835
1836static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001837 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001838 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1839
1840 sp<IDrm> drm = GetDrm(env, jdrm);
1841
1842 if (!CheckSession(env, drm, jsessionId)) {
1843 return NULL;
1844 }
1845
1846 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001847 jniThrowException(env, "java/lang/IllegalArgumentException",
1848 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001849 return NULL;
1850 }
1851
1852 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1853 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1854 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1855 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1856 Vector<uint8_t> output;
1857
1858 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Robert Shih60dab872021-02-13 11:24:59 -08001859 if (throwExceptionAsNecessary(env, drm, err, "Failed to decrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001860 return NULL;
1861 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001862
1863 return VectorToJByteArray(env, output);
1864}
1865
1866static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001867 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001868 jbyteArray jkeyId, jbyteArray jmessage) {
1869
1870 sp<IDrm> drm = GetDrm(env, jdrm);
1871
1872 if (!CheckSession(env, drm, jsessionId)) {
1873 return NULL;
1874 }
1875
1876 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001877 jniThrowException(env, "java/lang/IllegalArgumentException",
1878 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001879 return NULL;
1880 }
1881
1882 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1883 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1884 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1885 Vector<uint8_t> signature;
1886
1887 status_t err = drm->sign(sessionId, keyId, message, signature);
1888
Robert Shih60dab872021-02-13 11:24:59 -08001889 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001890 return NULL;
1891 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001892
1893 return VectorToJByteArray(env, signature);
1894}
1895
1896static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001897 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001898 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1899
1900 sp<IDrm> drm = GetDrm(env, jdrm);
1901
1902 if (!CheckSession(env, drm, jsessionId)) {
1903 return false;
1904 }
1905
1906 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001907 jniThrowException(env, "java/lang/IllegalArgumentException",
1908 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001909 return false;
1910 }
1911
1912 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1913 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1914 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1915 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1916 bool match;
1917
1918 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1919
Robert Shih60dab872021-02-13 11:24:59 -08001920 throwExceptionAsNecessary(env, drm, err, "Failed to verify");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001921 return match;
1922}
1923
Adam Stonec06e10e2017-12-19 12:54:33 -08001924static jobject
1925android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1926{
1927 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001928
1929 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001930 return NULL;
1931 }
1932
1933 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001934 PersistableBundle metrics;
Robert Shihba6777e2019-11-12 13:04:59 -08001935 sp<IDrmMetricsConsumer> consumer(new DrmMetricsConsumer(&metrics));
1936 status_t err = drm->getMetrics(consumer);
Adam Stonec06e10e2017-12-19 12:54:33 -08001937 if (err != OK) {
1938 ALOGE("getMetrics failed: %d", (int)err);
1939 return (jobject) NULL;
1940 }
1941
Robert Shih4354a962019-11-10 12:09:08 -08001942 return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001943}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001944
Jeff Tinkere4095a82014-03-04 13:17:11 -08001945static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001946 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001947 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1948
1949 sp<IDrm> drm = GetDrm(env, jdrm);
1950
1951 if (!CheckSession(env, drm, jsessionId)) {
1952 return NULL;
1953 }
1954
1955 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1956 jniThrowException(env, "java/lang/IllegalArgumentException",
1957 "required argument is null");
1958 return NULL;
1959 }
1960
1961 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1962 String8 algorithm = JStringToString8(env, jalgorithm);
1963 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1964 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1965 Vector<uint8_t> signature;
1966
1967 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1968
Robert Shih60dab872021-02-13 11:24:59 -08001969 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001970 return NULL;
1971 }
1972
1973 return VectorToJByteArray(env, signature);
1974}
1975
Robert Shih205f7a92021-01-19 21:12:10 -08001976static jboolean android_media_MediaDrm_requiresSecureDecoder(
1977 JNIEnv *env, jobject thiz, jstring jmimeType,
1978 jint jSecurityLevel) {
1979 sp<IDrm> drm = GetDrm(env, thiz);
1980 if (!CheckDrm(env, drm)) {
1981 return JNI_FALSE;
1982 }
1983
1984 String8 mimeType;
1985 if (jmimeType != NULL) {
1986 mimeType = JStringToString8(env, jmimeType);
1987 }
1988
1989 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
1990 if (securityLevel == DrmPlugin::kSecurityLevelUnknown) {
1991 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1992 return JNI_FALSE;
1993 }
1994
Robert Shih5bb242a2021-04-28 10:04:51 -07001995 bool required = false;
1996 status_t err = OK;
Robert Shih205f7a92021-01-19 21:12:10 -08001997 if (securityLevel == DrmPlugin::kSecurityLevelMax) {
Robert Shih5bb242a2021-04-28 10:04:51 -07001998 err = drm->requiresSecureDecoder(mimeType.c_str(), &required);
1999 } else {
2000 err = drm->requiresSecureDecoder(mimeType.c_str(), securityLevel, &required);
Robert Shih205f7a92021-01-19 21:12:10 -08002001 }
Robert Shih5bb242a2021-04-28 10:04:51 -07002002 if (throwExceptionAsNecessary(env, drm, err, "Failed to query secure decoder requirement")) {
2003 return false;
2004 }
2005 return required;
Robert Shih205f7a92021-01-19 21:12:10 -08002006}
Jeff Tinkere4095a82014-03-04 13:17:11 -08002007
Robert Shih02937122021-01-20 00:05:20 -08002008static void android_media_MediaDrm_setPlaybackId(
2009 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
2010 jstring jplaybackId) {
2011 sp<IDrm> drm = GetDrm(env, thiz);
2012 if (!CheckSession(env, drm, jsessionId)) {
2013 return;
2014 }
2015
2016 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2017
2018 String8 playbackId;
2019 if (jplaybackId != NULL) {
2020 playbackId = JStringToString8(env, jplaybackId);
2021 }
2022 status_t err = drm->setPlaybackId(sessionId, playbackId.c_str());
Robert Shih60dab872021-02-13 11:24:59 -08002023 throwExceptionAsNecessary(env, drm, err, "Failed to set playbackId");
Robert Shih02937122021-01-20 00:05:20 -08002024}
2025
Robert Shih696989f2021-02-12 23:25:16 -08002026static jobject android_media_MediaDrm_getLogMessages(
2027 JNIEnv *env, jobject thiz) {
2028 sp<IDrm> drm = GetDrm(env, thiz);
2029 if (!CheckDrm(env, drm)) {
2030 return NULL;
2031 }
2032
2033 Vector<drm::V1_4::LogMessage> logs;
2034 status_t err = drm->getLogMessages(logs);
2035 ALOGI("drm->getLogMessages %zu logs", logs.size());
Robert Shih60dab872021-02-13 11:24:59 -08002036 if (throwExceptionAsNecessary(env, drm, err, "Failed to get log messages")) {
Robert Shih696989f2021-02-12 23:25:16 -08002037 return NULL;
2038 }
2039 return hidlLogMessagesToJavaList(env, logs);
2040}
2041
Daniel Micay76f6a862015-09-19 17:31:01 -04002042static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002043 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
2044
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002045 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
2046
Edwin Wong4d1d84e2017-01-04 09:37:49 -08002047 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002048 (void *)android_media_MediaDrm_native_setup },
2049
Robert Shihd2e8b432019-11-21 20:27:56 -08002050 { "getSupportedCryptoSchemesNative", "()[B",
2051 (void *)android_media_MediaDrm_getSupportedCryptoSchemesNative },
2052
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08002053 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002054 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
2055
Robert Shih02937122021-01-20 00:05:20 -08002056 { "openSessionNative", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002057 (void *)android_media_MediaDrm_openSession },
2058
Robert Shih02937122021-01-20 00:05:20 -08002059 { "closeSessionNative", "([B)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002060 (void *)android_media_MediaDrm_closeSession },
2061
Robert Shih890eb572021-01-19 08:16:39 -08002062 { "getKeyRequestNative", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002063 "Landroid/media/MediaDrm$KeyRequest;",
2064 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002065
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002066 { "provideKeyResponse", "([B[B)[B",
2067 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002068
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002069 { "removeKeys", "([B)V",
2070 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002071
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002072 { "restoreKeys", "([B[B)V",
2073 (void *)android_media_MediaDrm_restoreKeys },
2074
2075 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
2076 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002077
Jeff Tinkere4095a82014-03-04 13:17:11 -08002078 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
2079 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002080
Jeff Tinkere4095a82014-03-04 13:17:11 -08002081 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
2082 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002083
2084 { "getSecureStops", "()Ljava/util/List;",
2085 (void *)android_media_MediaDrm_getSecureStops },
2086
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002087 { "getSecureStopIds", "()Ljava/util/List;",
2088 (void *)android_media_MediaDrm_getSecureStopIds },
2089
Jeff Tinker1b51c722014-10-31 00:54:26 -07002090 { "getSecureStop", "([B)[B",
2091 (void *)android_media_MediaDrm_getSecureStop },
2092
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002093 { "releaseSecureStops", "([B)V",
2094 (void *)android_media_MediaDrm_releaseSecureStops },
2095
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002096 { "removeSecureStop", "([B)V",
2097 (void *)android_media_MediaDrm_removeSecureStop },
2098
2099 { "removeAllSecureStops", "()V",
2100 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07002101
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002102 { "getConnectedHdcpLevel", "()I",
2103 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
2104
2105 { "getMaxHdcpLevel", "()I",
2106 (void *)android_media_MediaDrm_getMaxHdcpLevel },
2107
2108 { "getOpenSessionCount", "()I",
2109 (void *)android_media_MediaDrm_getOpenSessionCount },
2110
2111 { "getMaxSessionCount", "()I",
2112 (void *)android_media_MediaDrm_getMaxSessionCount },
2113
2114 { "getSecurityLevel", "([B)I",
2115 (void *)android_media_MediaDrm_getSecurityLevel },
2116
Jeff Tinker55d26242018-10-10 16:10:43 -07002117 { "removeOfflineLicense", "([B)V",
2118 (void *)android_media_MediaDrm_removeOfflineLicense },
2119
2120 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
2121 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
2122
2123 { "getOfflineLicenseState", "([B)I",
2124 (void *)android_media_MediaDrm_getOfflineLicenseState },
2125
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002126 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2127 (void *)android_media_MediaDrm_getPropertyString },
2128
2129 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2130 (void *)android_media_MediaDrm_getPropertyByteArray },
2131
2132 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2133 (void *)android_media_MediaDrm_setPropertyString },
2134
2135 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2136 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002137
2138 { "setCipherAlgorithmNative",
2139 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2140 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2141
2142 { "setMacAlgorithmNative",
2143 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2144 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2145
2146 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2147 (void *)android_media_MediaDrm_encryptNative },
2148
2149 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2150 (void *)android_media_MediaDrm_decryptNative },
2151
2152 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2153 (void *)android_media_MediaDrm_signNative },
2154
2155 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2156 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002157
2158 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2159 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002160
2161 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2162 (void *)android_media_MediaDrm_native_getMetrics },
Robert Shih205f7a92021-01-19 21:12:10 -08002163
2164 { "requiresSecureDecoder", "(Ljava/lang/String;I)Z",
2165 (void *)android_media_MediaDrm_requiresSecureDecoder },
Robert Shih02937122021-01-20 00:05:20 -08002166
2167 { "setPlaybackId", "([BLjava/lang/String;)V",
2168 (void *)android_media_MediaDrm_setPlaybackId },
Robert Shih696989f2021-02-12 23:25:16 -08002169
2170 { "getLogMessages", "()Ljava/util/List;",
2171 (void *)android_media_MediaDrm_getLogMessages },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002172};
2173
2174int register_android_media_Drm(JNIEnv *env) {
2175 return AndroidRuntime::registerNativeMethods(env,
2176 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2177}