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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user