Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 038d1663 authored by Andreas Huber's avatar Andreas Huber Committed by Android (Google) Code Review
Browse files

Merge "New Crypto JAVA class to facilitate decryption via MediaCodec."

parents d779412c 8240d923
Loading
Loading
Loading
Loading
+49 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

/**
 * Crypto class can be used in conjunction with MediaCodec to decode
 * encrypted media data.
 * @hide
*/
public final class Crypto {
    public static final native boolean isCryptoSchemeSupported(byte[] uuid);

    public Crypto(byte[] uuid, byte[] initData) {
        native_setup(uuid, initData);
    }

    public final native boolean requiresSecureDecoderComponent(String mime);

    @Override
    protected void finalize() {
        native_finalize();
    }

    public native final void release();
    private static native final void native_init();
    private native final void native_setup(byte[] uuid, byte[] initData);
    private native final void native_finalize();

    static {
        System.loadLibrary("media_jni");
        native_init();
    }

    private int mNativeContext;
}
+9 −5
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.media;
package android.media;


import android.media.Crypto;
import android.view.Surface;
import android.view.Surface;
import java.nio.ByteBuffer;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.Map;
@@ -25,8 +26,7 @@ import java.util.Map;
 * encoder/decoder components.
 * encoder/decoder components.
 * @hide
 * @hide
*/
*/
public class MediaCodec
final public class MediaCodec {
{
    /** Per buffer metadata includes an offset and size specifying
    /** Per buffer metadata includes an offset and size specifying
        the range of valid data in the associated codec buffer.
        the range of valid data in the associated codec buffer.
    */
    */
@@ -113,11 +113,14 @@ public class MediaCodec
     *
     *
     *  @param surface Specify a surface on which to render the output of this
     *  @param surface Specify a surface on which to render the output of this
     *                 decoder.
     *                 decoder.
     *  @param crypto  Specify a crypto object to facilitate secure decryption
     *                 of the media data.
     *  @param flags   Specify {@link #CONFIGURE_FLAG_ENCODE} to configure the
     *  @param flags   Specify {@link #CONFIGURE_FLAG_ENCODE} to configure the
     *                 component as an encoder.
     *                 component as an encoder.
    */
    */
    public void configure(
    public void configure(
            Map<String, Object> format, Surface surface, int flags) {
            Map<String, Object> format,
            Surface surface, Crypto crypto, int flags) {
        String[] keys = null;
        String[] keys = null;
        Object[] values = null;
        Object[] values = null;


@@ -133,11 +136,12 @@ public class MediaCodec
            }
            }
        }
        }


        native_configure(keys, values, surface, flags);
        native_configure(keys, values, surface, crypto, flags);
    }
    }


    private native final void native_configure(
    private native final void native_configure(
            String[] keys, Object[] values, Surface surface, int flags);
            String[] keys, Object[] values,
            Surface surface, Crypto crypto, int flags);


    /** After successfully configuring the component, call start. On return
    /** After successfully configuring the component, call start. On return
     *  you can query the component for its input/output buffers.
     *  you can query the component for its input/output buffers.
+1 −2
Original line number Original line Diff line number Diff line
@@ -23,8 +23,7 @@ import java.util.Map;
 * MediaExtractor
 * MediaExtractor
 * @hide
 * @hide
*/
*/
public class MediaExtractor
final public class MediaExtractor {
{
    public MediaExtractor(String path) {
    public MediaExtractor(String path) {
        native_setup(path);
        native_setup(path);
    }
    }
+1 −0
Original line number Original line Diff line number Diff line
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
include $(CLEAR_VARS)


LOCAL_SRC_FILES:= \
LOCAL_SRC_FILES:= \
    android_media_Crypto.cpp \
    android_media_MediaCodec.cpp \
    android_media_MediaCodec.cpp \
    android_media_MediaCodecList.cpp \
    android_media_MediaCodecList.cpp \
    android_media_MediaExtractor.cpp \
    android_media_MediaExtractor.cpp \
+291 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2012, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "Crypto-JNI"
#include <utils/Log.h>

#include "android_media_Crypto.h"

#include "android_runtime/AndroidRuntime.h"
#include "jni.h"
#include "JNIHelp.h"

#include <binder/IServiceManager.h>
#include <media/ICrypto.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ADebug.h>

namespace android {

struct fields_t {
    jfieldID context;
};

static fields_t gFields;

static sp<JCrypto> getCrypto(JNIEnv *env, jobject thiz) {
    return (JCrypto *)env->GetIntField(thiz, gFields.context);
}

JCrypto::JCrypto(
        JNIEnv *env, jobject thiz,
        const uint8_t uuid[16], const void *initData, size_t initSize) {
    mObject = env->NewWeakGlobalRef(thiz);

    mCrypto = MakeCrypto(uuid, initData, initSize);
}

JCrypto::~JCrypto() {
    mCrypto.clear();

    JNIEnv *env = AndroidRuntime::getJNIEnv();

    env->DeleteWeakGlobalRef(mObject);
    mObject = NULL;
}

// static
sp<ICrypto> JCrypto::MakeCrypto() {
    sp<IServiceManager> sm = defaultServiceManager();

    sp<IBinder> binder =
        sm->getService(String16("media.player"));

    sp<IMediaPlayerService> service =
        interface_cast<IMediaPlayerService>(binder);

    if (service == NULL) {
        return NULL;
    }

    sp<ICrypto> crypto = service->makeCrypto();

    if (crypto == NULL || crypto->initCheck() != OK) {
        return NULL;
    }

    return crypto;
}

// static
sp<ICrypto> JCrypto::MakeCrypto(
        const uint8_t uuid[16], const void *initData, size_t initSize) {
    sp<ICrypto> crypto = MakeCrypto();

    if (crypto == NULL) {
        return NULL;
    }

    status_t err = crypto->createPlugin(uuid, initData, initSize);

    if (err != OK) {
        return NULL;
    }

    return crypto;
}

bool JCrypto::requiresSecureDecoderComponent(const char *mime) const {
    if (mCrypto == NULL) {
        return false;
    }

    return mCrypto->requiresSecureDecoderComponent(mime);
}

// static
bool JCrypto::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
    sp<ICrypto> crypto = MakeCrypto();

    if (crypto == NULL) {
        return false;
    }

    return crypto->isCryptoSchemeSupported(uuid);
}

status_t JCrypto::initCheck() const {
    return mCrypto == NULL ? NO_INIT : OK;
}

// static
sp<ICrypto> JCrypto::GetCrypto(JNIEnv *env, jobject obj) {
    jclass clazz = env->FindClass("android/media/Crypto");
    CHECK(clazz != NULL);

    if (!env->IsInstanceOf(obj, clazz)) {
        return NULL;
    }

    sp<JCrypto> jcrypto = getCrypto(env, obj);

    if (jcrypto == NULL) {
        return NULL;
    }

    return jcrypto->mCrypto;
}

}  // namespace android

using namespace android;

static sp<JCrypto> setCrypto(
        JNIEnv *env, jobject thiz, const sp<JCrypto> &crypto) {
    sp<JCrypto> old = (JCrypto *)env->GetIntField(thiz, gFields.context);
    if (crypto != NULL) {
        crypto->incStrong(thiz);
    }
    if (old != NULL) {
        old->decStrong(thiz);
    }
    env->SetIntField(thiz, gFields.context, (int)crypto.get());

    return old;
}

static void android_media_Crypto_release(JNIEnv *env, jobject thiz) {
    setCrypto(env, thiz, NULL);
}

static void android_media_Crypto_native_init(JNIEnv *env) {
    jclass clazz = env->FindClass("android/media/Crypto");
    CHECK(clazz != NULL);

    gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
    CHECK(gFields.context != NULL);
}

static void android_media_Crypto_native_setup(
        JNIEnv *env, jobject thiz,
        jbyteArray uuidObj, jbyteArray initDataObj) {
    jsize uuidLength = env->GetArrayLength(uuidObj);

    if (uuidLength != 16) {
        jniThrowException(
                env,
                "java/lang/IllegalArgumentException",
                NULL);
        return;
    }

    jboolean isCopy;
    jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);

    jsize initDataLength = env->GetArrayLength(initDataObj);
    jbyte *initData = env->GetByteArrayElements(initDataObj, &isCopy);

    sp<JCrypto> crypto = new JCrypto(
            env, thiz, (const uint8_t *)uuid, initData, initDataLength);

    status_t err = crypto->initCheck();

    env->ReleaseByteArrayElements(initDataObj, initData, 0);
    initData = NULL;

    env->ReleaseByteArrayElements(uuidObj, uuid, 0);
    uuid = NULL;

    if (err != OK) {
        jniThrowException(
                env,
                "java/io/IOException",
                "Failed to instantiate crypto object.");
        return;
    }

    setCrypto(env,thiz, crypto);
}

static void android_media_Crypto_native_finalize(
        JNIEnv *env, jobject thiz) {
    android_media_Crypto_release(env, thiz);
}

static jboolean android_media_Crypto_isCryptoSchemeSupported(
        JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
    jsize uuidLength = env->GetArrayLength(uuidObj);

    if (uuidLength != 16) {
        jniThrowException(
                env,
                "java/lang/IllegalArgumentException",
                NULL);
        return false;
    }

    jboolean isCopy;
    jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);

    bool result = JCrypto::IsCryptoSchemeSupported((const uint8_t *)uuid);

    env->ReleaseByteArrayElements(uuidObj, uuid, 0);
    uuid = NULL;

    return result;
}

static jboolean android_media_Crypto_requiresSecureDecoderComponent(
        JNIEnv *env, jobject thiz, jstring mimeObj) {
    if (mimeObj == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return false;
    }

    sp<JCrypto> crypto = getCrypto(env, thiz);

    if (crypto == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return false;
    }

    const char *mime = env->GetStringUTFChars(mimeObj, NULL);

    if (mime == NULL) {
        return false;
    }

    bool result = crypto->requiresSecureDecoderComponent(mime);

    env->ReleaseStringUTFChars(mimeObj, mime);
    mime = NULL;

    return result;
}

static JNINativeMethod gMethods[] = {
    { "release", "()V", (void *)android_media_Crypto_release },
    { "native_init", "()V", (void *)android_media_Crypto_native_init },

    { "native_setup", "([B[B)V",
      (void *)android_media_Crypto_native_setup },

    { "native_finalize", "()V",
      (void *)android_media_Crypto_native_finalize },

    { "isCryptoSchemeSupported", "([B)Z",
      (void *)android_media_Crypto_isCryptoSchemeSupported },

    { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z",
      (void *)android_media_Crypto_requiresSecureDecoderComponent },
};

int register_android_media_Crypto(JNIEnv *env) {
    return AndroidRuntime::registerNativeMethods(env,
                "android/media/Crypto", gMethods, NELEM(gMethods));
}
Loading