blob: add4746322b8da48845df63845398542fd29846d [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 Zhangf98fc1c2018-02-13 17:55:34 -080030#include <hidlmemory/FrameworkUtils.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080031#include <media/stagefright/foundation/ADebug.h>
32#include <nativehelper/ScopedLocalRef.h>
33
34namespace android {
Chong Zhang2659c2f2017-04-27 13:18:20 -070035
Chong Zhangf98fc1c2018-02-13 17:55:34 -080036using hardware::fromHeap;
Chong Zhangd5927ae2017-01-03 11:07:18 -080037
38struct fields_t {
39 jfieldID context;
40};
41
42static fields_t gFields;
43
44static sp<JDescrambler> getDescrambler(JNIEnv *env, jobject thiz) {
45 return (JDescrambler *)env->GetLongField(thiz, gFields.context);
46}
47
48static void setDescrambler(
49 JNIEnv *env, jobject thiz, const sp<JDescrambler> &descrambler) {
50 sp<JDescrambler> old = (JDescrambler *)env->GetLongField(thiz, gFields.context);
51 if (descrambler != NULL) {
52 descrambler->incStrong(thiz);
53 }
54 if (old != NULL) {
55 old->decStrong(thiz);
56 }
57 env->SetLongField(thiz, gFields.context, (jlong)descrambler.get());
58}
59
60static status_t getBufferAndSize(
Chong Zhangaddc39e2017-03-31 14:52:52 -070061 JNIEnv *env, jobject byteBuf, jint offset, jint limit, size_t length,
Chong Zhangd5927ae2017-01-03 11:07:18 -080062 void **outPtr, jbyteArray *outByteArray) {
63 void *ptr = env->GetDirectBufferAddress(byteBuf);
64
Chong Zhangd5927ae2017-01-03 11:07:18 -080065 jbyteArray byteArray = NULL;
66
67 ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
68 CHECK(byteBufClass.get() != NULL);
69
70 if (ptr == NULL) {
71 jmethodID arrayID =
72 env->GetMethodID(byteBufClass.get(), "array", "()[B");
73 CHECK(arrayID != NULL);
74
75 byteArray =
76 (jbyteArray)env->CallObjectMethod(byteBuf, arrayID);
77
78 if (byteArray == NULL) {
79 return INVALID_OPERATION;
80 }
81
82 jboolean isCopy;
83 ptr = env->GetByteArrayElements(byteArray, &isCopy);
Chong Zhangd5927ae2017-01-03 11:07:18 -080084 }
85
Chong Zhangaddc39e2017-03-31 14:52:52 -070086 if ((jint)length + offset > limit) {
Chong Zhangd5927ae2017-01-03 11:07:18 -080087 if (byteArray != NULL) {
88 env->ReleaseByteArrayElements(byteArray, (jbyte *)ptr, 0);
89 }
90
91 return -ERANGE;
92 }
93
94 *outPtr = ptr;
95 *outByteArray = byteArray;
96
97 return OK;
98}
99
100JDescrambler::JDescrambler(JNIEnv *env, jobject descramblerBinderObj) {
Chong Zhang2659c2f2017-04-27 13:18:20 -0700101 mDescrambler = GetDescrambler(env, descramblerBinderObj);
102 if (mDescrambler == NULL) {
103 jniThrowException(env, "java/lang/NullPointerException", NULL);
Chong Zhangd5927ae2017-01-03 11:07:18 -0800104 }
105}
106
107JDescrambler::~JDescrambler() {
108 // Don't call release() here, it's called by Java class
109 mDescrambler.clear();
110 mMem.clear();
111 mDealer.clear();
112}
113
Chong Zhang2659c2f2017-04-27 13:18:20 -0700114// static
115sp<IDescrambler> JDescrambler::GetDescrambler(JNIEnv *env, jobject obj) {
116 if (obj != NULL) {
117 sp<hardware::IBinder> hwBinder =
118 JHwRemoteBinder::GetNativeContext(env, obj)->getBinder();
119
120 if (hwBinder != NULL) {
121 return hardware::fromBinder<
122 IDescrambler, BpHwDescrambler, BnHwDescrambler>(hwBinder);
123 }
124 }
125 return NULL;
126}
127
128bool JDescrambler::ensureBufferCapacity(size_t neededSize) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800129 if (mMem != NULL && mMem->size() >= neededSize) {
Chong Zhang2659c2f2017-04-27 13:18:20 -0700130 return true;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800131 }
132
133 ALOGV("ensureBufferCapacity: current size %zu, new size %zu",
134 mMem == NULL ? 0 : mMem->size(), neededSize);
135
136 size_t alignment = MemoryDealer::getAllocationAlignment();
137 neededSize = (neededSize + (alignment - 1)) & ~(alignment - 1);
138 // Align to multiples of 64K.
139 neededSize = (neededSize + 65535) & ~65535;
140 mDealer = new MemoryDealer(neededSize, "JDescrambler");
141 mMem = mDealer->allocate(neededSize);
Chong Zhang2659c2f2017-04-27 13:18:20 -0700142
143 ssize_t offset;
144 size_t size;
145 sp<IMemoryHeap> heap = mMem->getMemory(&offset, &size);
146 if (heap == NULL) {
147 return false;
148 }
149
Chong Zhangf98fc1c2018-02-13 17:55:34 -0800150 mHidlMemory = fromHeap(heap);
151 mDescramblerSrcBuffer.heapBase = *mHidlMemory;
Chong Zhang2659c2f2017-04-27 13:18:20 -0700152 mDescramblerSrcBuffer.offset = (uint64_t) offset;
153 mDescramblerSrcBuffer.size = (uint64_t) size;
154 return true;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800155}
156
Chong Zhang2659c2f2017-04-27 13:18:20 -0700157status_t JDescrambler::descramble(
Chong Zhangd5927ae2017-01-03 11:07:18 -0800158 jbyte key,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800159 ssize_t totalLength,
Chong Zhang2659c2f2017-04-27 13:18:20 -0700160 const hidl_vec<SubSample>& subSamples,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800161 const void *srcPtr,
162 jint srcOffset,
163 void *dstPtr,
Chong Zhangdadee0c2017-03-14 10:05:36 -0700164 jint dstOffset,
Chong Zhang2659c2f2017-04-27 13:18:20 -0700165 Status *status,
166 uint32_t *bytesWritten,
167 hidl_string *detailedError) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800168 // TODO: IDescrambler::descramble() is re-entrant, however because we
169 // only have 1 shared mem buffer, we can only do 1 descramble at a time.
170 // Concurrency might be improved by allowing on-demand allocation of up
171 // to 2 shared mem buffers.
172 Mutex::Autolock autolock(mSharedMemLock);
173
Chong Zhang2659c2f2017-04-27 13:18:20 -0700174 if (!ensureBufferCapacity(totalLength)) {
175 return NO_MEMORY;
176 }
Chong Zhangd5927ae2017-01-03 11:07:18 -0800177
178 memcpy(mMem->pointer(),
179 (const void*)((const uint8_t*)srcPtr + srcOffset), totalLength);
180
Chong Zhang2659c2f2017-04-27 13:18:20 -0700181 DestinationBuffer dstBuffer;
182 dstBuffer.type = BufferType::SHARED_MEMORY;
183 dstBuffer.nonsecureMemory = mDescramblerSrcBuffer;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800184
Chong Zhang2659c2f2017-04-27 13:18:20 -0700185 auto err = mDescrambler->descramble(
186 (ScramblingControl) key,
187 subSamples,
188 mDescramblerSrcBuffer,
189 0,
190 dstBuffer,
191 0,
192 [&status, &bytesWritten, &detailedError] (
193 Status _status, uint32_t _bytesWritten,
194 const hidl_string& _detailedError) {
195 *status = _status;
196 *bytesWritten = _bytesWritten;
197 *detailedError = _detailedError;
198 });
Chong Zhangd5927ae2017-01-03 11:07:18 -0800199
Chong Zhang2659c2f2017-04-27 13:18:20 -0700200 if (!err.isOk()) {
201 return FAILED_TRANSACTION;
202 }
203
204 if (*status == Status::OK) {
205 if (*bytesWritten > 0 && (ssize_t) *bytesWritten <= totalLength) {
206 memcpy((void*)((uint8_t*)dstPtr + dstOffset), mMem->pointer(), *bytesWritten);
207 } else {
208 // status seems OK but bytesWritten is invalid, we really
209 // have no idea what is wrong.
210 *status = Status::ERROR_CAS_UNKNOWN;
Chong Zhangdadee0c2017-03-14 10:05:36 -0700211 }
Chong Zhangd5927ae2017-01-03 11:07:18 -0800212 }
Chong Zhang2659c2f2017-04-27 13:18:20 -0700213 return OK;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800214}
215
216} // namespace android
217
218using namespace android;
219
220static void android_media_MediaDescrambler_native_release(JNIEnv *env, jobject thiz) {
221 setDescrambler(env, thiz, NULL);
222}
223
224static void android_media_MediaDescrambler_native_init(JNIEnv *env) {
225 ScopedLocalRef<jclass> clazz(
226 env, env->FindClass("android/media/MediaDescrambler"));
227 CHECK(clazz.get() != NULL);
228
229 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
230 CHECK(gFields.context != NULL);
231}
232
233static void android_media_MediaDescrambler_native_setup(
234 JNIEnv *env, jobject thiz, jobject descramblerBinderObj) {
235 setDescrambler(env, thiz, new JDescrambler(env, descramblerBinderObj));
236}
237
238static ssize_t getSubSampleInfo(JNIEnv *env, jint numSubSamples,
239 jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
Chong Zhang2659c2f2017-04-27 13:18:20 -0700240 hidl_vec<SubSample> *outSubSamples) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800241
Chong Zhang2659c2f2017-04-27 13:18:20 -0700242 if (numSubSamples <= 0 ||
243 numSubSamples >= (signed)(INT32_MAX / sizeof(SubSample))) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800244 // subSamples array may silently overflow if number of samples are
245 // too large. Use INT32_MAX as maximum allocation size may be less
246 // than SIZE_MAX on some platforms.
247 ALOGE("numSubSamples is invalid!");
248 return -1;
249 }
250
251 jboolean isCopy;
252 ssize_t totalSize = 0;
253
254 jint *numBytesOfClearData =
255 (numBytesOfClearDataObj == NULL)
256 ? NULL
257 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
258
259 jint *numBytesOfEncryptedData =
260 (numBytesOfEncryptedDataObj == NULL)
261 ? NULL
262 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
263
Chong Zhang2659c2f2017-04-27 13:18:20 -0700264 outSubSamples->resize(numSubSamples);
265 SubSample *subSamples = outSubSamples->data();
Chong Zhangd5927ae2017-01-03 11:07:18 -0800266 if (subSamples == NULL) {
267 ALOGE("Failed to allocate SubSample array!");
268 return -1;
269 }
270
271 for (jint i = 0; i < numSubSamples; ++i) {
Chong Zhang2659c2f2017-04-27 13:18:20 -0700272 subSamples[i].numBytesOfClearData =
Chong Zhangd5927ae2017-01-03 11:07:18 -0800273 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
274
Chong Zhang2659c2f2017-04-27 13:18:20 -0700275 subSamples[i].numBytesOfEncryptedData =
Chong Zhangd5927ae2017-01-03 11:07:18 -0800276 (numBytesOfEncryptedData == NULL)
277 ? 0 : numBytesOfEncryptedData[i];
278
Chong Zhang2659c2f2017-04-27 13:18:20 -0700279 totalSize += subSamples[i].numBytesOfClearData +
280 subSamples[i].numBytesOfEncryptedData;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800281 }
282
283 if (numBytesOfEncryptedData != NULL) {
284 env->ReleaseIntArrayElements(
285 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
286 numBytesOfEncryptedData = NULL;
287 }
288
289 if (numBytesOfClearData != NULL) {
290 env->ReleaseIntArrayElements(
291 numBytesOfClearDataObj, numBytesOfClearData, 0);
292 numBytesOfClearData = NULL;
293 }
294
Chong Zhangdadee0c2017-03-14 10:05:36 -0700295 if (totalSize < 0) {
Chong Zhangdadee0c2017-03-14 10:05:36 -0700296 return -1;
297 }
298
Chong Zhangd5927ae2017-01-03 11:07:18 -0800299 return totalSize;
300}
301
Chong Zhangdadee0c2017-03-14 10:05:36 -0700302static jthrowable createServiceSpecificException(
303 JNIEnv *env, int serviceSpecificError, const char *msg) {
304 if (env->ExceptionCheck()) {
305 ALOGW("Discarding pending exception");
306 env->ExceptionDescribe();
307 env->ExceptionClear();
308 }
309
310 ScopedLocalRef<jclass> clazz(
311 env, env->FindClass("android/os/ServiceSpecificException"));
312 CHECK(clazz.get() != NULL);
313
314 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
315 CHECK(ctor != NULL);
316
317 ScopedLocalRef<jstring> msgObj(
318 env, env->NewStringUTF(msg != NULL ?
319 msg : String8::format("Error %#x", serviceSpecificError)));
320
321 return (jthrowable)env->NewObject(
322 clazz.get(), ctor, serviceSpecificError, msgObj.get());
323}
324
Chong Zhangd5927ae2017-01-03 11:07:18 -0800325static jint android_media_MediaDescrambler_native_descramble(
326 JNIEnv *env, jobject thiz, jbyte key, jint numSubSamples,
327 jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
Chong Zhangaddc39e2017-03-31 14:52:52 -0700328 jobject srcBuf, jint srcOffset, jint srcLimit,
329 jobject dstBuf, jint dstOffset, jint dstLimit) {
Chong Zhangd5927ae2017-01-03 11:07:18 -0800330 sp<JDescrambler> descrambler = getDescrambler(env, thiz);
331 if (descrambler == NULL) {
Chong Zhang2659c2f2017-04-27 13:18:20 -0700332 jniThrowException(env, "java/lang/IllegalStateException",
333 "Invalid descrambler object!");
Chong Zhangd5927ae2017-01-03 11:07:18 -0800334 return -1;
335 }
336
Chong Zhang2659c2f2017-04-27 13:18:20 -0700337 hidl_vec<SubSample> subSamples;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800338 ssize_t totalLength = getSubSampleInfo(
339 env, numSubSamples, numBytesOfClearDataObj,
340 numBytesOfEncryptedDataObj, &subSamples);
341 if (totalLength < 0) {
342 jniThrowException(env, "java/lang/IllegalArgumentException",
Chong Zhangaddc39e2017-03-31 14:52:52 -0700343 "Invalid subsample info!");
Chong Zhangd5927ae2017-01-03 11:07:18 -0800344 return -1;
345 }
346
Chong Zhangd5927ae2017-01-03 11:07:18 -0800347 void *srcPtr = NULL, *dstPtr = NULL;
348 jbyteArray srcArray = NULL, dstArray = NULL;
349 status_t err = getBufferAndSize(
Chong Zhangaddc39e2017-03-31 14:52:52 -0700350 env, srcBuf, srcOffset, srcLimit, totalLength, &srcPtr, &srcArray);
Chong Zhangd5927ae2017-01-03 11:07:18 -0800351
352 if (err == OK) {
353 if (dstBuf == NULL) {
354 dstPtr = srcPtr;
355 } else {
356 err = getBufferAndSize(
Chong Zhangaddc39e2017-03-31 14:52:52 -0700357 env, dstBuf, dstOffset, dstLimit, totalLength, &dstPtr, &dstArray);
Chong Zhangd5927ae2017-01-03 11:07:18 -0800358 }
359 }
Chong Zhangaddc39e2017-03-31 14:52:52 -0700360
361 if (err != OK) {
362 jniThrowException(env, "java/lang/IllegalArgumentException",
363 "Invalid buffer offset and/or size for subsamples!");
364 return -1;
365 }
366
Chong Zhangdadee0c2017-03-14 10:05:36 -0700367 Status status;
Chong Zhang2659c2f2017-04-27 13:18:20 -0700368 uint32_t bytesWritten;
369 hidl_string detailedError;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800370
Chong Zhang2659c2f2017-04-27 13:18:20 -0700371 err = descrambler->descramble(
372 key, totalLength, subSamples,
373 srcPtr, srcOffset, dstPtr, dstOffset,
374 &status, &bytesWritten, &detailedError);
375
376 // Release byte array before throwing
Chong Zhangd5927ae2017-01-03 11:07:18 -0800377 if (srcArray != NULL) {
378 env->ReleaseByteArrayElements(srcArray, (jbyte *)srcPtr, 0);
379 }
380 if (dstArray != NULL) {
381 env->ReleaseByteArrayElements(dstArray, (jbyte *)dstPtr, 0);
382 }
Chong Zhangdadee0c2017-03-14 10:05:36 -0700383
Chong Zhang2659c2f2017-04-27 13:18:20 -0700384 if (err == NO_MEMORY) {
385 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
386 } else if (err == FAILED_TRANSACTION) {
387 jniThrowException(env, "android/os/RemoteException", NULL);
388 } else if (status != Status::OK) {
389 // Throw ServiceSpecific with cas error code and detailed msg,
390 // which will be re-thrown as MediaCasStateException.
391 env->Throw(createServiceSpecificException(
392 env, (int) status, detailedError.c_str()));
Chong Zhangdadee0c2017-03-14 10:05:36 -0700393 }
Chong Zhang2659c2f2017-04-27 13:18:20 -0700394 return bytesWritten;
Chong Zhangd5927ae2017-01-03 11:07:18 -0800395}
396
397static const JNINativeMethod gMethods[] = {
398 { "native_release", "()V",
399 (void *)android_media_MediaDescrambler_native_release },
400 { "native_init", "()V",
401 (void *)android_media_MediaDescrambler_native_init },
Chong Zhang2659c2f2017-04-27 13:18:20 -0700402 { "native_setup", "(Landroid/os/IHwBinder;)V",
Chong Zhangd5927ae2017-01-03 11:07:18 -0800403 (void *)android_media_MediaDescrambler_native_setup },
Chong Zhangaddc39e2017-03-31 14:52:52 -0700404 { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I",
Chong Zhangd5927ae2017-01-03 11:07:18 -0800405 (void *)android_media_MediaDescrambler_native_descramble },
406};
407
408int register_android_media_Descrambler(JNIEnv *env) {
409 return AndroidRuntime::registerNativeMethods(env,
410 "android/media/MediaDescrambler", gMethods, NELEM(gMethods));
411}
412