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

Commit 06b25fb2 authored by Hassan Shojania's avatar Hassan Shojania
Browse files

Modular DRM for MediaPlayer

Bug:  34559906
Test: Manual through the test app
Change-Id: I1b1ca61e74f250d63ff5ff462905facb81fe44e0
parent 9f1b5b73
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -22320,7 +22320,7 @@ package android.media {
    method public void pause() throws java.lang.IllegalStateException;
    method public void pause() throws java.lang.IllegalStateException;
    method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
    method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
    method public void prepareAsync() throws java.lang.IllegalStateException;
    method public void prepareAsync() throws java.lang.IllegalStateException;
    method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
    method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
    method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
    method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
    method public void release();
    method public void release();
    method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
    method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
@@ -22348,6 +22348,7 @@ package android.media {
    method public void setNextMediaPlayer(android.media.MediaPlayer);
    method public void setNextMediaPlayer(android.media.MediaPlayer);
    method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
    method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
    method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -22412,9 +22413,8 @@ package android.media {
    method public abstract void onCompletion(android.media.MediaPlayer);
    method public abstract void onCompletion(android.media.MediaPlayer);
  }
  }
  public static abstract class MediaPlayer.OnDrmConfigCallback {
  public static abstract interface MediaPlayer.OnDrmConfigListener {
    ctor public MediaPlayer.OnDrmConfigCallback();
    method public abstract void onDrmConfig(android.media.MediaPlayer);
    method public void onDrmConfig(android.media.MediaPlayer);
  }
  }
  public static abstract interface MediaPlayer.OnDrmInfoListener {
  public static abstract interface MediaPlayer.OnDrmInfoListener {
+4 −4
Original line number Original line Diff line number Diff line
@@ -23963,7 +23963,7 @@ package android.media {
    method public void pause() throws java.lang.IllegalStateException;
    method public void pause() throws java.lang.IllegalStateException;
    method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
    method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
    method public void prepareAsync() throws java.lang.IllegalStateException;
    method public void prepareAsync() throws java.lang.IllegalStateException;
    method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
    method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
    method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
    method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
    method public void release();
    method public void release();
    method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
    method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
@@ -23991,6 +23991,7 @@ package android.media {
    method public void setNextMediaPlayer(android.media.MediaPlayer);
    method public void setNextMediaPlayer(android.media.MediaPlayer);
    method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
    method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
    method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -24055,9 +24056,8 @@ package android.media {
    method public abstract void onCompletion(android.media.MediaPlayer);
    method public abstract void onCompletion(android.media.MediaPlayer);
  }
  }
  public static abstract class MediaPlayer.OnDrmConfigCallback {
  public static abstract interface MediaPlayer.OnDrmConfigListener {
    ctor public MediaPlayer.OnDrmConfigCallback();
    method public abstract void onDrmConfig(android.media.MediaPlayer);
    method public void onDrmConfig(android.media.MediaPlayer);
  }
  }
  public static abstract interface MediaPlayer.OnDrmInfoListener {
  public static abstract interface MediaPlayer.OnDrmInfoListener {
+4 −4
Original line number Original line Diff line number Diff line
@@ -22413,7 +22413,7 @@ package android.media {
    method public void pause() throws java.lang.IllegalStateException;
    method public void pause() throws java.lang.IllegalStateException;
    method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
    method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
    method public void prepareAsync() throws java.lang.IllegalStateException;
    method public void prepareAsync() throws java.lang.IllegalStateException;
    method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
    method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
    method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
    method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
    method public void release();
    method public void release();
    method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
    method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
@@ -22441,6 +22441,7 @@ package android.media {
    method public void setNextMediaPlayer(android.media.MediaPlayer);
    method public void setNextMediaPlayer(android.media.MediaPlayer);
    method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
    method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
    method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
    method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -22505,9 +22506,8 @@ package android.media {
    method public abstract void onCompletion(android.media.MediaPlayer);
    method public abstract void onCompletion(android.media.MediaPlayer);
  }
  }
  public static abstract class MediaPlayer.OnDrmConfigCallback {
  public static abstract interface MediaPlayer.OnDrmConfigListener {
    ctor public MediaPlayer.OnDrmConfigCallback();
    method public abstract void onDrmConfig(android.media.MediaPlayer);
    method public void onDrmConfig(android.media.MediaPlayer);
  }
  }
  public static abstract interface MediaPlayer.OnDrmInfoListener {
  public static abstract interface MediaPlayer.OnDrmInfoListener {
+239 −119

File changed.

Preview size limit exceeded, changes collapsed.

+21 −398
Original line number Original line Diff line number Diff line
@@ -58,86 +58,20 @@
#include "android_util_Binder.h"
#include "android_util_Binder.h"


// Modular DRM begin
// Modular DRM begin
#include <media/drm/DrmAPI.h>

#define FIND_CLASS(var, className) \
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
var = env->FindClass(className); \
LOG_FATAL_IF(! (var), "Unable to find class " className);
LOG_FATAL_IF(! (var), "Unable to find class " className);


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

#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find method " fieldName);
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);


// TODO: investigate if these can be shared with their MediaDrm counterparts
struct RequestFields {
    jfieldID data;
    jfieldID defaultUrl;
    jfieldID requestType;
};

struct HashmapFields {
    jmethodID init;
    jmethodID get;
    jmethodID put;
    jmethodID entrySet;
};

struct SetFields {
    jmethodID iterator;
};

struct IteratorFields {
    jmethodID next;
    jmethodID hasNext;
};

struct EntryFields {
    jmethodID getKey;
    jmethodID getValue;
};

struct KeyTypes {
    jint kKeyTypeStreaming;
    jint kKeyTypeOffline;
    jint kKeyTypeRelease;
};

static KeyTypes gKeyTypes;

struct KeyRequestTypes {
    jint kKeyRequestTypeInitial;
    jint kKeyRequestTypeRenewal;
    jint kKeyRequestTypeRelease;
};

static KeyRequestTypes gKeyRequestTypes;

struct StateExceptionFields {
struct StateExceptionFields {
    jmethodID init;
    jmethodID init;
    jclass classId;
    jclass classId;
};
};


struct drm_fields_t {
static StateExceptionFields gStateExceptionFields;
    RequestFields keyRequest;
    HashmapFields hashmap;
    SetFields set;
    IteratorFields iterator;
    EntryFields entry;
    StateExceptionFields stateException;
    jclass stringClassId;
};

static drm_fields_t gFields;

// Modular DRM end
// Modular DRM end


// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
@@ -1041,50 +975,14 @@ android_media_MediaPlayer_native_init(JNIEnv *env)
    gBufferingParamsFields.init(env);
    gBufferingParamsFields.init(env);


    // Modular DRM
    // Modular DRM
    FIND_CLASS(clazz, "android/media/MediaDrm");
    if (clazz) {
        jfieldID field;
        GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
        gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
        GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
        gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
        GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
        gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);

        env->DeleteLocalRef(clazz);
    } else {
        ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't "
              "get clazz android/media/MediaDrm");
    }

    FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
    if (clazz) {
        GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
        GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
        GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");

        jfieldID field;
        GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
        gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
        GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
        gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
        GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
        gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);

        env->DeleteLocalRef(clazz);
    } else {
        ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't "
              "get clazz android/media/MediaDrm$KeyRequest");
    }

    FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
    FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
    if (clazz) {
    if (clazz) {
        GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
        GET_METHOD_ID(gStateExceptionFields.init, clazz, "<init>", "(ILjava/lang/String;)V");
        gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
        gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));


        env->DeleteLocalRef(clazz);
        env->DeleteLocalRef(clazz);
    } else {
    } else {
        ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't "
        ALOGE("JNI android_media_MediaPlayer_native_init couldn't "
              "get clazz android/media/MediaDrm$MediaDrmStateException");
              "get clazz android/media/MediaDrm$MediaDrmStateException");
    }
    }


@@ -1315,8 +1213,8 @@ static void throwDrmStateException(JNIEnv *env, const char *msg, status_t err)
{
{
    ALOGE("Illegal DRM state exception: %s (%d)", msg, err);
    ALOGE("Illegal DRM state exception: %s (%d)", msg, err);


    jobject exception = env->NewObject(gFields.stateException.classId,
    jobject exception = env->NewObject(gStateExceptionFields.classId,
            gFields.stateException.init, static_cast<int>(err),
            gStateExceptionFields.init, static_cast<int>(err),
            env->NewStringUTF(msg));
            env->NewStringUTF(msg));
    env->Throw(static_cast<jthrowable>(exception));
    env->Throw(static_cast<jthrowable>(exception));
}
}
@@ -1393,18 +1291,6 @@ static bool throwDrmExceptionAsNecessary(JNIEnv *env, status_t err, const char *
    return false;
    return false;
}
}


// TODO: investigate if these can be shared with their MediaDrm counterparts
static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector)
{
    size_t length = vector.size();
    jbyteArray result = env->NewByteArray(length);
    if (result != NULL) {
        env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
    }
    return result;
}

// TODO: investigate if these can be shared with their MediaDrm counterparts
static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray)
static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray)
{
{
    Vector<uint8_t> vector;
    Vector<uint8_t> vector;
@@ -1414,74 +1300,8 @@ static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArr
    return vector;
    return vector;
}
}


// TODO: investigate if these can be shared with their MediaDrm counterparts
static String8 JStringToString8(JNIEnv *env, jstring const &jstr)
{
    String8 result;

    const char *s = env->GetStringUTFChars(jstr, NULL);
    if (s) {
        result = s;
        env->ReleaseStringUTFChars(jstr, s);
    }
    return result;
}

// TODO: investigate if these can be shared with their MediaDrm counterparts
static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env,
                                             jobject &hashMap, bool* pIsOK)
{
    jclass clazz = gFields.stringClassId;
    KeyedVector<String8, String8> keyedVector;
    *pIsOK = true;

    jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
    if (entrySet) {
        jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
        if (iterator) {
            jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
            while (hasNext) {
                jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
                if (entry) {
                    jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
                    if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
                        jniThrowException(env, "java/lang/IllegalArgumentException",
                                          "HashMap key is not a String");
                        env->DeleteLocalRef(entry);
                        *pIsOK = false;
                        break;
                    }
                    jstring jkey = static_cast<jstring>(obj);

                    obj = env->CallObjectMethod(entry, gFields.entry.getValue);
                    if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
                        jniThrowException(env, "java/lang/IllegalArgumentException",
                                          "HashMap value is not a String");
                        env->DeleteLocalRef(entry);
                        *pIsOK = false;
                        break;
                    }
                    jstring jvalue = static_cast<jstring>(obj);

                    String8 key = JStringToString8(env, jkey);
                    String8 value = JStringToString8(env, jvalue);
                    keyedVector.add(key, value);

                    env->DeleteLocalRef(jkey);
                    env->DeleteLocalRef(jvalue);
                    hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
                }
                env->DeleteLocalRef(entry);
            }
            env->DeleteLocalRef(iterator);
        }
        env->DeleteLocalRef(entrySet);
    }
    return keyedVector;
}

static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz,
static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz,
                    jbyteArray uuidObj, jint mode)
                    jbyteArray uuidObj, jbyteArray drmSessionIdObj)
{
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL) {
    if (mp == NULL) {
@@ -1504,13 +1324,23 @@ static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz,
        return;
        return;
    }
    }


    status_t err = mp->prepareDrm(uuid.array(), mode);
    Vector<uint8_t> drmSessionId = JByteArrayToVector(env, drmSessionIdObj);

    if (drmSessionId.size() == 0) {
        jniThrowException(
                          env,
                          "java/lang/IllegalArgumentException",
                          "empty drmSessionId");
        return;
    }

    status_t err = mp->prepareDrm(uuid.array(), drmSessionId);
    if (err != OK) {
    if (err != OK) {
        if (err == INVALID_OPERATION) {
        if (err == INVALID_OPERATION) {
            jniThrowException(
            jniThrowException(
                              env,
                              env,
                              "java/lang/IllegalStateException",
                              "java/lang/IllegalStateException",
                              "The player is not prepared yet.");
                              "The player must be in prepared state.");
        } else if (err == ERROR_DRM_CANNOT_HANDLE) {
        } else if (err == ERROR_DRM_CANNOT_HANDLE) {
            jniThrowException(
            jniThrowException(
                              env,
                              env,
@@ -1536,210 +1366,9 @@ static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz)
            jniThrowException(
            jniThrowException(
                              env,
                              env,
                              "java/lang/IllegalStateException",
                              "java/lang/IllegalStateException",
                              "The player is not prepared yet.");
                              "Can not release DRM in an active player state.");
        }
        }
        }
    }
    }

static jobject android_media_MediaPlayer_getKeyRequest(JNIEnv *env, jobject thiz, jbyteArray jscope,
                       jstring jmimeType, jint jkeyType, jobject joptParams)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return NULL;
    }

    Vector<uint8_t> scope;
    if (jscope != NULL) {
        scope = JByteArrayToVector(env, jscope);
    }

    String8 mimeType;
    if (jmimeType != NULL) {
        mimeType = JStringToString8(env, jmimeType);
    }

    DrmPlugin::KeyType keyType;
    if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
        keyType = DrmPlugin::kKeyType_Streaming;
    } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
        keyType = DrmPlugin::kKeyType_Offline;
    } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
        keyType = DrmPlugin::kKeyType_Release;
    } else {
        jniThrowException(env, "java/lang/IllegalArgumentException", "invalid keyType");
        return NULL;
    }

    KeyedVector<String8, String8> optParams;
    if (joptParams != NULL) {
        bool isOK;
        optParams = HashMapToKeyedVector(env, joptParams, &isOK);
        if (!isOK) {
            return NULL;
        }
    }

    Vector<uint8_t> request;
    String8 defaultUrl;
    DrmPlugin::KeyRequestType keyRequestType;
    status_t err = mp->getKeyRequest(scope, mimeType, keyType, optParams, request, defaultUrl,
                           keyRequestType);

    if (throwDrmExceptionAsNecessary(env, err, "Failed to get key request")) {
        return NULL;
    }

    ALOGV("JNI getKeyRequest err %d  request %d  url %s  keyReqType %d",
          err, (int)request.size(), defaultUrl.string(), (int)keyRequestType);

    // Fill out return obj
    jclass clazz;
    FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");

    jobject keyObj = NULL;

    if (clazz) {
        keyObj = env->AllocObject(clazz);
        jbyteArray jrequest = VectorToJByteArray(env, request);
        env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);

        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
        env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);

        switch (keyRequestType) {
        case DrmPlugin::kKeyRequestType_Initial:
            env->SetIntField(keyObj, gFields.keyRequest.requestType,
                         gKeyRequestTypes.kKeyRequestTypeInitial);
            break;
        case DrmPlugin::kKeyRequestType_Renewal:
            env->SetIntField(keyObj, gFields.keyRequest.requestType,
                         gKeyRequestTypes.kKeyRequestTypeRenewal);
            break;
        case DrmPlugin::kKeyRequestType_Release:
            env->SetIntField(keyObj, gFields.keyRequest.requestType,
                         gKeyRequestTypes.kKeyRequestTypeRelease);
            break;
        default:
            throwDrmStateException(env, "MediaPlayer/DRM plugin failure: unknown "
                    "key request type", ERROR_DRM_UNKNOWN);
            break;
        }
    }

    return keyObj;
}

static jbyteArray android_media_MediaPlayer_provideKeyResponse(JNIEnv *env, jobject thiz,
                          jbyteArray jreleaseKeySetId, jbyteArray jresponse)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return NULL;
    }

    if (jresponse == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", "key response is null");
        return NULL;
    }

    Vector<uint8_t> releaseKeySetId;
    if (jreleaseKeySetId != NULL) {
        releaseKeySetId = JByteArrayToVector(env, jreleaseKeySetId);
    }

    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
    Vector<uint8_t> keySetId;

    status_t err = mp->provideKeyResponse(releaseKeySetId, response, keySetId);

    if (throwDrmExceptionAsNecessary(env, err, "Failed to handle key response")) {
        return NULL;
    }
    return VectorToJByteArray(env, keySetId);
}

static void android_media_MediaPlayer_restoreKeys(JNIEnv *env, jobject thiz, jbyteArray jkeySetId)
{
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
     if (mp == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }

    if (jkeySetId == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", "invalid keyType");
        return;
    }

    Vector<uint8_t> keySetId;
    keySetId = JByteArrayToVector(env, jkeySetId);

    status_t err = mp->restoreKeys(keySetId);

    ALOGV("JNI restoreKeys err %d ", err);
    throwDrmExceptionAsNecessary(env, err, "Failed to restore keys");
}

static jstring android_media_MediaPlayer_getDrmPropertyString(JNIEnv *env, jobject thiz,
                       jstring jname)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return NULL;
    }

    if (jname == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException",
                "property name String is null");
        return NULL;
    }

    String8 name = JStringToString8(env, jname);
    String8 value;

    status_t err = mp->getDrmPropertyString(name, value);

    ALOGV("JNI getPropertyString err %d", err);

    if (throwDrmExceptionAsNecessary(env, err, "Failed to get property")) {
        return NULL;
    }

    return env->NewStringUTF(value.string());
}

static void android_media_MediaPlayer_setDrmPropertyString(JNIEnv *env, jobject thiz,
                    jstring jname, jstring jvalue)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }

    if (jname == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException",
                "property name String is null");
        return;
    }

    if (jvalue == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException",
                "property value String is null");
        return;
    }

    String8 name = JStringToString8(env, jname);
    String8 value = JStringToString8(env, jvalue);

    status_t err = mp->setDrmPropertyString(name, value);

    ALOGV("JNI setPropertyString err %d", err);
    throwDrmExceptionAsNecessary(env, err, "Failed to set property");
}
}
// Modular DRM end
// Modular DRM end
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
@@ -1802,14 +1431,8 @@ static const JNINativeMethod gMethods[] = {
                            "(I)Landroid/media/VolumeShaper$State;",
                            "(I)Landroid/media/VolumeShaper$State;",
                                                                (void *)android_media_MediaPlayer_getVolumeShaperState},
                                                                (void *)android_media_MediaPlayer_getVolumeShaperState},
    // Modular DRM
    // Modular DRM
    { "_prepareDrm", "([BI)V",                                  (void *)android_media_MediaPlayer_prepareDrm },
    { "_prepareDrm", "([B[B)V",                                 (void *)android_media_MediaPlayer_prepareDrm },
    { "_releaseDrm", "()V",                                     (void *)android_media_MediaPlayer_releaseDrm },
    { "_releaseDrm", "()V",                                     (void *)android_media_MediaPlayer_releaseDrm },
    { "_getKeyRequest", "([BLjava/lang/String;ILjava/util/Map;)" "Landroid/media/MediaDrm$KeyRequest;",
        (void *)android_media_MediaPlayer_getKeyRequest },
    { "_provideKeyResponse", "([B[B)[B",                        (void *)android_media_MediaPlayer_provideKeyResponse },
    { "_getDrmPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_MediaPlayer_getDrmPropertyString },
    { "_setDrmPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_setDrmPropertyString },
    { "_restoreKeys", "([B)V",                                  (void *)android_media_MediaPlayer_restoreKeys },
};
};


// This function only registers the native methods
// This function only registers the native methods