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

Commit c8d0e450 authored by Hassan Shojania's avatar Hassan Shojania Committed by Android (Google) Code Review
Browse files

Merge "Modular DRM for MediaPlayer"

parents e0e21d9f 06b25fb2
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -22320,7 +22320,7 @@ package android.media {
    method public void pause() throws 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 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 void release();
    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 setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    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, android.os.Handler);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -22412,9 +22413,8 @@ package android.media {
    method public abstract void onCompletion(android.media.MediaPlayer);
  }
  public static abstract class MediaPlayer.OnDrmConfigCallback {
    ctor public MediaPlayer.OnDrmConfigCallback();
    method public void onDrmConfig(android.media.MediaPlayer);
  public static abstract interface MediaPlayer.OnDrmConfigListener {
    method public abstract void onDrmConfig(android.media.MediaPlayer);
  }
  public static abstract interface MediaPlayer.OnDrmInfoListener {
+4 −4
Original line number Diff line number Diff line
@@ -23963,7 +23963,7 @@ package android.media {
    method public void pause() throws 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 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 void release();
    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 setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    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, android.os.Handler);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -24055,9 +24056,8 @@ package android.media {
    method public abstract void onCompletion(android.media.MediaPlayer);
  }
  public static abstract class MediaPlayer.OnDrmConfigCallback {
    ctor public MediaPlayer.OnDrmConfigCallback();
    method public void onDrmConfig(android.media.MediaPlayer);
  public static abstract interface MediaPlayer.OnDrmConfigListener {
    method public abstract void onDrmConfig(android.media.MediaPlayer);
  }
  public static abstract interface MediaPlayer.OnDrmInfoListener {
+4 −4
Original line number Diff line number Diff line
@@ -22413,7 +22413,7 @@ package android.media {
    method public void pause() throws 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 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 void release();
    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 setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
    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, android.os.Handler);
    method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener);
@@ -22505,9 +22506,8 @@ package android.media {
    method public abstract void onCompletion(android.media.MediaPlayer);
  }
  public static abstract class MediaPlayer.OnDrmConfigCallback {
    ctor public MediaPlayer.OnDrmConfigCallback();
    method public void onDrmConfig(android.media.MediaPlayer);
  public static abstract interface MediaPlayer.OnDrmConfigListener {
    method public abstract void onDrmConfig(android.media.MediaPlayer);
  }
  public static abstract interface MediaPlayer.OnDrmInfoListener {
+239 −119

File changed.

Preview size limit exceeded, changes collapsed.

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

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

#define FIND_CLASS(var, className) \
var = env->FindClass(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) \
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);


// 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 {
    jmethodID init;
    jclass classId;
};

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

static drm_fields_t gFields;

static StateExceptionFields gStateExceptionFields;
// Modular DRM end

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

    // 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");
    if (clazz) {
        GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
        gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
        GET_METHOD_ID(gStateExceptionFields.init, clazz, "<init>", "(ILjava/lang/String;)V");
        gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));

        env->DeleteLocalRef(clazz);
    } 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");
    }

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

    jobject exception = env->NewObject(gFields.stateException.classId,
            gFields.stateException.init, static_cast<int>(err),
    jobject exception = env->NewObject(gStateExceptionFields.classId,
            gStateExceptionFields.init, static_cast<int>(err),
            env->NewStringUTF(msg));
    env->Throw(static_cast<jthrowable>(exception));
}
@@ -1393,18 +1291,6 @@ static bool throwDrmExceptionAsNecessary(JNIEnv *env, status_t err, const char *
    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)
{
    Vector<uint8_t> vector;
@@ -1414,74 +1300,8 @@ static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArr
    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,
                    jbyteArray uuidObj, jint mode)
                    jbyteArray uuidObj, jbyteArray drmSessionIdObj)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL) {
@@ -1504,13 +1324,23 @@ static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz,
        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 == INVALID_OPERATION) {
            jniThrowException(
                              env,
                              "java/lang/IllegalStateException",
                              "The player is not prepared yet.");
                              "The player must be in prepared state.");
        } else if (err == ERROR_DRM_CANNOT_HANDLE) {
            jniThrowException(
                              env,
@@ -1536,210 +1366,9 @@ static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz)
            jniThrowException(
                              env,
                              "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
// ----------------------------------------------------------------------------
@@ -1802,14 +1431,8 @@ static const JNINativeMethod gMethods[] = {
                            "(I)Landroid/media/VolumeShaper$State;",
                                                                (void *)android_media_MediaPlayer_getVolumeShaperState},
    // 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 },
    { "_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