blob: 4f7b7115fe26091589c1b07d8e9bcd1de06f1290 [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) {
1006 std::vector<uint8_t> bv;
1007 for (auto &factory : DrmUtils::MakeDrmFactories()) {
1008 sp<drm::V1_3::IDrmFactory> factoryV1_3 = drm::V1_3::IDrmFactory::castFrom(factory);
1009 if (factoryV1_3 == nullptr) {
1010 continue;
1011 }
1012 factoryV1_3->getSupportedCryptoSchemes(
1013 [&](const hardware::hidl_vec<hardware::hidl_array<uint8_t, 16>>& schemes) {
1014 for (const auto &scheme : schemes) {
1015 bv.insert(bv.end(), scheme.data(), scheme.data() + scheme.size());
1016 }
1017 });
1018 }
1019
1020 jbyteArray jUuidBytes = env->NewByteArray(bv.size());
1021 env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
1022 return jUuidBytes;
1023}
1024
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001025static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001026 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
1027 jint jSecurityLevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001028
1029 if (uuidObj == NULL) {
1030 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1031 return false;
1032 }
1033
1034 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
1035
1036 if (uuid.size() != 16) {
1037 jniThrowException(
1038 env,
1039 "java/lang/IllegalArgumentException",
Jeff Tinkereada5372013-05-21 12:48:14 -07001040 "invalid UUID size, expected 16 bytes");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001041 return false;
1042 }
1043
Jeff Tinker7cda4912013-08-21 11:52:34 -07001044 String8 mimeType;
1045 if (jmimeType != NULL) {
1046 mimeType = JStringToString8(env, jmimeType);
1047 }
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001048 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
Jeff Tinker7cda4912013-08-21 11:52:34 -07001049
Jeff Tinker5de2e902019-01-25 23:09:36 -08001050 bool isSupported;
1051 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
1052 securityLevel, &isSupported);
1053
Robert Shih60dab872021-02-13 11:24:59 -08001054 if (throwExceptionAsNecessary(env, NULL, err, "Failed to query crypto scheme support")) {
Jeff Tinker5de2e902019-01-25 23:09:36 -08001055 return false;
1056 }
1057 return isSupported;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001058}
1059
1060static jbyteArray android_media_MediaDrm_openSession(
Jeff Tinker2bca5252018-02-11 18:59:14 +00001061 JNIEnv *env, jobject thiz, jint jlevel) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001062 sp<IDrm> drm = GetDrm(env, thiz);
1063
Jeff Tinker55d26242018-10-10 16:10:43 -07001064 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001065 return NULL;
1066 }
1067
1068 Vector<uint8_t> sessionId;
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08001069 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1070 if (level == DrmPlugin::kSecurityLevelUnknown) {
Jeff Tinker2bca5252018-02-11 18:59:14 +00001071 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1072 return NULL;
1073 }
1074
1075 status_t err = drm->openSession(level, sessionId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001076
Robert Shih60dab872021-02-13 11:24:59 -08001077 if (throwExceptionAsNecessary(env, drm, err, "Failed to open session")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001078 return NULL;
1079 }
1080
1081 return VectorToJByteArray(env, sessionId);
1082}
1083
1084static void android_media_MediaDrm_closeSession(
1085 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1086 sp<IDrm> drm = GetDrm(env, thiz);
1087
1088 if (!CheckSession(env, drm, jsessionId)) {
1089 return;
1090 }
1091
1092 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1093
1094 status_t err = drm->closeSession(sessionId);
1095
Robert Shih60dab872021-02-13 11:24:59 -08001096 throwExceptionAsNecessary(env, drm, err, "Failed to close session");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001097}
1098
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001099static jobject android_media_MediaDrm_getKeyRequest(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001100 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001101 jstring jmimeType, jint jkeyType, jobject joptParams) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001102 sp<IDrm> drm = GetDrm(env, thiz);
1103
1104 if (!CheckSession(env, drm, jsessionId)) {
1105 return NULL;
1106 }
1107
1108 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1109
1110 Vector<uint8_t> initData;
1111 if (jinitData != NULL) {
1112 initData = JByteArrayToVector(env, jinitData);
1113 }
1114
1115 String8 mimeType;
1116 if (jmimeType != NULL) {
1117 mimeType = JStringToString8(env, jmimeType);
1118 }
1119
Jeff Tinker17b89222013-05-21 12:35:06 -07001120 DrmPlugin::KeyType keyType;
1121 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1122 keyType = DrmPlugin::kKeyType_Streaming;
1123 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1124 keyType = DrmPlugin::kKeyType_Offline;
1125 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1126 keyType = DrmPlugin::kKeyType_Release;
1127 } else {
1128 jniThrowException(env, "java/lang/IllegalArgumentException",
1129 "invalid keyType");
1130 return NULL;
1131 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001132
1133 KeyedVector<String8, String8> optParams;
1134 if (joptParams != NULL) {
Daniel Broms35d6a4f2014-09-29 15:32:03 +02001135 bool isOK;
1136 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1137 if (!isOK) {
1138 return NULL;
1139 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001140 }
1141
1142 Vector<uint8_t> request;
1143 String8 defaultUrl;
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001144 DrmPlugin::KeyRequestType keyRequestType;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001145
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001146 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001147 keyType, optParams, request, defaultUrl, &keyRequestType);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001148
Robert Shih60dab872021-02-13 11:24:59 -08001149 if (throwExceptionAsNecessary(env, drm, err, "Failed to get key request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001150 return NULL;
1151 }
1152
1153 // Fill out return obj
1154 jclass clazz;
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001155 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001156
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001157 jobject keyObj = NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001158
1159 if (clazz) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001160 keyObj = env->AllocObject(clazz);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001161 jbyteArray jrequest = VectorToJByteArray(env, request);
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001162 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001163
1164 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001165 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001166
1167 switch (keyRequestType) {
1168 case DrmPlugin::kKeyRequestType_Initial:
1169 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1170 gKeyRequestTypes.kKeyRequestTypeInitial);
1171 break;
1172 case DrmPlugin::kKeyRequestType_Renewal:
1173 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1174 gKeyRequestTypes.kKeyRequestTypeRenewal);
1175 break;
1176 case DrmPlugin::kKeyRequestType_Release:
1177 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1178 gKeyRequestTypes.kKeyRequestTypeRelease);
1179 break;
Rahul Frias8f761ba2018-01-22 23:43:54 -08001180 case DrmPlugin::kKeyRequestType_None:
1181 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1182 gKeyRequestTypes.kKeyRequestTypeNone);
1183 break;
1184 case DrmPlugin::kKeyRequestType_Update:
1185 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1186 gKeyRequestTypes.kKeyRequestTypeUpdate);
1187 break;
1188
Jeff Tinker74797f82015-03-31 15:44:34 -07001189 default:
Jeff Tinker4cdc2de2015-03-16 13:06:33 -07001190 throwStateException(env, "DRM plugin failure: unknown key request type",
1191 ERROR_DRM_UNKNOWN);
1192 break;
1193 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001194 }
1195
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001196 return keyObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001197}
1198
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001199static jbyteArray android_media_MediaDrm_provideKeyResponse(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001200 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1201 sp<IDrm> drm = GetDrm(env, thiz);
1202
1203 if (!CheckSession(env, drm, jsessionId)) {
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001204 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001205 }
1206
1207 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1208
1209 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001210 jniThrowException(env, "java/lang/IllegalArgumentException",
1211 "key response is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001212 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001213 }
1214 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001215 Vector<uint8_t> keySetId;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001216
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001217 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001218
Robert Shih60dab872021-02-13 11:24:59 -08001219 if (throwExceptionAsNecessary(env, drm, err, "Failed to handle key response")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001220 return NULL;
1221 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001222 return VectorToJByteArray(env, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001223}
1224
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001225static void android_media_MediaDrm_removeKeys(
1226 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1227 sp<IDrm> drm = GetDrm(env, thiz);
1228
Jeff Tinker55d26242018-10-10 16:10:43 -07001229 if (!CheckDrm(env, drm)) {
1230 return;
1231 }
1232
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001233 if (jkeysetId == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001234 jniThrowException(env, "java/lang/IllegalArgumentException",
1235 "keySetId is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001236 return;
1237 }
1238
1239 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1240
1241 status_t err = drm->removeKeys(keySetId);
1242
Robert Shih60dab872021-02-13 11:24:59 -08001243 throwExceptionAsNecessary(env, drm, err, "Failed to remove keys");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001244}
1245
1246static void android_media_MediaDrm_restoreKeys(
1247 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1248 jbyteArray jkeysetId) {
1249
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001250 sp<IDrm> drm = GetDrm(env, thiz);
1251
1252 if (!CheckSession(env, drm, jsessionId)) {
1253 return;
1254 }
1255
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001256 if (jkeysetId == NULL) {
1257 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1258 return;
1259 }
1260
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001261 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001262 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001263
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001264 status_t err = drm->restoreKeys(sessionId, keySetId);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001265
Robert Shih60dab872021-02-13 11:24:59 -08001266 throwExceptionAsNecessary(env, drm, err, "Failed to restore keys");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001267}
1268
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001269static jobject android_media_MediaDrm_queryKeyStatus(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001270 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1271 sp<IDrm> drm = GetDrm(env, thiz);
1272
1273 if (!CheckSession(env, drm, jsessionId)) {
1274 return NULL;
1275 }
1276 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1277
1278 KeyedVector<String8, String8> infoMap;
1279
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001280 status_t err = drm->queryKeyStatus(sessionId, infoMap);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001281
Robert Shih60dab872021-02-13 11:24:59 -08001282 if (throwExceptionAsNecessary(env, drm, err, "Failed to query key status")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001283 return NULL;
1284 }
1285
1286 return KeyedVectorToHashMap(env, infoMap);
1287}
1288
Jeff Tinkere4095a82014-03-04 13:17:11 -08001289static jobject android_media_MediaDrm_getProvisionRequestNative(
1290 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001291 sp<IDrm> drm = GetDrm(env, thiz);
1292
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001293 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001294 return NULL;
1295 }
1296
1297 Vector<uint8_t> request;
1298 String8 defaultUrl;
1299
Jeff Tinkere4095a82014-03-04 13:17:11 -08001300 String8 certType;
1301 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1302 certType = "X.509";
1303 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1304 certType = "none";
1305 } else {
1306 certType = "invalid";
1307 }
1308
1309 String8 certAuthority = JStringToString8(env, jcertAuthority);
1310 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001311
Robert Shih60dab872021-02-13 11:24:59 -08001312 if (throwExceptionAsNecessary(env, drm, err, "Failed to get provision request")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001313 return NULL;
1314 }
1315
1316 // Fill out return obj
1317 jclass clazz;
1318 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1319
1320 jobject provisionObj = NULL;
1321
1322 if (clazz) {
1323 provisionObj = env->AllocObject(clazz);
1324 jbyteArray jrequest = VectorToJByteArray(env, request);
1325 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1326
1327 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1328 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1329 }
1330
1331 return provisionObj;
1332}
1333
Jeff Tinkere4095a82014-03-04 13:17:11 -08001334static jobject android_media_MediaDrm_provideProvisionResponseNative(
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001335 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1336 sp<IDrm> drm = GetDrm(env, thiz);
1337
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001338 if (!CheckDrm(env, drm)) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001339 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001340 }
1341
1342 if (jresponse == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001343 jniThrowException(env, "java/lang/IllegalArgumentException",
1344 "provision response is null");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001345 return NULL;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001346 }
1347
1348 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Jeff Tinkere4095a82014-03-04 13:17:11 -08001349 Vector<uint8_t> certificate, wrappedKey;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001350
Jeff Tinkere4095a82014-03-04 13:17:11 -08001351 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1352
1353 // Fill out return obj
1354 jclass clazz = gFields.certificateClassId;
1355
1356 jobject certificateObj = NULL;
1357
1358 if (clazz && certificate.size() && wrappedKey.size()) {
1359 certificateObj = env->AllocObject(clazz);
1360 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1361 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1362
1363 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1364 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1365 }
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001366
Robert Shih60dab872021-02-13 11:24:59 -08001367 throwExceptionAsNecessary(env, drm, err, "Failed to handle provision response");
Jeff Tinkere4095a82014-03-04 13:17:11 -08001368 return certificateObj;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001369}
1370
1371static jobject android_media_MediaDrm_getSecureStops(
1372 JNIEnv *env, jobject thiz) {
1373 sp<IDrm> drm = GetDrm(env, thiz);
1374
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001375 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001376 return NULL;
1377 }
1378
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001379 List<Vector<uint8_t>> secureStops;
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001380
1381 status_t err = drm->getSecureStops(secureStops);
1382
Robert Shih60dab872021-02-13 11:24:59 -08001383 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stops")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001384 return NULL;
1385 }
1386
1387 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1388}
1389
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001390static jobject android_media_MediaDrm_getSecureStopIds(
1391 JNIEnv *env, jobject thiz) {
1392 sp<IDrm> drm = GetDrm(env, thiz);
1393
Jeff Tinker55d26242018-10-10 16:10:43 -07001394 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001395 return NULL;
1396 }
1397
Jeff Tinkerb78ee402018-11-05 15:18:53 -08001398 List<Vector<uint8_t>> secureStopIds;
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001399
1400 status_t err = drm->getSecureStopIds(secureStopIds);
1401
Robert Shih60dab872021-02-13 11:24:59 -08001402 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop Ids")) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001403 return NULL;
1404 }
1405
1406 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1407}
1408
Jeff Tinker1b51c722014-10-31 00:54:26 -07001409static jbyteArray android_media_MediaDrm_getSecureStop(
1410 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1411 sp<IDrm> drm = GetDrm(env, thiz);
1412
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001413 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001414 return NULL;
1415 }
1416
1417 Vector<uint8_t> secureStop;
1418
1419 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1420
Robert Shih60dab872021-02-13 11:24:59 -08001421 if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop")) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001422 return NULL;
1423 }
1424
1425 return VectorToJByteArray(env, secureStop);
1426}
1427
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001428static void android_media_MediaDrm_releaseSecureStops(
1429 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1430 sp<IDrm> drm = GetDrm(env, thiz);
1431
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001432 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001433 return;
1434 }
1435
1436 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1437
1438 status_t err = drm->releaseSecureStops(ssRelease);
1439
Robert Shih60dab872021-02-13 11:24:59 -08001440 throwExceptionAsNecessary(env, drm, err, "Failed to release secure stops");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001441}
1442
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001443static void android_media_MediaDrm_removeSecureStop(
1444 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1445 sp<IDrm> drm = GetDrm(env, thiz);
1446
Jeff Tinker55d26242018-10-10 16:10:43 -07001447 if (!CheckDrm(env, drm)) {
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001448 return;
1449 }
1450
1451 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1452
Robert Shih60dab872021-02-13 11:24:59 -08001453 throwExceptionAsNecessary(env, drm, err, "Failed to remove secure stop");
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001454}
1455
1456static void android_media_MediaDrm_removeAllSecureStops(
Jeff Tinker1b51c722014-10-31 00:54:26 -07001457 JNIEnv *env, jobject thiz) {
1458 sp<IDrm> drm = GetDrm(env, thiz);
1459
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001460 if (!CheckDrm(env, drm)) {
Jeff Tinker1b51c722014-10-31 00:54:26 -07001461 return;
1462 }
1463
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08001464 status_t err = drm->removeAllSecureStops();
Jeff Tinker1b51c722014-10-31 00:54:26 -07001465
Robert Shih60dab872021-02-13 11:24:59 -08001466 throwExceptionAsNecessary(env, drm, err, "Failed to remove all secure stops");
Jeff Tinker1b51c722014-10-31 00:54:26 -07001467}
1468
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001469
1470static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1471 switch(level) {
1472 case DrmPlugin::kHdcpLevelUnknown:
1473 return gHdcpLevels.kHdcpLevelUnknown;
1474 case DrmPlugin::kHdcpNone:
1475 return gHdcpLevels.kHdcpNone;
1476 case DrmPlugin::kHdcpV1:
1477 return gHdcpLevels.kHdcpV1;
1478 case DrmPlugin::kHdcpV2:
1479 return gHdcpLevels.kHdcpV2;
1480 case DrmPlugin::kHdcpV2_1:
1481 return gHdcpLevels.kHdcpV2_1;
1482 case DrmPlugin::kHdcpV2_2:
1483 return gHdcpLevels.kHdcpV2_2;
Jeff Tinkerc71c0182019-01-14 10:26:06 -08001484 case DrmPlugin::kHdcpV2_3:
1485 return gHdcpLevels.kHdcpV2_3;
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001486 case DrmPlugin::kHdcpNoOutput:
1487 return gHdcpLevels.kHdcpNoOutput;
1488 }
1489 return gHdcpLevels.kHdcpNone;
1490}
1491
1492static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1493 jobject thiz) {
1494 sp<IDrm> drm = GetDrm(env, thiz);
1495
1496 if (!CheckDrm(env, drm)) {
1497 return gHdcpLevels.kHdcpNone;
1498 }
1499
1500 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1501 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1502
1503 status_t err = drm->getHdcpLevels(&connected, &max);
1504
Robert Shih60dab872021-02-13 11:24:59 -08001505 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001506 return gHdcpLevels.kHdcpLevelUnknown;
1507 }
1508 return HdcpLevelTojint(connected);
1509}
1510
1511static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1512 jobject thiz) {
1513 sp<IDrm> drm = GetDrm(env, thiz);
1514
1515 if (!CheckDrm(env, drm)) {
1516 return gHdcpLevels.kHdcpLevelUnknown;
1517 }
1518
1519 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1520 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1521
1522 status_t err = drm->getHdcpLevels(&connected, &max);
1523
Robert Shih60dab872021-02-13 11:24:59 -08001524 if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001525 return gHdcpLevels.kHdcpLevelUnknown;
1526 }
1527 return HdcpLevelTojint(max);
1528}
1529
1530static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1531 jobject thiz) {
1532 sp<IDrm> drm = GetDrm(env, thiz);
1533
1534 if (!CheckDrm(env, drm)) {
1535 return 0;
1536 }
1537
1538 uint32_t open = 0, max = 0;
1539 status_t err = drm->getNumberOfSessions(&open, &max);
1540
Robert Shih60dab872021-02-13 11:24:59 -08001541 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001542 return 0;
1543 }
1544 return open;
1545}
1546
1547static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1548 jobject thiz) {
1549 sp<IDrm> drm = GetDrm(env, thiz);
1550
1551 if (!CheckDrm(env, drm)) {
1552 return 0;
1553 }
1554
1555 uint32_t open = 0, max = 0;
1556 status_t err = drm->getNumberOfSessions(&open, &max);
1557
Robert Shih60dab872021-02-13 11:24:59 -08001558 if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001559 return 0;
1560 }
1561 return max;
1562}
1563
1564static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1565 jobject thiz, jbyteArray jsessionId) {
1566 sp<IDrm> drm = GetDrm(env, thiz);
1567
1568 if (!CheckSession(env, drm, jsessionId)) {
1569 return gSecurityLevels.kSecurityLevelUnknown;
1570 }
1571
1572 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1573
1574 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1575
1576 status_t err = drm->getSecurityLevel(sessionId, &level);
1577
Robert Shih60dab872021-02-13 11:24:59 -08001578 if (throwExceptionAsNecessary(env, drm, err, "Failed to get security level")) {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001579 return gSecurityLevels.kSecurityLevelUnknown;
1580 }
1581
1582 switch(level) {
1583 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1584 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1585 case DrmPlugin::kSecurityLevelSwSecureDecode:
1586 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1587 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1588 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1589 case DrmPlugin::kSecurityLevelHwSecureDecode:
1590 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1591 case DrmPlugin::kSecurityLevelHwSecureAll:
1592 return gSecurityLevels.kSecurityLevelHwSecureAll;
1593 default:
1594 return gSecurityLevels.kSecurityLevelUnknown;
1595 }
1596}
1597
Jeff Tinker55d26242018-10-10 16:10:43 -07001598static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1599 JNIEnv *env, jobject thiz) {
1600 sp<IDrm> drm = GetDrm(env, thiz);
1601
1602 if (!CheckDrm(env, drm)) {
1603 return NULL;
1604 }
1605
1606 List<Vector<uint8_t> > keySetIds;
1607
1608 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1609
Robert Shih60dab872021-02-13 11:24:59 -08001610 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline key set Ids")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001611 return NULL;
1612 }
1613
1614 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1615}
1616
1617static void android_media_MediaDrm_removeOfflineLicense(
1618 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1619 sp<IDrm> drm = GetDrm(env, thiz);
1620
1621 if (!CheckDrm(env, drm)) {
1622 return;
1623 }
1624
1625 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1626
Robert Shih60dab872021-02-13 11:24:59 -08001627 throwExceptionAsNecessary(env, drm, err, "Failed to remove offline license");
Jeff Tinker55d26242018-10-10 16:10:43 -07001628}
1629
1630static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1631 jobject thiz, jbyteArray jkeySetId) {
1632 sp<IDrm> drm = GetDrm(env, thiz);
1633
1634 if (!CheckDrm(env, drm)) {
1635 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1636 }
1637
1638 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1639
1640 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1641
1642 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1643
Robert Shih60dab872021-02-13 11:24:59 -08001644 if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline license state")) {
Jeff Tinker55d26242018-10-10 16:10:43 -07001645 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1646 }
1647
1648 switch(state) {
1649 case DrmPlugin::kOfflineLicenseStateUsable:
1650 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
Jeff Tinker8de43ee2018-12-11 01:00:09 -08001651 case DrmPlugin::kOfflineLicenseStateReleased:
1652 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
Jeff Tinker55d26242018-10-10 16:10:43 -07001653 default:
1654 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1655 }
1656}
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001657
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001658static jstring android_media_MediaDrm_getPropertyString(
1659 JNIEnv *env, jobject thiz, jstring jname) {
1660 sp<IDrm> drm = GetDrm(env, thiz);
1661
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001662 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001663 return NULL;
1664 }
1665
1666 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001667 jniThrowException(env, "java/lang/IllegalArgumentException",
1668 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001669 return NULL;
1670 }
1671
1672 String8 name = JStringToString8(env, jname);
1673 String8 value;
1674
1675 status_t err = drm->getPropertyString(name, value);
1676
Robert Shih60dab872021-02-13 11:24:59 -08001677 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001678 return NULL;
1679 }
1680
1681 return env->NewStringUTF(value.string());
1682}
1683
1684static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1685 JNIEnv *env, jobject thiz, jstring jname) {
1686 sp<IDrm> drm = GetDrm(env, thiz);
1687
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001688 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001689 return NULL;
1690 }
1691
1692 if (jname == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001693 jniThrowException(env, "java/lang/IllegalArgumentException",
1694 "property name String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001695 return NULL;
1696 }
1697
1698 String8 name = JStringToString8(env, jname);
1699 Vector<uint8_t> value;
1700
1701 status_t err = drm->getPropertyByteArray(name, value);
1702
Robert Shih60dab872021-02-13 11:24:59 -08001703 if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001704 return NULL;
1705 }
1706
1707 return VectorToJByteArray(env, value);
1708}
1709
1710static void android_media_MediaDrm_setPropertyString(
1711 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1712 sp<IDrm> drm = GetDrm(env, thiz);
1713
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001714 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001715 return;
1716 }
1717
Jeff Tinkereada5372013-05-21 12:48:14 -07001718 if (jname == NULL) {
1719 jniThrowException(env, "java/lang/IllegalArgumentException",
1720 "property name String is null");
1721 return;
1722 }
1723
1724 if (jvalue == NULL) {
1725 jniThrowException(env, "java/lang/IllegalArgumentException",
1726 "property value String is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001727 return;
1728 }
1729
1730 String8 name = JStringToString8(env, jname);
1731 String8 value = JStringToString8(env, jvalue);
1732
1733 status_t err = drm->setPropertyString(name, value);
1734
Robert Shih60dab872021-02-13 11:24:59 -08001735 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001736}
1737
1738static void android_media_MediaDrm_setPropertyByteArray(
1739 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1740 sp<IDrm> drm = GetDrm(env, thiz);
1741
Jeff Tinker3eb07f42017-12-08 17:34:53 -08001742 if (!CheckDrm(env, drm)) {
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001743 return;
1744 }
1745
Jeff Tinkereada5372013-05-21 12:48:14 -07001746 if (jname == NULL) {
1747 jniThrowException(env, "java/lang/IllegalArgumentException",
1748 "property name String is null");
1749 return;
1750 }
1751
1752 if (jvalue == NULL) {
1753 jniThrowException(env, "java/lang/IllegalArgumentException",
1754 "property value byte array is null");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001755 return;
1756 }
1757
1758 String8 name = JStringToString8(env, jname);
1759 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1760
1761 status_t err = drm->setPropertyByteArray(name, value);
1762
Robert Shih60dab872021-02-13 11:24:59 -08001763 throwExceptionAsNecessary(env, drm, err, "Failed to set property");
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001764}
1765
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001766static void android_media_MediaDrm_setCipherAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001767 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001768 jstring jalgorithm) {
1769
1770 sp<IDrm> drm = GetDrm(env, jdrm);
1771
1772 if (!CheckSession(env, drm, jsessionId)) {
1773 return;
1774 }
1775
1776 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001777 jniThrowException(env, "java/lang/IllegalArgumentException",
1778 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001779 return;
1780 }
1781
1782 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1783 String8 algorithm = JStringToString8(env, jalgorithm);
1784
1785 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1786
Robert Shih60dab872021-02-13 11:24:59 -08001787 throwExceptionAsNecessary(env, drm, err, "Failed to set cipher algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001788}
1789
1790static void android_media_MediaDrm_setMacAlgorithmNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001791 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001792 jstring jalgorithm) {
1793
1794 sp<IDrm> drm = GetDrm(env, jdrm);
1795
1796 if (!CheckSession(env, drm, jsessionId)) {
1797 return;
1798 }
1799
1800 if (jalgorithm == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001801 jniThrowException(env, "java/lang/IllegalArgumentException",
1802 "algorithm String is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001803 return;
1804 }
1805
1806 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1807 String8 algorithm = JStringToString8(env, jalgorithm);
1808
1809 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1810
Robert Shih60dab872021-02-13 11:24:59 -08001811 throwExceptionAsNecessary(env, drm, err, "Failed to set mac algorithm");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001812}
1813
1814
1815static jbyteArray android_media_MediaDrm_encryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001816 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001817 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1818
1819 sp<IDrm> drm = GetDrm(env, jdrm);
1820
1821 if (!CheckSession(env, drm, jsessionId)) {
1822 return NULL;
1823 }
1824
1825 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001826 jniThrowException(env, "java/lang/IllegalArgumentException",
1827 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001828 return NULL;
1829 }
1830
1831 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1832 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1833 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1834 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1835 Vector<uint8_t> output;
1836
1837 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1838
Robert Shih60dab872021-02-13 11:24:59 -08001839 if (throwExceptionAsNecessary(env, drm, err, "Failed to encrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001840 return NULL;
1841 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001842
1843 return VectorToJByteArray(env, output);
1844}
1845
1846static jbyteArray android_media_MediaDrm_decryptNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001847 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001848 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1849
1850 sp<IDrm> drm = GetDrm(env, jdrm);
1851
1852 if (!CheckSession(env, drm, jsessionId)) {
1853 return NULL;
1854 }
1855
1856 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001857 jniThrowException(env, "java/lang/IllegalArgumentException",
1858 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001859 return NULL;
1860 }
1861
1862 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1863 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1864 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1865 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1866 Vector<uint8_t> output;
1867
1868 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
Robert Shih60dab872021-02-13 11:24:59 -08001869 if (throwExceptionAsNecessary(env, drm, err, "Failed to decrypt")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001870 return NULL;
1871 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001872
1873 return VectorToJByteArray(env, output);
1874}
1875
1876static jbyteArray android_media_MediaDrm_signNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001877 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001878 jbyteArray jkeyId, jbyteArray jmessage) {
1879
1880 sp<IDrm> drm = GetDrm(env, jdrm);
1881
1882 if (!CheckSession(env, drm, jsessionId)) {
1883 return NULL;
1884 }
1885
1886 if (jkeyId == NULL || jmessage == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001887 jniThrowException(env, "java/lang/IllegalArgumentException",
1888 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001889 return NULL;
1890 }
1891
1892 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1893 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1894 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1895 Vector<uint8_t> signature;
1896
1897 status_t err = drm->sign(sessionId, keyId, message, signature);
1898
Robert Shih60dab872021-02-13 11:24:59 -08001899 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinker8117d8f2013-08-16 13:46:02 -07001900 return NULL;
1901 }
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001902
1903 return VectorToJByteArray(env, signature);
1904}
1905
1906static jboolean android_media_MediaDrm_verifyNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001907 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001908 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1909
1910 sp<IDrm> drm = GetDrm(env, jdrm);
1911
1912 if (!CheckSession(env, drm, jsessionId)) {
1913 return false;
1914 }
1915
1916 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
Jeff Tinkereada5372013-05-21 12:48:14 -07001917 jniThrowException(env, "java/lang/IllegalArgumentException",
1918 "required argument is null");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001919 return false;
1920 }
1921
1922 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1923 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1924 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1925 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1926 bool match;
1927
1928 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1929
Robert Shih60dab872021-02-13 11:24:59 -08001930 throwExceptionAsNecessary(env, drm, err, "Failed to verify");
Jeff Tinker16b8cff2013-03-30 16:26:13 -07001931 return match;
1932}
1933
Adam Stonec06e10e2017-12-19 12:54:33 -08001934static jobject
1935android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1936{
1937 sp<IDrm> drm = GetDrm(env, thiz);
Jeff Tinker55d26242018-10-10 16:10:43 -07001938
1939 if (!CheckDrm(env, drm)) {
Adam Stonec06e10e2017-12-19 12:54:33 -08001940 return NULL;
1941 }
1942
1943 // Retrieve current metrics snapshot from drm.
Adam Stone94395c92018-01-30 12:07:00 -08001944 PersistableBundle metrics;
Robert Shihba6777e2019-11-12 13:04:59 -08001945 sp<IDrmMetricsConsumer> consumer(new DrmMetricsConsumer(&metrics));
1946 status_t err = drm->getMetrics(consumer);
Adam Stonec06e10e2017-12-19 12:54:33 -08001947 if (err != OK) {
1948 ALOGE("getMetrics failed: %d", (int)err);
1949 return (jobject) NULL;
1950 }
1951
Robert Shih4354a962019-11-10 12:09:08 -08001952 return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics);
Adam Stonec06e10e2017-12-19 12:54:33 -08001953}
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001954
Jeff Tinkere4095a82014-03-04 13:17:11 -08001955static jbyteArray android_media_MediaDrm_signRSANative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -08001956 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
Jeff Tinkere4095a82014-03-04 13:17:11 -08001957 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1958
1959 sp<IDrm> drm = GetDrm(env, jdrm);
1960
1961 if (!CheckSession(env, drm, jsessionId)) {
1962 return NULL;
1963 }
1964
1965 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1966 jniThrowException(env, "java/lang/IllegalArgumentException",
1967 "required argument is null");
1968 return NULL;
1969 }
1970
1971 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1972 String8 algorithm = JStringToString8(env, jalgorithm);
1973 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1974 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1975 Vector<uint8_t> signature;
1976
1977 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1978
Robert Shih60dab872021-02-13 11:24:59 -08001979 if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) {
Jeff Tinkere4095a82014-03-04 13:17:11 -08001980 return NULL;
1981 }
1982
1983 return VectorToJByteArray(env, signature);
1984}
1985
Robert Shih205f7a92021-01-19 21:12:10 -08001986static jboolean android_media_MediaDrm_requiresSecureDecoder(
1987 JNIEnv *env, jobject thiz, jstring jmimeType,
1988 jint jSecurityLevel) {
1989 sp<IDrm> drm = GetDrm(env, thiz);
1990 if (!CheckDrm(env, drm)) {
1991 return JNI_FALSE;
1992 }
1993
1994 String8 mimeType;
1995 if (jmimeType != NULL) {
1996 mimeType = JStringToString8(env, jmimeType);
1997 }
1998
1999 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
2000 if (securityLevel == DrmPlugin::kSecurityLevelUnknown) {
2001 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
2002 return JNI_FALSE;
2003 }
2004
Robert Shih5bb242a2021-04-28 10:04:51 -07002005 bool required = false;
2006 status_t err = OK;
Robert Shih205f7a92021-01-19 21:12:10 -08002007 if (securityLevel == DrmPlugin::kSecurityLevelMax) {
Robert Shih5bb242a2021-04-28 10:04:51 -07002008 err = drm->requiresSecureDecoder(mimeType.c_str(), &required);
2009 } else {
2010 err = drm->requiresSecureDecoder(mimeType.c_str(), securityLevel, &required);
Robert Shih205f7a92021-01-19 21:12:10 -08002011 }
Robert Shih5bb242a2021-04-28 10:04:51 -07002012 if (throwExceptionAsNecessary(env, drm, err, "Failed to query secure decoder requirement")) {
2013 return false;
2014 }
2015 return required;
Robert Shih205f7a92021-01-19 21:12:10 -08002016}
Jeff Tinkere4095a82014-03-04 13:17:11 -08002017
Robert Shih02937122021-01-20 00:05:20 -08002018static void android_media_MediaDrm_setPlaybackId(
2019 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
2020 jstring jplaybackId) {
2021 sp<IDrm> drm = GetDrm(env, thiz);
2022 if (!CheckSession(env, drm, jsessionId)) {
2023 return;
2024 }
2025
2026 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
2027
2028 String8 playbackId;
2029 if (jplaybackId != NULL) {
2030 playbackId = JStringToString8(env, jplaybackId);
2031 }
2032 status_t err = drm->setPlaybackId(sessionId, playbackId.c_str());
Robert Shih60dab872021-02-13 11:24:59 -08002033 throwExceptionAsNecessary(env, drm, err, "Failed to set playbackId");
Robert Shih02937122021-01-20 00:05:20 -08002034}
2035
Robert Shih696989f2021-02-12 23:25:16 -08002036static jobject android_media_MediaDrm_getLogMessages(
2037 JNIEnv *env, jobject thiz) {
2038 sp<IDrm> drm = GetDrm(env, thiz);
2039 if (!CheckDrm(env, drm)) {
2040 return NULL;
2041 }
2042
2043 Vector<drm::V1_4::LogMessage> logs;
2044 status_t err = drm->getLogMessages(logs);
2045 ALOGI("drm->getLogMessages %zu logs", logs.size());
Robert Shih60dab872021-02-13 11:24:59 -08002046 if (throwExceptionAsNecessary(env, drm, err, "Failed to get log messages")) {
Robert Shih696989f2021-02-12 23:25:16 -08002047 return NULL;
2048 }
2049 return hidlLogMessagesToJavaList(env, logs);
2050}
2051
Daniel Micay76f6a862015-09-19 17:31:01 -04002052static const JNINativeMethod gMethods[] = {
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002053 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
2054
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002055 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
2056
Edwin Wong4d1d84e2017-01-04 09:37:49 -08002057 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002058 (void *)android_media_MediaDrm_native_setup },
2059
Robert Shihd2e8b432019-11-21 20:27:56 -08002060 { "getSupportedCryptoSchemesNative", "()[B",
2061 (void *)android_media_MediaDrm_getSupportedCryptoSchemesNative },
2062
Jeff Tinkerd571a7c2019-01-17 17:29:30 -08002063 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002064 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
2065
Robert Shih02937122021-01-20 00:05:20 -08002066 { "openSessionNative", "(I)[B",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002067 (void *)android_media_MediaDrm_openSession },
2068
Robert Shih02937122021-01-20 00:05:20 -08002069 { "closeSessionNative", "([B)V",
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002070 (void *)android_media_MediaDrm_closeSession },
2071
Robert Shih890eb572021-01-19 08:16:39 -08002072 { "getKeyRequestNative", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002073 "Landroid/media/MediaDrm$KeyRequest;",
2074 (void *)android_media_MediaDrm_getKeyRequest },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002075
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002076 { "provideKeyResponse", "([B[B)[B",
2077 (void *)android_media_MediaDrm_provideKeyResponse },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002078
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002079 { "removeKeys", "([B)V",
2080 (void *)android_media_MediaDrm_removeKeys },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002081
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002082 { "restoreKeys", "([B[B)V",
2083 (void *)android_media_MediaDrm_restoreKeys },
2084
2085 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
2086 (void *)android_media_MediaDrm_queryKeyStatus },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002087
Jeff Tinkere4095a82014-03-04 13:17:11 -08002088 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
2089 (void *)android_media_MediaDrm_getProvisionRequestNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002090
Jeff Tinkere4095a82014-03-04 13:17:11 -08002091 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
2092 (void *)android_media_MediaDrm_provideProvisionResponseNative },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002093
2094 { "getSecureStops", "()Ljava/util/List;",
2095 (void *)android_media_MediaDrm_getSecureStops },
2096
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002097 { "getSecureStopIds", "()Ljava/util/List;",
2098 (void *)android_media_MediaDrm_getSecureStopIds },
2099
Jeff Tinker1b51c722014-10-31 00:54:26 -07002100 { "getSecureStop", "([B)[B",
2101 (void *)android_media_MediaDrm_getSecureStop },
2102
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002103 { "releaseSecureStops", "([B)V",
2104 (void *)android_media_MediaDrm_releaseSecureStops },
2105
Jeff Tinker1bfb3d22018-01-25 11:46:03 -08002106 { "removeSecureStop", "([B)V",
2107 (void *)android_media_MediaDrm_removeSecureStop },
2108
2109 { "removeAllSecureStops", "()V",
2110 (void *)android_media_MediaDrm_removeAllSecureStops },
Jeff Tinker1b51c722014-10-31 00:54:26 -07002111
Jeff Tinker3eb07f42017-12-08 17:34:53 -08002112 { "getConnectedHdcpLevel", "()I",
2113 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
2114
2115 { "getMaxHdcpLevel", "()I",
2116 (void *)android_media_MediaDrm_getMaxHdcpLevel },
2117
2118 { "getOpenSessionCount", "()I",
2119 (void *)android_media_MediaDrm_getOpenSessionCount },
2120
2121 { "getMaxSessionCount", "()I",
2122 (void *)android_media_MediaDrm_getMaxSessionCount },
2123
2124 { "getSecurityLevel", "([B)I",
2125 (void *)android_media_MediaDrm_getSecurityLevel },
2126
Jeff Tinker55d26242018-10-10 16:10:43 -07002127 { "removeOfflineLicense", "([B)V",
2128 (void *)android_media_MediaDrm_removeOfflineLicense },
2129
2130 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
2131 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
2132
2133 { "getOfflineLicenseState", "([B)I",
2134 (void *)android_media_MediaDrm_getOfflineLicenseState },
2135
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002136 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2137 (void *)android_media_MediaDrm_getPropertyString },
2138
2139 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2140 (void *)android_media_MediaDrm_getPropertyByteArray },
2141
2142 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2143 (void *)android_media_MediaDrm_setPropertyString },
2144
2145 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2146 (void *)android_media_MediaDrm_setPropertyByteArray },
Jeff Tinker16b8cff2013-03-30 16:26:13 -07002147
2148 { "setCipherAlgorithmNative",
2149 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2150 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2151
2152 { "setMacAlgorithmNative",
2153 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2154 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2155
2156 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2157 (void *)android_media_MediaDrm_encryptNative },
2158
2159 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2160 (void *)android_media_MediaDrm_decryptNative },
2161
2162 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2163 (void *)android_media_MediaDrm_signNative },
2164
2165 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2166 (void *)android_media_MediaDrm_verifyNative },
Jeff Tinkere4095a82014-03-04 13:17:11 -08002167
2168 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2169 (void *)android_media_MediaDrm_signRSANative },
Adam Stonec06e10e2017-12-19 12:54:33 -08002170
2171 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2172 (void *)android_media_MediaDrm_native_getMetrics },
Robert Shih205f7a92021-01-19 21:12:10 -08002173
2174 { "requiresSecureDecoder", "(Ljava/lang/String;I)Z",
2175 (void *)android_media_MediaDrm_requiresSecureDecoder },
Robert Shih02937122021-01-20 00:05:20 -08002176
2177 { "setPlaybackId", "([BLjava/lang/String;)V",
2178 (void *)android_media_MediaDrm_setPlaybackId },
Robert Shih696989f2021-02-12 23:25:16 -08002179
2180 { "getLogMessages", "()Ljava/util/List;",
2181 (void *)android_media_MediaDrm_getLogMessages },
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08002182};
2183
2184int register_android_media_Drm(JNIEnv *env) {
2185 return AndroidRuntime::registerNativeMethods(env,
2186 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2187}