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 32 namespace android { 33 34 struct fields_t { 35 jfieldID context; 36 }; 37 38 static fields_t gFields; 39 40 static sp<JCrypto> getCrypto(JNIEnv *env, jobject thiz) { 41 return (JCrypto *)env->GetLongField(thiz, gFields.context); 42 } 43 44 JCrypto::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 52 JCrypto::~JCrypto() { 53 mCrypto.clear(); 54 55 JNIEnv *env = AndroidRuntime::getJNIEnv(); 56 57 env->DeleteWeakGlobalRef(mObject); 58 mObject = NULL; 59 } 60 61 // static 62 sp<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 && crypto->initCheck() != NO_INIT)) { 78 return NULL; 79 } 80 81 return crypto; 82 } 83 84 // static 85 sp<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 102 bool JCrypto::requiresSecureDecoderComponent(const char *mime) const { 103 if (mCrypto == NULL) { 104 return false; 105 } 106 107 return mCrypto->requiresSecureDecoderComponent(mime); 108 } 109 110 // static 111 bool 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 121 status_t JCrypto::initCheck() const { 122 return mCrypto == NULL ? NO_INIT : OK; 123 } 124 125 // static 126 sp<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 // JNI conversion utilities 144 static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) { 145 Vector<uint8_t> vector; 146 size_t length = env->GetArrayLength(byteArray); 147 vector.insertAt((size_t)0, length); 148 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray()); 149 return vector; 150 } 151 152 } // namespace android 153 154 using namespace android; 155 156 static sp<JCrypto> setCrypto( 157 JNIEnv *env, jobject thiz, const sp<JCrypto> &crypto) { 158 sp<JCrypto> old = (JCrypto *)env->GetLongField(thiz, gFields.context); 159 if (crypto != NULL) { 160 crypto->incStrong(thiz); 161 } 162 if (old != NULL) { 163 old->decStrong(thiz); 164 } 165 env->SetLongField(thiz, gFields.context, (jlong)crypto.get()); 166 167 return old; 168 } 169 170 static void android_media_MediaCrypto_release(JNIEnv *env, jobject thiz) { 171 setCrypto(env, thiz, NULL); 172 } 173 174 static void android_media_MediaCrypto_native_init(JNIEnv *env) { 175 jclass clazz = env->FindClass("android/media/MediaCrypto"); 176 CHECK(clazz != NULL); 177 178 gFields.context = env->GetFieldID(clazz, "mNativeContext", "J"); 179 CHECK(gFields.context != NULL); 180 } 181 182 static void android_media_MediaCrypto_native_setup( 183 JNIEnv *env, jobject thiz, 184 jbyteArray uuidObj, jbyteArray initDataObj) { 185 jsize uuidLength = env->GetArrayLength(uuidObj); 186 187 if (uuidLength != 16) { 188 jniThrowException( 189 env, 190 "java/lang/IllegalArgumentException", 191 NULL); 192 return; 193 } 194 195 jboolean isCopy; 196 jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy); 197 198 jsize initDataLength = 0; 199 jbyte *initData = NULL; 200 201 if (initDataObj != NULL) { 202 initDataLength = env->GetArrayLength(initDataObj); 203 initData = env->GetByteArrayElements(initDataObj, &isCopy); 204 } 205 206 sp<JCrypto> crypto = new JCrypto( 207 env, thiz, (const uint8_t *)uuid, initData, initDataLength); 208 209 status_t err = crypto->initCheck(); 210 211 if (initDataObj != NULL) { 212 env->ReleaseByteArrayElements(initDataObj, initData, 0); 213 initData = NULL; 214 } 215 216 env->ReleaseByteArrayElements(uuidObj, uuid, 0); 217 uuid = NULL; 218 219 if (err != OK) { 220 jniThrowException( 221 env, 222 "android/media/MediaCryptoException", 223 "Failed to instantiate crypto object."); 224 return; 225 } 226 227 setCrypto(env,thiz, crypto); 228 } 229 230 static void android_media_MediaCrypto_native_finalize( 231 JNIEnv *env, jobject thiz) { 232 android_media_MediaCrypto_release(env, thiz); 233 } 234 235 static jboolean android_media_MediaCrypto_isCryptoSchemeSupportedNative( 236 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj) { 237 jsize uuidLength = env->GetArrayLength(uuidObj); 238 239 if (uuidLength != 16) { 240 jniThrowException( 241 env, 242 "java/lang/IllegalArgumentException", 243 NULL); 244 return JNI_FALSE; 245 } 246 247 jboolean isCopy; 248 jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy); 249 250 bool result = JCrypto::IsCryptoSchemeSupported((const uint8_t *)uuid); 251 252 env->ReleaseByteArrayElements(uuidObj, uuid, 0); 253 uuid = NULL; 254 255 return result ? JNI_TRUE : JNI_FALSE; 256 } 257 258 static jboolean android_media_MediaCrypto_requiresSecureDecoderComponent( 259 JNIEnv *env, jobject thiz, jstring mimeObj) { 260 if (mimeObj == NULL) { 261 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 262 return JNI_FALSE; 263 } 264 265 sp<JCrypto> crypto = getCrypto(env, thiz); 266 267 if (crypto == NULL) { 268 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 269 return JNI_FALSE; 270 } 271 272 const char *mime = env->GetStringUTFChars(mimeObj, NULL); 273 274 if (mime == NULL) { 275 return JNI_FALSE; 276 } 277 278 bool result = crypto->requiresSecureDecoderComponent(mime); 279 280 env->ReleaseStringUTFChars(mimeObj, mime); 281 mime = NULL; 282 283 return result ? JNI_TRUE : JNI_FALSE; 284 } 285 286 static void android_media_MediaCrypto_setMediaDrmSession( 287 JNIEnv *env, jobject thiz, jbyteArray jsessionId) { 288 if (jsessionId == NULL) { 289 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 290 return; 291 } 292 293 sp<ICrypto> crypto = JCrypto::GetCrypto(env, thiz); 294 295 if (crypto == NULL) { 296 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 297 return; 298 } 299 300 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); 301 302 status_t err = crypto->setMediaDrmSession(sessionId); 303 304 if (err != OK) { 305 String8 msg("setMediaDrmSession failed"); 306 if (err == ERROR_DRM_SESSION_NOT_OPENED) { 307 msg += ": session not opened"; 308 } else if (err == ERROR_UNSUPPORTED) { 309 msg += ": not supported by this crypto scheme"; 310 } else if (err == NO_INIT) { 311 msg += ": crypto plugin not initialized"; 312 } else { 313 msg.appendFormat(": general failure (%d)", err); 314 } 315 jniThrowException(env, "android/media/MediaCryptoException", msg.string()); 316 } 317 } 318 319 static JNINativeMethod gMethods[] = { 320 { "release", "()V", (void *)android_media_MediaCrypto_release }, 321 { "native_init", "()V", (void *)android_media_MediaCrypto_native_init }, 322 323 { "native_setup", "([B[B)V", 324 (void *)android_media_MediaCrypto_native_setup }, 325 326 { "native_finalize", "()V", 327 (void *)android_media_MediaCrypto_native_finalize }, 328 329 { "isCryptoSchemeSupportedNative", "([B)Z", 330 (void *)android_media_MediaCrypto_isCryptoSchemeSupportedNative }, 331 332 { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z", 333 (void *)android_media_MediaCrypto_requiresSecureDecoderComponent }, 334 335 { "setMediaDrmSession", "([B)V", 336 (void *)android_media_MediaCrypto_setMediaDrmSession }, 337 }; 338 339 int register_android_media_Crypto(JNIEnv *env) { 340 return AndroidRuntime::registerNativeMethods(env, 341 "android/media/MediaCrypto", gMethods, NELEM(gMethods)); 342 } 343 344