Home | History | Annotate | Download | only in jni
      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 }  // namespace android
    144 
    145 using namespace android;
    146 
    147 static sp<JCrypto> setCrypto(
    148         JNIEnv *env, jobject thiz, const sp<JCrypto> &crypto) {
    149     sp<JCrypto> old = (JCrypto *)env->GetLongField(thiz, gFields.context);
    150     if (crypto != NULL) {
    151         crypto->incStrong(thiz);
    152     }
    153     if (old != NULL) {
    154         old->decStrong(thiz);
    155     }
    156     env->SetLongField(thiz, gFields.context, (jlong)crypto.get());
    157 
    158     return old;
    159 }
    160 
    161 static void android_media_MediaCrypto_release(JNIEnv *env, jobject thiz) {
    162     setCrypto(env, thiz, NULL);
    163 }
    164 
    165 static 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", "J");
    170     CHECK(gFields.context != NULL);
    171 }
    172 
    173 static 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 
    221 static void android_media_MediaCrypto_native_finalize(
    222         JNIEnv *env, jobject thiz) {
    223     android_media_MediaCrypto_release(env, thiz);
    224 }
    225 
    226 static 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 JNI_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 ? JNI_TRUE : JNI_FALSE;
    247 }
    248 
    249 static 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 JNI_FALSE;
    254     }
    255 
    256     sp<JCrypto> crypto = getCrypto(env, thiz);
    257 
    258     if (crypto == NULL) {
    259         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    260         return JNI_FALSE;
    261     }
    262 
    263     const char *mime = env->GetStringUTFChars(mimeObj, NULL);
    264 
    265     if (mime == NULL) {
    266         return JNI_FALSE;
    267     }
    268 
    269     bool result = crypto->requiresSecureDecoderComponent(mime);
    270 
    271     env->ReleaseStringUTFChars(mimeObj, mime);
    272     mime = NULL;
    273 
    274     return result ? JNI_TRUE : JNI_FALSE;
    275 }
    276 
    277 static 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 
    294 int register_android_media_Crypto(JNIEnv *env) {
    295     return AndroidRuntime::registerNativeMethods(env,
    296                 "android/media/MediaCrypto", gMethods, NELEM(gMethods));
    297 }
    298 
    299