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

Commit 9e2e8e0b authored by Jeff Tinker's avatar Jeff Tinker Committed by Android Git Automerger
Browse files

am 72e2307c: am 1e0f36cf: Merge "Implement async event callout from drm plugin...

am 72e2307c: am 1e0f36cf: Merge "Implement async event callout from drm plugin to Java app" into jb-mr2-dev

* commit '72e2307c':
  Implement async event callout from drm plugin to Java app
parents db964a70 72e2307c
Loading
Loading
Loading
Loading
+16 −9
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Bundle;
import android.os.Parcel;
import android.util.Log;

/**
@@ -136,10 +137,8 @@ public final class MediaDrm {
    public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3;
    public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4;

    /* Do not change these values without updating their counterparts
     * in include/media/mediadrm.h!
     */
    private static final int DRM_EVENT = 200;

    private class EventHandler extends Handler
    {
        private MediaDrm mMediaDrm;
@@ -161,11 +160,19 @@ public final class MediaDrm {
                Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");

                if (mOnEventListener != null) {
                    Bundle bundle = msg.getData();
                    byte[] sessionId = bundle.getByteArray("sessionId");
                    byte[] data = bundle.getByteArray("data");
                    if (msg.obj != null && msg.obj instanceof Parcel) {
                        Parcel parcel = (Parcel)msg.obj;
                        byte[] sessionId = parcel.createByteArray();
                        if (sessionId.length == 0) {
                            sessionId = null;
                        }
                        byte[] data = parcel.createByteArray();
                        if (data.length == 0) {
                            data = null;
                        }
                        mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
                    }
                }
                return;

            default:
@@ -183,14 +190,14 @@ public final class MediaDrm {
     * the cookie passed to native_setup().)
     */
    private static void postEventFromNative(Object mediadrm_ref,
                                            int what, int arg1, int arg2, Object obj)
                                            int eventType, int extra, Object obj)
    {
        MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
        if (md == null) {
            return;
        }
        if (md.mEventHandler != null) {
            Message m = md.mEventHandler.obtainMessage(what, arg1, arg2, obj);
            Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj);
            md.mEventHandler.sendMessage(m);
        }
    }
+142 −3
Original line number Diff line number Diff line
@@ -21,10 +21,12 @@
#include "android_media_MediaDrm.h"

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

#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <media/IDrm.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -43,6 +45,15 @@ namespace android {
    var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
    LOG_FATAL_IF(! var, "Unable to find method " fieldName);

#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
    var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
    LOG_FATAL_IF(! var, "Unable to find field " fieldName);

#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
    var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
    LOG_FATAL_IF(! var, "Unable to find static method " fieldName);


struct RequestFields {
    jfieldID data;
    jfieldID defaultUrl;
@@ -74,8 +85,16 @@ struct EntryFields {
    jmethodID getValue;
};

struct EventTypes {
    int kEventProvisionRequired;
    int kEventKeyRequired;
    int kEventKeyExpired;
    int kEventVendorDefined;
} gEventTypes;

struct fields_t {
    jfieldID context;
    jmethodID post_event;
    RequestFields keyRequest;
    RequestFields provisionRequest;
    ArrayListFields arraylist;
@@ -87,6 +106,88 @@ struct fields_t {

static fields_t gFields;

// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class JNIDrmListener: public DrmListener
{
public:
    JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
    ~JNIDrmListener();
    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
private:
    JNIDrmListener();
    jclass      mClass;     // Reference to MediaDrm class
    jobject     mObject;    // Weak ref to MediaDrm Java object to call on
};

JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
{
    // Hold onto the MediaDrm class for use in calling the static method
    // that posts events to the application thread.
    jclass clazz = env->GetObjectClass(thiz);
    if (clazz == NULL) {
        ALOGE("Can't find android/media/MediaDrm");
        jniThrowException(env, "java/lang/Exception", NULL);
        return;
    }
    mClass = (jclass)env->NewGlobalRef(clazz);

    // We use a weak reference so the MediaDrm object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    mObject  = env->NewGlobalRef(weak_thiz);
}

JNIDrmListener::~JNIDrmListener()
{
    // remove global references
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    env->DeleteGlobalRef(mObject);
    env->DeleteGlobalRef(mClass);
}

void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
                            const Parcel *obj)
{
    jint jeventType;

    // translate DrmPlugin event types into their java equivalents
    switch(eventType) {
        case DrmPlugin::kDrmPluginEventProvisionRequired:
            jeventType = gEventTypes.kEventProvisionRequired;
            break;
        case DrmPlugin::kDrmPluginEventKeyNeeded:
            jeventType = gEventTypes.kEventKeyRequired;
            break;
        case DrmPlugin::kDrmPluginEventKeyExpired:
            jeventType = gEventTypes.kEventKeyExpired;
            break;
        case DrmPlugin::kDrmPluginEventVendorDefined:
            jeventType = gEventTypes.kEventVendorDefined;
            break;
        default:
            ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
            return;
    }

    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (obj && obj->dataSize() > 0) {
        jobject jParcel = createJavaParcelObject(env);
        if (jParcel != NULL) {
            Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
            nativeParcel->setData(obj->data(), obj->dataSize());
            env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
                    jeventType, extra, jParcel);
        }
    }

    if (env->ExceptionCheck()) {
        ALOGW("An exception occurred while notifying an event.");
        LOGW_EX(env);
        env->ExceptionClear();
    }
}


static bool throwExceptionAsNecessary(
        JNIEnv *env, status_t err, const char *msg = NULL) {

@@ -109,6 +210,9 @@ JDrm::JDrm(
        JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
    mObject = env->NewWeakGlobalRef(thiz);
    mDrm = MakeDrm(uuid);
    if (mDrm != NULL) {
        mDrm->setListener(this);
    }
}

JDrm::~JDrm() {
@@ -160,6 +264,25 @@ sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
    return drm;
}

status_t JDrm::setListener(const sp<DrmListener>& listener) {
    Mutex::Autolock lock(mLock);
    mListener = listener;
    return OK;
}

void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
    sp<DrmListener> listener;
    mLock.lock();
    listener = mListener;
    mLock.unlock();

    if (listener != NULL) {
        Mutex::Autolock lock(mNotifyLock);
        listener->notify(eventType, extra, obj);
    }
}


// static
bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
    sp<IDrm> drm = MakeDrm();
@@ -194,10 +317,9 @@ static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector)
}

static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
    jboolean isCopy;
    String8 result;

    const char *s = env->GetStringUTFChars(jstr, &isCopy);
    const char *s = env->GetStringUTFChars(jstr, NULL);
    if (s) {
        result = s;
        env->ReleaseStringUTFChars(jstr, s);
@@ -322,13 +444,28 @@ static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jse
}

static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
    setDrm(env, thiz, NULL);
    sp<JDrm> drm = setDrm(env, thiz, NULL);
    if (drm != NULL) {
        drm->setListener(NULL);
    }
}

static void android_media_MediaDrm_native_init(JNIEnv *env) {
    jclass clazz;
    FIND_CLASS(clazz, "android/media/MediaDrm");
    GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
    GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
                         "(Ljava/lang/Object;IILjava/lang/Object;)V");

    jfieldID field;
    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I");
    gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I");
    gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I");
    gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_VENDOR_DEFINED", "I");
    gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);

    FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
    GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
@@ -389,6 +526,8 @@ static void android_media_MediaDrm_native_setup(
        return;
    }

    sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
    drm->setListener(listener);
    setDrm(env, thiz, drm);
}

+17 −2
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include "jni.h"

#include <media/stagefright/foundation/ABase.h>
#include <media/IDrm.h>
#include <media/IDrmClient.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>

@@ -27,15 +29,24 @@ namespace android {

struct IDrm;

struct JDrm : public RefBase {
class DrmListener: virtual public RefBase
{
public:
    virtual void notify(DrmPlugin::EventType eventType, int extra,
                        const Parcel *obj) = 0;
};

struct JDrm : public BnDrmClient {
    static bool IsCryptoSchemeSupported(const uint8_t uuid[16]);

    JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16]);

    status_t initCheck() const;

    sp<IDrm> getDrm() { return mDrm; }

    void notify(DrmPlugin::EventType, int extra, const Parcel *obj);
    status_t setListener(const sp<DrmListener>& listener);

protected:
    virtual ~JDrm();

@@ -43,6 +54,10 @@ private:
    jweak mObject;
    sp<IDrm> mDrm;

    sp<DrmListener> mListener;
    Mutex mNotifyLock;
    Mutex mLock;

    static sp<IDrm> MakeDrm();
    static sp<IDrm> MakeDrm(const uint8_t uuid[16]);