diff options
author | Hassan Shojania <shojania@google.com> | 2017-02-06 21:09:42 -0800 |
---|---|---|
committer | Hassan Shojania <shojania@google.com> | 2017-02-15 18:44:54 -0800 |
commit | 06b25fb2367d1962da5445d1c3c033c73a4b95eb (patch) | |
tree | cc44d6aeda9b03802fc4cf26c5b1eb640c36c8f9 /media/jni/android_media_MediaPlayer.cpp | |
parent | 9f1b5b73e8d83e4509b2f68aa8aab6f10e5a61e3 (diff) |
Modular DRM for MediaPlayer
Bug: 34559906
Test: Manual through the test app
Change-Id: I1b1ca61e74f250d63ff5ff462905facb81fe44e0
Diffstat (limited to 'media/jni/android_media_MediaPlayer.cpp')
-rw-r--r-- | media/jni/android_media_MediaPlayer.cpp | 419 |
1 files changed, 21 insertions, 398 deletions
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index c941766c07d6..636727eb0ac0 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -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."); - } - } -} - -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; + "Can not release DRM in an active player state."); } } - - 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 |