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