From 2bca525460ee030f4f4003331618ad2a44f76437 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Sun, 11 Feb 2018 18:59:14 +0000 Subject: [PATCH] Revert "Revert "Fix MediaDrm security level APIs"" This reverts commit fda717d50127c35f52880e94690042c7603600e3. Change-Id: I5e51c7e8d7ab0626fdfd9726278cb762b79a512e --- api/current.txt | 3 +- media/java/android/media/MediaDrm.java | 96 +++++++++++++++++--------- media/jni/android_media_MediaDrm.cpp | 67 ++++++++---------- 3 files changed, 93 insertions(+), 73 deletions(-) diff --git a/api/current.txt b/api/current.txt index 3944b45c3faa3..d4f1586c738c0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23371,6 +23371,7 @@ package android.media { method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String); method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap) throws android.media.NotProvisionedException; method public int getMaxHdcpLevel(); + method public static int getMaxSecurityLevel(); method public int getMaxSessionCount(); method public android.os.PersistableBundle getMetrics(); method public int getOpenSessionCount(); @@ -23384,6 +23385,7 @@ package android.media { method public static boolean isCryptoSchemeSupported(java.util.UUID); method public static boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String); method public byte[] openSession() throws android.media.NotProvisionedException, android.media.ResourceBusyException; + method public byte[] openSession(int) throws android.media.NotProvisionedException, android.media.ResourceBusyException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.NotProvisionedException; method public void provideProvisionResponse(byte[]) throws android.media.DeniedByServerException; method public java.util.HashMap queryKeyStatus(byte[]); @@ -23399,7 +23401,6 @@ package android.media { method public void setOnKeyStatusChangeListener(android.media.MediaDrm.OnKeyStatusChangeListener, android.os.Handler); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyString(java.lang.String, java.lang.String); - method public void setSecurityLevel(byte[], int); field public static final deprecated int EVENT_KEY_EXPIRED = 3; // 0x3 field public static final int EVENT_KEY_REQUIRED = 2; // 0x2 field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index 90fcaabd12fa1..279e05f57d1c2 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -634,8 +634,39 @@ public final class MediaDrm implements AutoCloseable { * @throws ResourceBusyException if required resources are in use */ @NonNull - public native byte[] openSession() throws NotProvisionedException, - ResourceBusyException; + public byte[] openSession() throws NotProvisionedException, + ResourceBusyException { + return openSession(getMaxSecurityLevel()); + } + + /** + * Open a new session at a requested security level. The security level + * represents the robustness of the device's DRM implementation. By default, + * sessions are opened at the native security level of the device. + * Overriding the security level is necessary when the decrypted frames need + * to be manipulated, such as for image compositing. The security level + * parameter must be lower than the native level. Reducing the security + * level will typically limit the content to lower resolutions, as + * determined by the license policy. If the requested level is not + * supported, the next lower supported security level will be set. The level + * can be queried using {@link #getSecurityLevel}. A session + * ID is returned. + * + * @param level the new security level, one of + * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE}, + * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or + * {@link #HW_SECURE_ALL}. + * + * @throws NotProvisionedException if provisioning is needed + * @throws ResourceBusyException if required resources are in use + * @throws IllegalArgumentException if the requested security level is + * higher than the native level or lower than the lowest supported level or + * if the device does not support specifying the security level when opening + * a session + */ + @NonNull + public native byte[] openSession(@SecurityLevel int level) throws + NotProvisionedException, ResourceBusyException; /** * Close a session on the MediaDrm object that was previously opened @@ -1109,7 +1140,7 @@ public final class MediaDrm implements AutoCloseable { */ @Retention(RetentionPolicy.SOURCE) @IntDef({SECURITY_LEVEL_UNKNOWN, SW_SECURE_CRYPTO, SW_SECURE_DECODE, - HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL}) + HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL}) public @interface SecurityLevel {} /** @@ -1119,39 +1150,55 @@ public final class MediaDrm implements AutoCloseable { public static final int SECURITY_LEVEL_UNKNOWN = 0; /** - * Software-based whitebox crypto + * DRM key management uses software-based whitebox crypto. */ public static final int SW_SECURE_CRYPTO = 1; /** - * Software-based whitebox crypto and an obfuscated decoder + * DRM key management and decoding use software-based whitebox crypto. */ - public static final int SW_SECURE_DECODE = 2; + public static final int SW_SECURE_DECODE = 2; /** - * DRM key management and crypto operations are performed within a - * hardware backed trusted execution environment + * DRM key management and crypto operations are performed within a hardware + * backed trusted execution environment. */ public static final int HW_SECURE_CRYPTO = 3; /** - * DRM key management, crypto operations and decoding of content - * are performed within a hardware backed trusted execution environment + * DRM key management, crypto operations and decoding of content are + * performed within a hardware backed trusted execution environment. */ - public static final int HW_SECURE_DECODE = 4; + public static final int HW_SECURE_DECODE = 4; /** * DRM key management, crypto operations, decoding of content and all - * handling of the media (compressed and uncompressed) is handled within - * a hardware backed trusted execution environment. + * handling of the media (compressed and uncompressed) is handled within a + * hardware backed trusted execution environment. */ public static final int HW_SECURE_ALL = 5; /** - * Return the current security level of a session. A session - * has an initial security level determined by the robustness of - * the DRM system's implementation on the device. The security - * level may be adjusted using {@link #setSecurityLevel}. + * The maximum security level supported by the device. This is the default + * security level when a session is opened. + * @hide + */ + public static final int SECURITY_LEVEL_MAX = 6; + + /** + * The maximum security level supported by the device. This is the default + * security level when a session is opened. + */ + @SecurityLevel + public static final int getMaxSecurityLevel() { + return SECURITY_LEVEL_MAX; + } + + /** + * Return the current security level of a session. A session has an initial + * security level determined by the robustness of the DRM system's + * implementation on the device. The security level may be changed at the + * time a session is opened using {@link #openSession}. * @param sessionId the session to query. *

* @return one of {@link #SECURITY_LEVEL_UNKNOWN}, @@ -1162,21 +1209,6 @@ public final class MediaDrm implements AutoCloseable { @SecurityLevel public native int getSecurityLevel(@NonNull byte[] sessionId); - /** - * Set the security level of a session. This can be useful if specific - * attributes of a lower security level are needed by an application, - * such as image manipulation or compositing. Reducing the security - * level will typically limit decryption to lower content resolutions, - * depending on the license policy. - * @param sessionId the session to set the security level on. - * @param level the new security level, one of - * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE}, - * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or - * {@link #HW_SECURE_ALL}. - */ - public native void setSecurityLevel(@NonNull byte[] sessionId, - @SecurityLevel int level); - /** * String property name: identifies the maker of the DRM plugin */ diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 4f06caaea7037..d7f51d4e6986f 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -145,6 +145,7 @@ struct HDCPLevels { struct SecurityLevels { jint kSecurityLevelUnknown; + jint kSecurityLevelMax; jint kSecurityLevelSwSecureCrypto; jint kSecurityLevelSwSecureDecode; jint kSecurityLevelHwSecureCrypto; @@ -683,6 +684,10 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_ALL", "I"); gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field); + jmethodID getMaxSecurityLevel; + GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I"); + gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel); + FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); @@ -813,7 +818,7 @@ static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative( } static jbyteArray android_media_MediaDrm_openSession( - JNIEnv *env, jobject thiz) { + JNIEnv *env, jobject thiz, jint jlevel) { sp drm = GetDrm(env, thiz); if (drm == NULL) { @@ -823,7 +828,26 @@ static jbyteArray android_media_MediaDrm_openSession( } Vector sessionId; - status_t err = drm->openSession(sessionId); + DrmPlugin::SecurityLevel level; + + if (jlevel == gSecurityLevels.kSecurityLevelMax) { + level = DrmPlugin::kSecurityLevelMax; + } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) { + level = DrmPlugin::kSecurityLevelSwSecureCrypto; + } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) { + level = DrmPlugin::kSecurityLevelSwSecureDecode; + } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) { + level = DrmPlugin::kSecurityLevelHwSecureCrypto; + } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) { + level = DrmPlugin::kSecurityLevelHwSecureDecode; + } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) { + level = DrmPlugin::kSecurityLevelHwSecureAll; + } else { + jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level"); + return NULL; + } + + status_t err = drm->openSession(level, sessionId); if (throwExceptionAsNecessary(env, err, "Failed to open session")) { return NULL; @@ -1345,40 +1369,6 @@ static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env, } -static void android_media_MediaDrm_setSecurityLevel(JNIEnv *env, - jobject thiz, jbyteArray jsessionId, jint jlevel) { - sp drm = GetDrm(env, thiz); - - if (!CheckSession(env, drm, jsessionId)) { - return; - } - - Vector sessionId(JByteArrayToVector(env, jsessionId)); - DrmPlugin::SecurityLevel level; - - if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) { - level = DrmPlugin::kSecurityLevelSwSecureCrypto; - } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) { - level = DrmPlugin::kSecurityLevelSwSecureDecode; - } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) { - level = DrmPlugin::kSecurityLevelHwSecureCrypto; - } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) { - level = DrmPlugin::kSecurityLevelHwSecureDecode; - } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) { - level = DrmPlugin::kSecurityLevelHwSecureAll; - } else { - jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level"); - return; - } - - status_t err = drm->setSecurityLevel(sessionId, level); - - if (throwExceptionAsNecessary(env, err, "Failed to set security level")) { - return; - } -} - - static jstring android_media_MediaDrm_getPropertyString( JNIEnv *env, jobject thiz, jstring jname) { sp drm = GetDrm(env, thiz); @@ -1724,7 +1714,7 @@ static const JNINativeMethod gMethods[] = { { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z", (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative }, - { "openSession", "()[B", + { "openSession", "(I)[B", (void *)android_media_MediaDrm_openSession }, { "closeSession", "([B)V", @@ -1785,9 +1775,6 @@ static const JNINativeMethod gMethods[] = { { "getSecurityLevel", "([B)I", (void *)android_media_MediaDrm_getSecurityLevel }, - { "setSecurityLevel", "([BI)V", - (void *)android_media_MediaDrm_setSecurityLevel }, - { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_MediaDrm_getPropertyString },