blob: 5506f6149fa5252acfcc4d73b6bc18933ddb0708 [file] [log] [blame]
Andreas Huber8240d922012-04-04 14:06:32 -07001/*
2 * Copyright 2012, 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
Andreas Huber07ea4262012-04-11 12:21:20 -070018#define LOG_TAG "MediaCrypto-JNI"
Andreas Huber8240d922012-04-04 14:06:32 -070019#include <utils/Log.h>
20
Andreas Huber07ea4262012-04-11 12:21:20 -070021#include "android_media_MediaCrypto.h"
Andreas Huber8240d922012-04-04 14:06:32 -070022
23#include "android_runtime/AndroidRuntime.h"
24#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070025#include <nativehelper/JNIHelp.h>
Andreas Huber8240d922012-04-04 14:06:32 -070026
Jeff Tinkerdc614f82016-02-12 08:58:32 -080027#include <cutils/properties.h>
Andreas Huber8240d922012-04-04 14:06:32 -070028#include <media/stagefright/foundation/ADebug.h>
Robert Shih218b9532019-08-15 14:48:11 -070029#include <mediadrm/DrmUtils.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080030#include <mediadrm/ICrypto.h>
Andreas Huber8240d922012-04-04 14:06:32 -070031
32namespace android {
33
34struct fields_t {
35 jfieldID context;
36};
37
38static fields_t gFields;
39
40static sp<JCrypto> getCrypto(JNIEnv *env, jobject thiz) {
Ashok Bhat075e9a12014-01-06 13:45:09 +000041 return (JCrypto *)env->GetLongField(thiz, gFields.context);
Andreas Huber8240d922012-04-04 14:06:32 -070042}
43
44JCrypto::JCrypto(
45 JNIEnv *env, jobject thiz,
46 const uint8_t uuid[16], const void *initData, size_t initSize) {
47 mObject = env->NewWeakGlobalRef(thiz);
48
49 mCrypto = MakeCrypto(uuid, initData, initSize);
50}
51
52JCrypto::~JCrypto() {
Jeff Tinker94dd36c2017-05-08 19:22:06 -070053 if (mCrypto != NULL) {
54 mCrypto->destroyPlugin();
55 }
Andreas Huber8240d922012-04-04 14:06:32 -070056 mCrypto.clear();
57
58 JNIEnv *env = AndroidRuntime::getJNIEnv();
59
60 env->DeleteWeakGlobalRef(mObject);
61 mObject = NULL;
62}
63
64// static
65sp<ICrypto> JCrypto::MakeCrypto() {
Robert Shih218b9532019-08-15 14:48:11 -070066 return DrmUtils::MakeCrypto();
Andreas Huber8240d922012-04-04 14:06:32 -070067}
68
69// static
70sp<ICrypto> JCrypto::MakeCrypto(
71 const uint8_t uuid[16], const void *initData, size_t initSize) {
72 sp<ICrypto> crypto = MakeCrypto();
73
74 if (crypto == NULL) {
75 return NULL;
76 }
77
78 status_t err = crypto->createPlugin(uuid, initData, initSize);
79
80 if (err != OK) {
81 return NULL;
82 }
83
84 return crypto;
85}
86
87bool JCrypto::requiresSecureDecoderComponent(const char *mime) const {
88 if (mCrypto == NULL) {
89 return false;
90 }
91
92 return mCrypto->requiresSecureDecoderComponent(mime);
93}
94
95// static
96bool JCrypto::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
97 sp<ICrypto> crypto = MakeCrypto();
98
99 if (crypto == NULL) {
100 return false;
101 }
102
103 return crypto->isCryptoSchemeSupported(uuid);
104}
105
106status_t JCrypto::initCheck() const {
107 return mCrypto == NULL ? NO_INIT : OK;
108}
109
110// static
111sp<ICrypto> JCrypto::GetCrypto(JNIEnv *env, jobject obj) {
Andreas Huber07ea4262012-04-11 12:21:20 -0700112 jclass clazz = env->FindClass("android/media/MediaCrypto");
Andreas Huber8240d922012-04-04 14:06:32 -0700113 CHECK(clazz != NULL);
114
115 if (!env->IsInstanceOf(obj, clazz)) {
116 return NULL;
117 }
118
119 sp<JCrypto> jcrypto = getCrypto(env, obj);
120
121 if (jcrypto == NULL) {
122 return NULL;
123 }
124
125 return jcrypto->mCrypto;
126}
127
Jeff Tinker6f6ef112015-04-10 04:05:25 -0700128// JNI conversion utilities
129static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
130 Vector<uint8_t> vector;
131 size_t length = env->GetArrayLength(byteArray);
132 vector.insertAt((size_t)0, length);
133 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
134 return vector;
135}
136
Andreas Huber8240d922012-04-04 14:06:32 -0700137} // namespace android
138
139using namespace android;
140
141static sp<JCrypto> setCrypto(
142 JNIEnv *env, jobject thiz, const sp<JCrypto> &crypto) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000143 sp<JCrypto> old = (JCrypto *)env->GetLongField(thiz, gFields.context);
Andreas Huber8240d922012-04-04 14:06:32 -0700144 if (crypto != NULL) {
145 crypto->incStrong(thiz);
146 }
147 if (old != NULL) {
148 old->decStrong(thiz);
149 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000150 env->SetLongField(thiz, gFields.context, (jlong)crypto.get());
Andreas Huber8240d922012-04-04 14:06:32 -0700151
152 return old;
153}
154
Andreas Huber07ea4262012-04-11 12:21:20 -0700155static void android_media_MediaCrypto_release(JNIEnv *env, jobject thiz) {
Andreas Huber8240d922012-04-04 14:06:32 -0700156 setCrypto(env, thiz, NULL);
157}
158
Andreas Huber07ea4262012-04-11 12:21:20 -0700159static void android_media_MediaCrypto_native_init(JNIEnv *env) {
160 jclass clazz = env->FindClass("android/media/MediaCrypto");
Andreas Huber8240d922012-04-04 14:06:32 -0700161 CHECK(clazz != NULL);
162
Ashok Bhat075e9a12014-01-06 13:45:09 +0000163 gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
Andreas Huber8240d922012-04-04 14:06:32 -0700164 CHECK(gFields.context != NULL);
165}
166
Andreas Huber07ea4262012-04-11 12:21:20 -0700167static void android_media_MediaCrypto_native_setup(
Andreas Huber8240d922012-04-04 14:06:32 -0700168 JNIEnv *env, jobject thiz,
169 jbyteArray uuidObj, jbyteArray initDataObj) {
170 jsize uuidLength = env->GetArrayLength(uuidObj);
171
172 if (uuidLength != 16) {
173 jniThrowException(
174 env,
175 "java/lang/IllegalArgumentException",
176 NULL);
177 return;
178 }
179
180 jboolean isCopy;
181 jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);
182
Andreas Huber07ea4262012-04-11 12:21:20 -0700183 jsize initDataLength = 0;
184 jbyte *initData = NULL;
185
186 if (initDataObj != NULL) {
187 initDataLength = env->GetArrayLength(initDataObj);
188 initData = env->GetByteArrayElements(initDataObj, &isCopy);
189 }
Andreas Huber8240d922012-04-04 14:06:32 -0700190
191 sp<JCrypto> crypto = new JCrypto(
192 env, thiz, (const uint8_t *)uuid, initData, initDataLength);
193
194 status_t err = crypto->initCheck();
195
Andreas Huber07ea4262012-04-11 12:21:20 -0700196 if (initDataObj != NULL) {
197 env->ReleaseByteArrayElements(initDataObj, initData, 0);
198 initData = NULL;
199 }
Andreas Huber8240d922012-04-04 14:06:32 -0700200
201 env->ReleaseByteArrayElements(uuidObj, uuid, 0);
202 uuid = NULL;
203
204 if (err != OK) {
Robert Shih4b2c6412021-02-14 07:56:32 +0000205 std::string strerr(StrCryptoError(err));
206 jniThrowExceptionFmt(
Andreas Huber8240d922012-04-04 14:06:32 -0700207 env,
Andreas Huber60d610b2012-05-02 16:06:09 -0700208 "android/media/MediaCryptoException",
Robert Shih4b2c6412021-02-14 07:56:32 +0000209 "Failed to instantiate crypto object: %s", strerr.c_str());
Andreas Huber8240d922012-04-04 14:06:32 -0700210 return;
211 }
212
213 setCrypto(env,thiz, crypto);
214}
215
Andreas Huber07ea4262012-04-11 12:21:20 -0700216static void android_media_MediaCrypto_native_finalize(
Andreas Huber8240d922012-04-04 14:06:32 -0700217 JNIEnv *env, jobject thiz) {
Andreas Huber07ea4262012-04-11 12:21:20 -0700218 android_media_MediaCrypto_release(env, thiz);
Andreas Huber8240d922012-04-04 14:06:32 -0700219}
220
Andreas Huber60d610b2012-05-02 16:06:09 -0700221static jboolean android_media_MediaCrypto_isCryptoSchemeSupportedNative(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800222 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj) {
Andreas Huber8240d922012-04-04 14:06:32 -0700223 jsize uuidLength = env->GetArrayLength(uuidObj);
224
225 if (uuidLength != 16) {
226 jniThrowException(
227 env,
228 "java/lang/IllegalArgumentException",
229 NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000230 return JNI_FALSE;
Andreas Huber8240d922012-04-04 14:06:32 -0700231 }
232
233 jboolean isCopy;
234 jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);
235
236 bool result = JCrypto::IsCryptoSchemeSupported((const uint8_t *)uuid);
237
238 env->ReleaseByteArrayElements(uuidObj, uuid, 0);
239 uuid = NULL;
240
Ashok Bhat075e9a12014-01-06 13:45:09 +0000241 return result ? JNI_TRUE : JNI_FALSE;
Andreas Huber8240d922012-04-04 14:06:32 -0700242}
243
Andreas Huber07ea4262012-04-11 12:21:20 -0700244static jboolean android_media_MediaCrypto_requiresSecureDecoderComponent(
Andreas Huber8240d922012-04-04 14:06:32 -0700245 JNIEnv *env, jobject thiz, jstring mimeObj) {
246 if (mimeObj == NULL) {
247 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000248 return JNI_FALSE;
Andreas Huber8240d922012-04-04 14:06:32 -0700249 }
250
251 sp<JCrypto> crypto = getCrypto(env, thiz);
252
253 if (crypto == NULL) {
254 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000255 return JNI_FALSE;
Andreas Huber8240d922012-04-04 14:06:32 -0700256 }
257
258 const char *mime = env->GetStringUTFChars(mimeObj, NULL);
259
260 if (mime == NULL) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000261 return JNI_FALSE;
Andreas Huber8240d922012-04-04 14:06:32 -0700262 }
263
264 bool result = crypto->requiresSecureDecoderComponent(mime);
265
266 env->ReleaseStringUTFChars(mimeObj, mime);
267 mime = NULL;
268
Ashok Bhat075e9a12014-01-06 13:45:09 +0000269 return result ? JNI_TRUE : JNI_FALSE;
Andreas Huber8240d922012-04-04 14:06:32 -0700270}
271
Jeff Tinker6f6ef112015-04-10 04:05:25 -0700272static void android_media_MediaCrypto_setMediaDrmSession(
273 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
274 if (jsessionId == NULL) {
275 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
276 return;
277 }
278
279 sp<ICrypto> crypto = JCrypto::GetCrypto(env, thiz);
280
281 if (crypto == NULL) {
282 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
283 return;
284 }
285
286 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
287
288 status_t err = crypto->setMediaDrmSession(sessionId);
289
Jeff Tinker025af8b2015-06-01 14:17:06 -0700290 if (err != OK) {
291 String8 msg("setMediaDrmSession failed");
292 if (err == ERROR_DRM_SESSION_NOT_OPENED) {
293 msg += ": session not opened";
294 } else if (err == ERROR_UNSUPPORTED) {
295 msg += ": not supported by this crypto scheme";
296 } else if (err == NO_INIT) {
297 msg += ": crypto plugin not initialized";
298 } else {
Robert Shih4b2c6412021-02-14 07:56:32 +0000299 std::string strerr(StrCryptoError(err));
300 msg.appendFormat(": general failure (%s)", strerr.c_str());
Jeff Tinker025af8b2015-06-01 14:17:06 -0700301 }
Tomasz Wasilczyk3815d342023-08-10 23:54:44 +0000302 jniThrowException(env, "android/media/MediaCryptoException", msg.c_str());
Jeff Tinker6f6ef112015-04-10 04:05:25 -0700303 }
Jeff Tinker6f6ef112015-04-10 04:05:25 -0700304}
305
Daniel Micay76f6a862015-09-19 17:31:01 -0400306static const JNINativeMethod gMethods[] = {
Andreas Huber07ea4262012-04-11 12:21:20 -0700307 { "release", "()V", (void *)android_media_MediaCrypto_release },
308 { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
Andreas Huber8240d922012-04-04 14:06:32 -0700309
310 { "native_setup", "([B[B)V",
Andreas Huber07ea4262012-04-11 12:21:20 -0700311 (void *)android_media_MediaCrypto_native_setup },
Andreas Huber8240d922012-04-04 14:06:32 -0700312
313 { "native_finalize", "()V",
Andreas Huber07ea4262012-04-11 12:21:20 -0700314 (void *)android_media_MediaCrypto_native_finalize },
Andreas Huber8240d922012-04-04 14:06:32 -0700315
Andreas Huber60d610b2012-05-02 16:06:09 -0700316 { "isCryptoSchemeSupportedNative", "([B)Z",
317 (void *)android_media_MediaCrypto_isCryptoSchemeSupportedNative },
Andreas Huber8240d922012-04-04 14:06:32 -0700318
319 { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z",
Andreas Huber07ea4262012-04-11 12:21:20 -0700320 (void *)android_media_MediaCrypto_requiresSecureDecoderComponent },
Jeff Tinker6f6ef112015-04-10 04:05:25 -0700321
322 { "setMediaDrmSession", "([B)V",
323 (void *)android_media_MediaCrypto_setMediaDrmSession },
Andreas Huber8240d922012-04-04 14:06:32 -0700324};
325
326int register_android_media_Crypto(JNIEnv *env) {
327 return AndroidRuntime::registerNativeMethods(env,
Andreas Huber07ea4262012-04-11 12:21:20 -0700328 "android/media/MediaCrypto", gMethods, NELEM(gMethods));
Andreas Huber8240d922012-04-04 14:06:32 -0700329}
330