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