1/* 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 18#define LOG_TAG "MediaCrypto-JNI" 19#include <utils/Log.h> 20 21#include "android_media_MediaCrypto.h" 22 23#include "android_runtime/AndroidRuntime.h" 24#include "jni.h" 25#include "JNIHelp.h" 26 27#include <binder/IServiceManager.h> 28#include <media/ICrypto.h> 29#include <media/IMediaPlayerService.h> 30#include <media/stagefright/foundation/ADebug.h> 31 32namespace android { 33 34struct fields_t { 35 jfieldID context; 36}; 37 38static fields_t gFields; 39 40static sp<JCrypto> getCrypto(JNIEnv *env, jobject thiz) { 41 return (JCrypto *)env->GetIntField(thiz, gFields.context); 42} 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() { 53 mCrypto.clear(); 54 55 JNIEnv *env = AndroidRuntime::getJNIEnv(); 56 57 env->DeleteWeakGlobalRef(mObject); 58 mObject = NULL; 59} 60 61// static 62sp<ICrypto> JCrypto::MakeCrypto() { 63 sp<IServiceManager> sm = defaultServiceManager(); 64 65 sp<IBinder> binder = 66 sm->getService(String16("media.player")); 67 68 sp<IMediaPlayerService> service = 69 interface_cast<IMediaPlayerService>(binder); 70 71 if (service == NULL) { 72 return NULL; 73 } 74 75 sp<ICrypto> crypto = service->makeCrypto(); 76 77 if (crypto == NULL || crypto->initCheck() != OK) { 78 return NULL; 79 } 80 81 return crypto; 82} 83 84// static 85sp<ICrypto> JCrypto::MakeCrypto( 86 const uint8_t uuid[16], const void *initData, size_t initSize) { 87 sp<ICrypto> crypto = MakeCrypto(); 88 89 if (crypto == NULL) { 90 return NULL; 91 } 92 93 status_t err = crypto->createPlugin(uuid, initData, initSize); 94 95 if (err != OK) { 96 return NULL; 97 } 98 99 return crypto; 100} 101 102bool JCrypto::requiresSecureDecoderComponent(const char *mime) const { 103 if (mCrypto == NULL) { 104 return false; 105 } 106 107 return mCrypto->requiresSecureDecoderComponent(mime); 108} 109 110// static 111bool JCrypto::IsCryptoSchemeSupported(const uint8_t uuid[16]) { 112 sp<ICrypto> crypto = MakeCrypto(); 113 114 if (crypto == NULL) { 115 return false; 116 } 117 118 return crypto->isCryptoSchemeSupported(uuid); 119} 120 121status_t JCrypto::initCheck() const { 122 return mCrypto == NULL ? NO_INIT : OK; 123} 124 125// static 126sp<ICrypto> JCrypto::GetCrypto(JNIEnv *env, jobject obj) { 127 jclass clazz = env->FindClass("android/media/MediaCrypto"); 128 CHECK(clazz != NULL); 129 130 if (!env->IsInstanceOf(obj, clazz)) { 131 return NULL; 132 } 133 134 sp<JCrypto> jcrypto = getCrypto(env, obj); 135 136 if (jcrypto == NULL) { 137 return NULL; 138 } 139 140 return jcrypto->mCrypto; 141} 142 143} // namespace android 144 145using namespace android; 146 147static sp<JCrypto> setCrypto( 148 JNIEnv *env, jobject thiz, const sp<JCrypto> &crypto) { 149 sp<JCrypto> old = (JCrypto *)env->GetIntField(thiz, gFields.context); 150 if (crypto != NULL) { 151 crypto->incStrong(thiz); 152 } 153 if (old != NULL) { 154 old->decStrong(thiz); 155 } 156 env->SetIntField(thiz, gFields.context, (int)crypto.get()); 157 158 return old; 159} 160 161static void android_media_MediaCrypto_release(JNIEnv *env, jobject thiz) { 162 setCrypto(env, thiz, NULL); 163} 164 165static void android_media_MediaCrypto_native_init(JNIEnv *env) { 166 jclass clazz = env->FindClass("android/media/MediaCrypto"); 167 CHECK(clazz != NULL); 168 169 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 170 CHECK(gFields.context != NULL); 171} 172 173static void android_media_MediaCrypto_native_setup( 174 JNIEnv *env, jobject thiz, 175 jbyteArray uuidObj, jbyteArray initDataObj) { 176 jsize uuidLength = env->GetArrayLength(uuidObj); 177 178 if (uuidLength != 16) { 179 jniThrowException( 180 env, 181 "java/lang/IllegalArgumentException", 182 NULL); 183 return; 184 } 185 186 jboolean isCopy; 187 jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy); 188 189 jsize initDataLength = 0; 190 jbyte *initData = NULL; 191 192 if (initDataObj != NULL) { 193 initDataLength = env->GetArrayLength(initDataObj); 194 initData = env->GetByteArrayElements(initDataObj, &isCopy); 195 } 196 197 sp<JCrypto> crypto = new JCrypto( 198 env, thiz, (const uint8_t *)uuid, initData, initDataLength); 199 200 status_t err = crypto->initCheck(); 201 202 if (initDataObj != NULL) { 203 env->ReleaseByteArrayElements(initDataObj, initData, 0); 204 initData = NULL; 205 } 206 207 env->ReleaseByteArrayElements(uuidObj, uuid, 0); 208 uuid = NULL; 209 210 if (err != OK) { 211 jniThrowException( 212 env, 213 "android/media/MediaCryptoException", 214 "Failed to instantiate crypto object."); 215 return; 216 } 217 218 setCrypto(env,thiz, crypto); 219} 220 221static void android_media_MediaCrypto_native_finalize( 222 JNIEnv *env, jobject thiz) { 223 android_media_MediaCrypto_release(env, thiz); 224} 225 226static jboolean android_media_MediaCrypto_isCryptoSchemeSupportedNative( 227 JNIEnv *env, jobject thiz, jbyteArray uuidObj) { 228 jsize uuidLength = env->GetArrayLength(uuidObj); 229 230 if (uuidLength != 16) { 231 jniThrowException( 232 env, 233 "java/lang/IllegalArgumentException", 234 NULL); 235 return false; 236 } 237 238 jboolean isCopy; 239 jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy); 240 241 bool result = JCrypto::IsCryptoSchemeSupported((const uint8_t *)uuid); 242 243 env->ReleaseByteArrayElements(uuidObj, uuid, 0); 244 uuid = NULL; 245 246 return result; 247} 248 249static jboolean android_media_MediaCrypto_requiresSecureDecoderComponent( 250 JNIEnv *env, jobject thiz, jstring mimeObj) { 251 if (mimeObj == NULL) { 252 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 253 return false; 254 } 255 256 sp<JCrypto> crypto = getCrypto(env, thiz); 257 258 if (crypto == NULL) { 259 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 260 return false; 261 } 262 263 const char *mime = env->GetStringUTFChars(mimeObj, NULL); 264 265 if (mime == NULL) { 266 return false; 267 } 268 269 bool result = crypto->requiresSecureDecoderComponent(mime); 270 271 env->ReleaseStringUTFChars(mimeObj, mime); 272 mime = NULL; 273 274 return result; 275} 276 277static JNINativeMethod gMethods[] = { 278 { "release", "()V", (void *)android_media_MediaCrypto_release }, 279 { "native_init", "()V", (void *)android_media_MediaCrypto_native_init }, 280 281 { "native_setup", "([B[B)V", 282 (void *)android_media_MediaCrypto_native_setup }, 283 284 { "native_finalize", "()V", 285 (void *)android_media_MediaCrypto_native_finalize }, 286 287 { "isCryptoSchemeSupportedNative", "([B)Z", 288 (void *)android_media_MediaCrypto_isCryptoSchemeSupportedNative }, 289 290 { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z", 291 (void *)android_media_MediaCrypto_requiresSecureDecoderComponent }, 292}; 293 294int register_android_media_Crypto(JNIEnv *env) { 295 return AndroidRuntime::registerNativeMethods(env, 296 "android/media/MediaCrypto", gMethods, NELEM(gMethods)); 297} 298 299