diff options
author | Jeff Tinker <jtinker@google.com> | 2013-04-05 01:16:23 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-04-05 01:16:23 +0000 |
commit | 1e0f36cffd8a4399fcd12e25bddde4544992bcb2 (patch) | |
tree | f45ba878d81b7bc05592c46ee2232ad973b4391a | |
parent | 80fdc9624e6d53a78031bf99d34e7c01d53ad66e (diff) | |
parent | 54cfbd6dc28334119c33b6a77779bfe244c71e69 (diff) | |
download | frameworks_base-1e0f36cffd8a4399fcd12e25bddde4544992bcb2.zip frameworks_base-1e0f36cffd8a4399fcd12e25bddde4544992bcb2.tar.gz frameworks_base-1e0f36cffd8a4399fcd12e25bddde4544992bcb2.tar.bz2 |
Merge "Implement async event callout from drm plugin to Java app" into jb-mr2-dev
-rw-r--r-- | media/java/android/media/MediaDrm.java | 25 | ||||
-rw-r--r-- | media/jni/android_media_MediaDrm.cpp | 145 | ||||
-rw-r--r-- | media/jni/android_media_MediaDrm.h | 19 |
3 files changed, 175 insertions, 14 deletions
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index 3cdf261..4eb0c56 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -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,10 +160,18 @@ 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"); - mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, 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; @@ -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); } } diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 1618edf..c32ba9d 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -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); } diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h index 01067c4..9b3917f 100644 --- a/media/jni/android_media_MediaDrm.h +++ b/media/jni/android_media_MediaDrm.h @@ -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]); |