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

* commit '1e0f36cffd8a4399fcd12e25bddde4544992bcb2':
  Implement async event callout from drm plugin to Java app
This commit is contained in:
Jeff Tinker
2013-04-04 18:23:10 -07:00
committed by Android Git Automerger
3 changed files with 175 additions and 14 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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]);