blob: e77e855ce53a573a61906ef547f8480f9345f8ea [file] [log] [blame]
Chong Zhangd5927ae2017-01-03 11:07:18 -08001/*
2 * Copyright 2017, 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 "MediaDescrambler-JNI"
19#include <utils/Log.h>
20
21#include "android_media_MediaDescrambler.h"
22#include "android_runtime/AndroidRuntime.h"
Chong Zhang2659c2f2017-04-27 13:18:20 -070023#include "android_os_HwRemoteBinder.h"
Steven Moreland60cc6c02017-08-25 15:49:25 -070024#include <nativehelper/JNIHelp.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080025
Chong Zhang2659c2f2017-04-27 13:18:20 -070026#include <android/hardware/cas/native/1.0/BpHwDescrambler.h>
27#include <android/hardware/cas/native/1.0/BnHwDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080028#include <binder/MemoryDealer.h>
Chong Zhang2659c2f2017-04-27 13:18:20 -070029#include <hidl/HidlSupport.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080030#include <media/stagefright/foundation/ADebug.h>
31#include <nativehelper/ScopedLocalRef.h>
32
33namespace android {
Chong Zhang2659c2f2017-04-27 13:18:20 -070034
35using hardware::hidl_handle;
Chong Zhangd5927ae2017-01-03 11:07:18 -080036
37struct fields_t {
38 jfieldID context;
39};
40
41static fields_t gFields;
42
43static sp<JDescrambler> getDescrambler(JNIEnv *env, jobject thiz) {
44 return (JDescrambler *)env->GetLongField(thiz, gFields.context);
45}
46
47static void setDescrambler(
48 JNIEnv *env, jobject thiz, const sp<JDescrambler> &descrambler) {
49 sp<JDescrambler> old = (JDescrambler *)env->GetLongField(thiz, gFields.context);
50 if (descrambler != NULL) {
51 descrambler->incStrong(thiz);
52 }
53 if (old != NULL) {
54 old->decStrong(thiz);
55 }
56 env->SetLongField(thiz, gFields.context, (jlong)descrambler.get());
57}
58
59static status_t getBufferAndSize(
Chong Zhangaddc39e2017-03-31 14:52:52 -070060 JNIEnv *env, jobject byteBuf, jint offset, jint limit, size_t length,
Chong Zhangd5927ae2017-01-03 11:07:18 -080061 void **outPtr, jbyteArray *outByteArray) {
62 void *ptr = env->GetDirectBufferAddress(byteBuf);
63
Chong Zhangd5927ae2017-01-03 11:07:18 -080064 jbyteArray byteArray = NULL;
65
66 ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
67 CHECK(byteBufClass.get() != NULL);
68
69 if (ptr == NULL) {
70 jmethodID arrayID =
71 env->GetMethodID(byteBufClass.get(), "array", "()[B");
72 CHECK(arrayID != NULL);
73
74 byteArray =
75 (jbyteArray)env->CallObjectMethod(byteBuf, arrayID);
76
77 if (byteArray == NULL) {
78 return INVALID_OPERATION;
79 }
80
81 jboolean isCopy;
82 ptr = env->GetByteArrayElements(byteArray, &isCopy);
Chong Zhangd5927ae2017-01-03 11:07:18 -080083 }
84
Chong Zhangaddc39e2017-03-31 14:52:52 -070085 if ((jint)length + offset > limit) {
Chong Zhangd5927ae2017-01-03 11:07:18 -080086 if (byteArray != NULL) {
87 env->ReleaseByteArrayElements(byteArray, (jbyte *)ptr, 0);
88 }
89
90 return -ERANGE;
91 }
92
93 *outPtr = ptr;
94 *outByteArray = byteArray;
95
96 return OK;
97}
98
99JDescrambler::JDescrambler(JNIEnv *env, jobject descramblerBinderObj) {
Chong Zhang2659c2f2017-04-27 13:18:20 -0700100 mDescrambler = GetDescrambler(env, descramblerBinderObj);
101 if (mDescrambler == NULL) {
102 jniThrowException(env, "java/lang/NullPointerException", NULL);
Chong Zhangd5927ae2017-01-03 11:07:18 -0800103 }
104}
105
106JDescrambler::~JDescrambler() {
107 // Don't call release() here, it's called by Java class
108 mDescrambler.clear();
109 mMem.clear();
110 mDealer.clear();
111}
112
Chong Zhang2659c2f2017-04-27 13:18:20 -0700113// static
114sp<IDescrambler> JDescrambler::GetDescrambler(JNIEnv *env, jobject obj) {
115 if (obj != NULL) {
116 sp<hardware::IBinder> hwBinder =
117 JHwRemoteBinder::GetNativeContext(env, obj)->getBinder();
118
119 if (hwBinder != NULL) {
120 return hardware::fromBinder<
121 IDescrambler, BpHwDescrambler, BnHwDescrambler>(hwBinder);
122 }
123 }
124 return NULL;
125}
126
127bool JDescrambler::ensureBufferCapacity(size_t neededSize) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800128 if (mMem != NULL && mMem->size() >= neededSize) {
Chong Zhang2659c2f2017-04-27 13:18:20 -0700129 return true;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800130 }
131
132 ALOGV("ensureBufferCapacity: current size %zu, new size %zu",
133 mMem == NULL ? 0 : mMem->size(), neededSize);
134
135 size_t alignment = MemoryDealer::getAllocationAlignment();
136 neededSize = (neededSize + (alignment - 1)) & ~(alignment - 1);
137 // Align to multiples of 64K.
138 neededSize = (neededSize + 65535) & ~65535;
139 mDealer = new MemoryDealer(neededSize, "JDescrambler");
140 mMem = mDealer->allocate(neededSize);
Chong Zhang2659c2f2017-04-27 13:18:20 -0700141
142 ssize_t offset;
143 size_t size;
144 sp<IMemoryHeap> heap = mMem->getMemory(&offset, &size);
145 if (heap == NULL) {
146 return false;
147 }
148
149 native_handle_t* nativeHandle = native_handle_create(1, 0);
150 if (!nativeHandle) {
151 ALOGE("ensureBufferCapacity: failed to create native handle");
152 return false;
153 }
154 nativeHandle->data[0] = heap->getHeapID();
155 mDescramblerSrcBuffer.heapBase = hidl_memory("ashmem",
156 hidl_handle(nativeHandle), heap->getSize());
157 mDescramblerSrcBuffer.offset = (uint64_t) offset;
158 mDescramblerSrcBuffer.size = (uint64_t) size;
159 return true;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800160}
161
Chong Zhang2659c2f2017-04-27 13:18:20 -0700162status_t JDescrambler::descramble(
Chong Zhangd5927ae2017-01-03 11:07:18 -0800163 jbyte key,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800164 ssize_t totalLength,
Chong Zhang2659c2f2017-04-27 13:18:20 -0700165 const hidl_vec<SubSample>& subSamples,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800166 const void *srcPtr,
167 jint srcOffset,
168 void *dstPtr,
Chong Zhangdadee0c2017-03-14 10:05:36 -0700169 jint dstOffset,
Chong Zhang2659c2f2017-04-27 13:18:20 -0700170 Status *status,
171 uint32_t *bytesWritten,
172 hidl_string *detailedError) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800173 // TODO: IDescrambler::descramble() is re-entrant, however because we
174 // only have 1 shared mem buffer, we can only do 1 descramble at a time.
175 // Concurrency might be improved by allowing on-demand allocation of up
176 // to 2 shared mem buffers.
177 Mutex::Autolock autolock(mSharedMemLock);
178
Chong Zhang2659c2f2017-04-27 13:18:20 -0700179 if (!ensureBufferCapacity(totalLength)) {
180 return NO_MEMORY;
181 }
Chong Zhangd5927ae2017-01-03 11:07:18 -0800182
183 memcpy(mMem->pointer(),
184 (const void*)((const uint8_t*)srcPtr + srcOffset), totalLength);
185
Chong Zhang2659c2f2017-04-27 13:18:20 -0700186 DestinationBuffer dstBuffer;
187 dstBuffer.type = BufferType::SHARED_MEMORY;
188 dstBuffer.nonsecureMemory = mDescramblerSrcBuffer;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800189
Chong Zhang2659c2f2017-04-27 13:18:20 -0700190 auto err = mDescrambler->descramble(
191 (ScramblingControl) key,
192 subSamples,
193 mDescramblerSrcBuffer,
194 0,
195 dstBuffer,
196 0,
197 [&status, &bytesWritten, &detailedError] (
198 Status _status, uint32_t _bytesWritten,
199 const hidl_string& _detailedError) {
200 *status = _status;
201 *bytesWritten = _bytesWritten;
202 *detailedError = _detailedError;
203 });
Chong Zhangd5927ae2017-01-03 11:07:18 -0800204
Chong Zhang2659c2f2017-04-27 13:18:20 -0700205 if (!err.isOk()) {
206 return FAILED_TRANSACTION;
207 }
208
209 if (*status == Status::OK) {
210 if (*bytesWritten > 0 && (ssize_t) *bytesWritten <= totalLength) {
211 memcpy((void*)((uint8_t*)dstPtr + dstOffset), mMem->pointer(), *bytesWritten);
212 } else {
213 // status seems OK but bytesWritten is invalid, we really
214 // have no idea what is wrong.
215 *status = Status::ERROR_CAS_UNKNOWN;
Chong Zhangdadee0c2017-03-14 10:05:36 -0700216 }
Chong Zhangd5927ae2017-01-03 11:07:18 -0800217 }
Chong Zhang2659c2f2017-04-27 13:18:20 -0700218 return OK;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800219}
220
221} // namespace android
222
223using namespace android;
224
225static void android_media_MediaDescrambler_native_release(JNIEnv *env, jobject thiz) {
226 setDescrambler(env, thiz, NULL);
227}
228
229static void android_media_MediaDescrambler_native_init(JNIEnv *env) {
230 ScopedLocalRef<jclass> clazz(
231 env, env->FindClass("android/media/MediaDescrambler"));
232 CHECK(clazz.get() != NULL);
233
234 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
235 CHECK(gFields.context != NULL);
236}
237
238static void android_media_MediaDescrambler_native_setup(
239 JNIEnv *env, jobject thiz, jobject descramblerBinderObj) {
240 setDescrambler(env, thiz, new JDescrambler(env, descramblerBinderObj));
241}
242
243static ssize_t getSubSampleInfo(JNIEnv *env, jint numSubSamples,
244 jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
Chong Zhang2659c2f2017-04-27 13:18:20 -0700245 hidl_vec<SubSample> *outSubSamples) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800246
Chong Zhang2659c2f2017-04-27 13:18:20 -0700247 if (numSubSamples <= 0 ||
248 numSubSamples >= (signed)(INT32_MAX / sizeof(SubSample))) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800249 // subSamples array may silently overflow if number of samples are
250 // too large. Use INT32_MAX as maximum allocation size may be less
251 // than SIZE_MAX on some platforms.
252 ALOGE("numSubSamples is invalid!");
253 return -1;
254 }
255
256 jboolean isCopy;
257 ssize_t totalSize = 0;
258
259 jint *numBytesOfClearData =
260 (numBytesOfClearDataObj == NULL)
261 ? NULL
262 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
263
264 jint *numBytesOfEncryptedData =
265 (numBytesOfEncryptedDataObj == NULL)
266 ? NULL
267 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
268
Chong Zhang2659c2f2017-04-27 13:18:20 -0700269 outSubSamples->resize(numSubSamples);
270 SubSample *subSamples = outSubSamples->data();
Chong Zhangd5927ae2017-01-03 11:07:18 -0800271 if (subSamples == NULL) {
272 ALOGE("Failed to allocate SubSample array!");
273 return -1;
274 }
275
276 for (jint i = 0; i < numSubSamples; ++i) {
Chong Zhang2659c2f2017-04-27 13:18:20 -0700277 subSamples[i].numBytesOfClearData =
Chong Zhangd5927ae2017-01-03 11:07:18 -0800278 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
279
Chong Zhang2659c2f2017-04-27 13:18:20 -0700280 subSamples[i].numBytesOfEncryptedData =
Chong Zhangd5927ae2017-01-03 11:07:18 -0800281 (numBytesOfEncryptedData == NULL)
282 ? 0 : numBytesOfEncryptedData[i];
283
Chong Zhang2659c2f2017-04-27 13:18:20 -0700284 totalSize += subSamples[i].numBytesOfClearData +
285 subSamples[i].numBytesOfEncryptedData;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800286 }
287
288 if (numBytesOfEncryptedData != NULL) {
289 env->ReleaseIntArrayElements(
290 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
291 numBytesOfEncryptedData = NULL;
292 }
293
294 if (numBytesOfClearData != NULL) {
295 env->ReleaseIntArrayElements(
296 numBytesOfClearDataObj, numBytesOfClearData, 0);
297 numBytesOfClearData = NULL;
298 }
299
Chong Zhangdadee0c2017-03-14 10:05:36 -0700300 if (totalSize < 0) {
Chong Zhangdadee0c2017-03-14 10:05:36 -0700301 return -1;
302 }
303
Chong Zhangd5927ae2017-01-03 11:07:18 -0800304 return totalSize;
305}
306
Chong Zhangdadee0c2017-03-14 10:05:36 -0700307static jthrowable createServiceSpecificException(
308 JNIEnv *env, int serviceSpecificError, const char *msg) {
309 if (env->ExceptionCheck()) {
310 ALOGW("Discarding pending exception");
311 env->ExceptionDescribe();
312 env->ExceptionClear();
313 }
314
315 ScopedLocalRef<jclass> clazz(
316 env, env->FindClass("android/os/ServiceSpecificException"));
317 CHECK(clazz.get() != NULL);
318
319 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
320 CHECK(ctor != NULL);
321
322 ScopedLocalRef<jstring> msgObj(
323 env, env->NewStringUTF(msg != NULL ?
324 msg : String8::format("Error %#x", serviceSpecificError)));
325
326 return (jthrowable)env->NewObject(
327 clazz.get(), ctor, serviceSpecificError, msgObj.get());
328}
329
Chong Zhangd5927ae2017-01-03 11:07:18 -0800330static jint android_media_MediaDescrambler_native_descramble(
331 JNIEnv *env, jobject thiz, jbyte key, jint numSubSamples,
332 jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
Chong Zhangaddc39e2017-03-31 14:52:52 -0700333 jobject srcBuf, jint srcOffset, jint srcLimit,
334 jobject dstBuf, jint dstOffset, jint dstLimit) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800335 sp<JDescrambler> descrambler = getDescrambler(env, thiz);
336 if (descrambler == NULL) {
Chong Zhang2659c2f2017-04-27 13:18:20 -0700337 jniThrowException(env, "java/lang/IllegalStateException",
338 "Invalid descrambler object!");
Chong Zhangd5927ae2017-01-03 11:07:18 -0800339 return -1;
340 }
341
Chong Zhang2659c2f2017-04-27 13:18:20 -0700342 hidl_vec<SubSample> subSamples;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800343 ssize_t totalLength = getSubSampleInfo(
344 env, numSubSamples, numBytesOfClearDataObj,
345 numBytesOfEncryptedDataObj, &subSamples);
346 if (totalLength < 0) {
347 jniThrowException(env, "java/lang/IllegalArgumentException",
Chong Zhangaddc39e2017-03-31 14:52:52 -0700348 "Invalid subsample info!");
Chong Zhangd5927ae2017-01-03 11:07:18 -0800349 return -1;
350 }
351
Chong Zhangd5927ae2017-01-03 11:07:18 -0800352 void *srcPtr = NULL, *dstPtr = NULL;
353 jbyteArray srcArray = NULL, dstArray = NULL;
354 status_t err = getBufferAndSize(
Chong Zhangaddc39e2017-03-31 14:52:52 -0700355 env, srcBuf, srcOffset, srcLimit, totalLength, &srcPtr, &srcArray);
Chong Zhangd5927ae2017-01-03 11:07:18 -0800356
357 if (err == OK) {
358 if (dstBuf == NULL) {
359 dstPtr = srcPtr;
360 } else {
361 err = getBufferAndSize(
Chong Zhangaddc39e2017-03-31 14:52:52 -0700362 env, dstBuf, dstOffset, dstLimit, totalLength, &dstPtr, &dstArray);
Chong Zhangd5927ae2017-01-03 11:07:18 -0800363 }
364 }
Chong Zhangaddc39e2017-03-31 14:52:52 -0700365
366 if (err != OK) {
367 jniThrowException(env, "java/lang/IllegalArgumentException",
368 "Invalid buffer offset and/or size for subsamples!");
369 return -1;
370 }
371
Chong Zhangdadee0c2017-03-14 10:05:36 -0700372 Status status;
Chong Zhang2659c2f2017-04-27 13:18:20 -0700373 uint32_t bytesWritten;
374 hidl_string detailedError;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800375
Chong Zhang2659c2f2017-04-27 13:18:20 -0700376 err = descrambler->descramble(
377 key, totalLength, subSamples,
378 srcPtr, srcOffset, dstPtr, dstOffset,
379 &status, &bytesWritten, &detailedError);
380
381 // Release byte array before throwing
Chong Zhangd5927ae2017-01-03 11:07:18 -0800382 if (srcArray != NULL) {
383 env->ReleaseByteArrayElements(srcArray, (jbyte *)srcPtr, 0);
384 }
385 if (dstArray != NULL) {
386 env->ReleaseByteArrayElements(dstArray, (jbyte *)dstPtr, 0);
387 }
Chong Zhangdadee0c2017-03-14 10:05:36 -0700388
Chong Zhang2659c2f2017-04-27 13:18:20 -0700389 if (err == NO_MEMORY) {
390 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
391 } else if (err == FAILED_TRANSACTION) {
392 jniThrowException(env, "android/os/RemoteException", NULL);
393 } else if (status != Status::OK) {
394 // Throw ServiceSpecific with cas error code and detailed msg,
395 // which will be re-thrown as MediaCasStateException.
396 env->Throw(createServiceSpecificException(
397 env, (int) status, detailedError.c_str()));
Chong Zhangdadee0c2017-03-14 10:05:36 -0700398 }
Chong Zhang2659c2f2017-04-27 13:18:20 -0700399 return bytesWritten;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800400}
401
402static const JNINativeMethod gMethods[] = {
403 { "native_release", "()V",
404 (void *)android_media_MediaDescrambler_native_release },
405 { "native_init", "()V",
406 (void *)android_media_MediaDescrambler_native_init },
Chong Zhang2659c2f2017-04-27 13:18:20 -0700407 { "native_setup", "(Landroid/os/IHwBinder;)V",
Chong Zhangd5927ae2017-01-03 11:07:18 -0800408 (void *)android_media_MediaDescrambler_native_setup },
Chong Zhangaddc39e2017-03-31 14:52:52 -0700409 { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I",
Chong Zhangd5927ae2017-01-03 11:07:18 -0800410 (void *)android_media_MediaDescrambler_native_descramble },
411};
412
413int register_android_media_Descrambler(JNIEnv *env) {
414 return AndroidRuntime::registerNativeMethods(env,
415 "android/media/MediaDescrambler", gMethods, NELEM(gMethods));
416}
417