Add new MediaDrm methods
Methods for querying HDCP, security levels and
number of sessions
bug:64001680
bug:33657579
Test: cts: MediaDrmMockTest, ClearKeySystemTest
gts: GtsMediaTestCases
Change-Id: Ie616f96ab6b74410a3d7548a7f34b20cf0831d0c
diff --git a/api/current.txt b/api/current.txt
index 06f3b2a..ed0f0bc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23021,24 +23021,29 @@
method public android.media.MediaDescription.Builder setTitle(java.lang.CharSequence);
}
- public final class MediaDrm {
+ public final class MediaDrm implements java.lang.AutoCloseable {
ctor public MediaDrm(java.util.UUID) throws android.media.UnsupportedSchemeException;
+ method public void close();
method public void closeSession(byte[]);
- method protected void finalize();
+ method public int getConnectedHdcpLevel();
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<java.lang.String, java.lang.String>) throws android.media.NotProvisionedException;
+ method public int getMaxHdcpLevel();
+ method public int getMaxSessionCount();
+ method public int getOpenSessionCount();
method public byte[] getPropertyByteArray(java.lang.String);
method public java.lang.String getPropertyString(java.lang.String);
method public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
method public byte[] getSecureStop(byte[]);
method public java.util.List<byte[]> getSecureStops();
+ method public int getSecurityLevel(byte[]);
method public static final boolean isCryptoSchemeSupported(java.util.UUID);
method public static final boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String);
method public byte[] openSession() 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<java.lang.String, java.lang.String> queryKeyStatus(byte[]);
- method public final void release();
+ method public deprecated void release();
method public void releaseAllSecureStops();
method public void releaseSecureStops(byte[]);
method public void removeKeys(byte[]);
@@ -23048,11 +23053,22 @@
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
field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
+ field public static final int HDCP_LEVEL_UNKNOWN = 0; // 0x0
+ field public static final int HDCP_NONE = 1; // 0x1
+ field public static final int HDCP_NO_DIGITAL_OUTPUT = 2147483647; // 0x7fffffff
+ field public static final int HDCP_V1 = 2; // 0x2
+ field public static final int HDCP_V2 = 3; // 0x3
+ field public static final int HDCP_V2_1 = 4; // 0x4
+ field public static final int HDCP_V2_2 = 5; // 0x5
+ field public static final int HW_SECURE_ALL = 5; // 0x5
+ field public static final int HW_SECURE_CRYPTO = 3; // 0x3
+ field public static final int HW_SECURE_DECODE = 4; // 0x4
field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
field public static final int KEY_TYPE_RELEASE = 3; // 0x3
field public static final int KEY_TYPE_STREAMING = 1; // 0x1
@@ -23061,6 +23077,9 @@
field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
field public static final java.lang.String PROPERTY_VENDOR = "vendor";
field public static final java.lang.String PROPERTY_VERSION = "version";
+ field public static final int SECURITY_LEVEL_UNKNOWN = 0; // 0x0
+ field public static final int SW_SECURE_CRYPTO = 1; // 0x1
+ field public static final int SW_SECURE_DECODE = 2; // 0x2
}
public final class MediaDrm.CryptoSession {
@@ -23070,6 +23089,9 @@
method public boolean verify(byte[], byte[], byte[]);
}
+ public static abstract class MediaDrm.HdcpLevel implements java.lang.annotation.Annotation {
+ }
+
public static final class MediaDrm.KeyRequest {
method public byte[] getData();
method public java.lang.String getDefaultUrl();
@@ -23110,6 +23132,9 @@
method public java.lang.String getDefaultUrl();
}
+ public static abstract class MediaDrm.SecurityLevel implements java.lang.annotation.Annotation {
+ }
+
public class MediaDrmException extends java.lang.Exception {
ctor public MediaDrmException(java.lang.String);
}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index e2f9b47..690d740 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -16,13 +16,6 @@
package android.media;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.UUID;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,6 +27,16 @@
import android.os.Message;
import android.os.Parcel;
import android.util.Log;
+import dalvik.system.CloseGuard;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+
/**
* MediaDrm can be used to obtain keys for decrypting protected media streams, in
@@ -117,10 +120,13 @@
* MediaDrm objects on a thread with its own Looper running (main UI
* thread by default has a Looper running).
*/
-public final class MediaDrm {
+public final class MediaDrm implements AutoCloseable {
private static final String TAG = "MediaDrm";
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
private EventHandler mEventHandler;
@@ -215,6 +221,8 @@
*/
native_setup(new WeakReference<MediaDrm>(this),
getByteArrayFromUUID(uuid), ActivityThread.currentOpPackageName());
+
+ mCloseGuard.open("release");
}
/**
@@ -954,6 +962,168 @@
*/
public native void releaseAllSecureStops();
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({HDCP_LEVEL_UNKNOWN, HDCP_NONE, HDCP_V1, HDCP_V2,
+ HDCP_V2_1, HDCP_V2_2, HDCP_NO_DIGITAL_OUTPUT})
+ public @interface HdcpLevel {}
+
+
+ /**
+ * The DRM plugin did not report an HDCP level, or an error
+ * occurred accessing it
+ */
+ public static final int HDCP_LEVEL_UNKNOWN = 0;
+
+ /**
+ * HDCP is not supported on this device, content is unprotected
+ */
+ public static final int HDCP_NONE = 1;
+
+ /**
+ * HDCP version 1.0
+ */
+ public static final int HDCP_V1 = 2;
+
+ /**
+ * HDCP version 2.0 Type 1.
+ */
+ public static final int HDCP_V2 = 3;
+
+ /**
+ * HDCP version 2.1 Type 1.
+ */
+ public static final int HDCP_V2_1 = 4;
+
+ /**
+ * HDCP version 2.2 Type 1.
+ */
+ public static final int HDCP_V2_2 = 5;
+
+ /**
+ * No digital output, implicitly secure
+ */
+ public static final int HDCP_NO_DIGITAL_OUTPUT = Integer.MAX_VALUE;
+
+ /**
+ * Return the HDCP level negotiated with downstream receivers the
+ * device is connected to. If multiple HDCP-capable displays are
+ * simultaneously connected to separate interfaces, this method
+ * returns the lowest negotiated level of all interfaces.
+ * <p>
+ * This method should only be used for informational purposes, not for
+ * enforcing compliance with HDCP requirements. Trusted enforcement of
+ * HDCP policies must be handled by the DRM system.
+ * <p>
+ * @return one of {@link #HDCP_LEVEL_UNKNOWN}, {@link #HDCP_NONE},
+ * {@link #HDCP_V1}, {@link #HDCP_V2}, {@link #HDCP_V2_1}, {@link #HDCP_V2_2}
+ * or {@link #HDCP_NO_DIGITAL_OUTPUT}.
+ */
+ @HdcpLevel
+ public native int getConnectedHdcpLevel();
+
+ /**
+ * Return the maximum supported HDCP level. The maximum HDCP level is a
+ * constant for a given device, it does not depend on downstream receivers
+ * that may be connected. If multiple HDCP-capable interfaces are present,
+ * it indicates the highest of the maximum HDCP levels of all interfaces.
+ * <p>
+ * @return one of {@link #HDCP_LEVEL_UNKNOWN}, {@link #HDCP_NONE},
+ * {@link #HDCP_V1}, {@link #HDCP_V2}, {@link #HDCP_V2_1}, {@link #HDCP_V2_2}
+ * or {@link #HDCP_NO_DIGITAL_OUTPUT}.
+ */
+ @HdcpLevel
+ public native int getMaxHdcpLevel();
+
+ /**
+ * Return the number of MediaDrm sessions that are currently opened
+ * simultaneously among all MediaDrm instances for the active DRM scheme.
+ * @return the number of open sessions.
+ */
+ public native int getOpenSessionCount();
+
+ /**
+ * Return the maximum number of MediaDrm sessions that may be opened
+ * simultaneosly among all MediaDrm instances for the active DRM
+ * scheme. The maximum number of sessions is not affected by any
+ * sessions that may have already been opened.
+ * @return maximum sessions.
+ */
+ public native int getMaxSessionCount();
+
+ /**
+ * Security level indicates the robustness of the device's DRM
+ * implementation.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SECURITY_LEVEL_UNKNOWN, SW_SECURE_CRYPTO, SW_SECURE_DECODE,
+ HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL})
+ public @interface SecurityLevel {}
+
+ /**
+ * The DRM plugin did not report a security level, or an error occurred
+ * accessing it
+ */
+ public static final int SECURITY_LEVEL_UNKNOWN = 0;
+
+ /**
+ * Software-based whitebox crypto
+ */
+ public static final int SW_SECURE_CRYPTO = 1;
+
+ /**
+ * Software-based whitebox crypto and an obfuscated decoder
+ */
+ public static final int SW_SECURE_DECODE = 2;
+
+ /**
+ * 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
+ */
+ 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.
+ */
+ 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}.
+ * @param sessionId the session to query.
+ * <p>
+ * @return one of {@link #SECURITY_LEVEL_UNKNOWN},
+ * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE},
+ * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or
+ * {@link #HW_SECURE_ALL}.
+ */
+ @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
*/
@@ -1311,18 +1481,52 @@
}
@Override
- protected void finalize() {
- native_finalize();
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ release();
+ } finally {
+ super.finalize();
+ }
}
- public native final void release();
+ /**
+ * Releases resources associated with the current session of
+ * MediaDrm. It is considered good practice to call this method when
+ * the {@link MediaDrm} object is no longer needed in your
+ * application. After this method is called, {@link MediaDrm} is no
+ * longer usable since it has lost all of its required resource.
+ *
+ * This method was added in API 28. In API versions 18 through 27, release()
+ * should be called instead. There is no need to do anything for API
+ * versions prior to 18.
+ */
+ @Override
+ public void close() {
+ release();
+ }
+
+ /**
+ * @deprecated replaced by {@link #close()}.
+ */
+ @Deprecated
+ public void release() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ native_release();
+ }
+ }
+
+ /** @hide */
+ public native final void native_release();
+
private static native final void native_init();
private native final void native_setup(Object mediadrm_this, byte[] uuid,
String appPackageName);
- private native final void native_finalize();
-
static {
System.loadLibrary("media_jni");
native_init();
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 51c9e5f..1dddbee 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -130,6 +130,26 @@
jclass classId;
};
+struct HDCPLevels {
+ jint kHdcpLevelUnknown;
+ jint kHdcpNone;
+ jint kHdcpV1;
+ jint kHdcpV2;
+ jint kHdcpV2_1;
+ jint kHdcpV2_2;
+ jint kHdcpNoOutput;
+} gHdcpLevels;
+
+struct SecurityLevels {
+ jint kSecurityLevelUnknown;
+ jint kSecurityLevelSwSecureCrypto;
+ jint kSecurityLevelSwSecureDecode;
+ jint kSecurityLevelHwSecureCrypto;
+ jint kSecurityLevelHwSecureDecode;
+ jint kSecurityLevelHwSecureAll;
+} gSecurityLevels;
+
+
struct fields_t {
jfieldID context;
jmethodID post_event;
@@ -565,12 +585,19 @@
return old;
}
-static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
-{
+static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
return false;
}
+ return true;
+}
+
+static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
+{
+ if (!CheckDrm(env, drm)) {
+ return false;
+ }
if (jsessionId == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
@@ -579,7 +606,7 @@
return true;
}
-static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
+static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
sp<JDrm> drm = setDrm(env, thiz, NULL);
if (drm != NULL) {
drm->setListener(NULL);
@@ -625,6 +652,34 @@
GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
+ gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
+ gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
+ gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
+ gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
+ gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
+ gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
+ gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
+
+ GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
+ gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "SW_SECURE_CRYPTO", "I");
+ gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "SW_SECURE_DECODE", "I");
+ gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_CRYPTO", "I");
+ gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_DECODE", "I");
+ gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_ALL", "I");
+ gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
+
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;");
@@ -724,11 +779,6 @@
setDrm(env, thiz, drm);
}
-static void android_media_MediaDrm_native_finalize(
- JNIEnv *env, jobject thiz) {
- android_media_MediaDrm_release(env, thiz);
-}
-
static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
@@ -971,9 +1021,7 @@
JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return NULL;
}
@@ -1018,9 +1066,7 @@
JNIEnv *env, jobject thiz, jbyteArray jresponse) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return NULL;
}
@@ -1057,9 +1103,7 @@
JNIEnv *env, jobject thiz) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return NULL;
}
@@ -1078,9 +1122,7 @@
JNIEnv *env, jobject thiz, jbyteArray ssid) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return NULL;
}
@@ -1099,9 +1141,7 @@
JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return;
}
@@ -1116,9 +1156,7 @@
JNIEnv *env, jobject thiz) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return;
}
@@ -1127,13 +1165,173 @@
throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
}
+
+static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
+ switch(level) {
+ case DrmPlugin::kHdcpLevelUnknown:
+ return gHdcpLevels.kHdcpLevelUnknown;
+ case DrmPlugin::kHdcpNone:
+ return gHdcpLevels.kHdcpNone;
+ case DrmPlugin::kHdcpV1:
+ return gHdcpLevels.kHdcpV1;
+ case DrmPlugin::kHdcpV2:
+ return gHdcpLevels.kHdcpV2;
+ case DrmPlugin::kHdcpV2_1:
+ return gHdcpLevels.kHdcpV2_1;
+ case DrmPlugin::kHdcpV2_2:
+ return gHdcpLevels.kHdcpV2_2;
+ case DrmPlugin::kHdcpNoOutput:
+ return gHdcpLevels.kHdcpNoOutput;
+ }
+ return gHdcpLevels.kHdcpNone;
+}
+
+static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
+ jobject thiz) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckDrm(env, drm)) {
+ return gHdcpLevels.kHdcpNone;
+ }
+
+ DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
+ DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
+
+ status_t err = drm->getHdcpLevels(&connected, &max);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
+ return gHdcpLevels.kHdcpLevelUnknown;
+ }
+ return HdcpLevelTojint(connected);
+}
+
+static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
+ jobject thiz) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckDrm(env, drm)) {
+ return gHdcpLevels.kHdcpLevelUnknown;
+ }
+
+ DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
+ DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
+
+ status_t err = drm->getHdcpLevels(&connected, &max);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
+ return gHdcpLevels.kHdcpLevelUnknown;
+ }
+ return HdcpLevelTojint(max);
+}
+
+static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
+ jobject thiz) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckDrm(env, drm)) {
+ return 0;
+ }
+
+ uint32_t open = 0, max = 0;
+ status_t err = drm->getNumberOfSessions(&open, &max);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
+ return 0;
+ }
+ return open;
+}
+
+static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
+ jobject thiz) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckDrm(env, drm)) {
+ return 0;
+ }
+
+ uint32_t open = 0, max = 0;
+ status_t err = drm->getNumberOfSessions(&open, &max);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
+ return 0;
+ }
+ return max;
+}
+
+static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
+ jobject thiz, jbyteArray jsessionId) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return gSecurityLevels.kSecurityLevelUnknown;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+ DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
+
+ status_t err = drm->getSecurityLevel(sessionId, &level);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get security level")) {
+ return gSecurityLevels.kSecurityLevelUnknown;
+ }
+
+ switch(level) {
+ case DrmPlugin::kSecurityLevelSwSecureCrypto:
+ return gSecurityLevels.kSecurityLevelSwSecureCrypto;
+ case DrmPlugin::kSecurityLevelSwSecureDecode:
+ return gSecurityLevels.kSecurityLevelSwSecureDecode;
+ case DrmPlugin::kSecurityLevelHwSecureCrypto:
+ return gSecurityLevels.kSecurityLevelHwSecureCrypto;
+ case DrmPlugin::kSecurityLevelHwSecureDecode:
+ return gSecurityLevels.kSecurityLevelHwSecureDecode;
+ case DrmPlugin::kSecurityLevelHwSecureAll:
+ return gSecurityLevels.kSecurityLevelHwSecureAll;
+ default:
+ return gSecurityLevels.kSecurityLevelUnknown;
+ }
+}
+
+
+static void android_media_MediaDrm_setSecurityLevel(JNIEnv *env,
+ jobject thiz, jbyteArray jsessionId, jint jlevel) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return;
+ }
+
+ Vector<uint8_t> 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<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return NULL;
}
@@ -1159,9 +1357,7 @@
JNIEnv *env, jobject thiz, jstring jname) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return NULL;
}
@@ -1187,9 +1383,7 @@
JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return;
}
@@ -1217,9 +1411,7 @@
JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
sp<IDrm> drm = GetDrm(env, thiz);
- if (drm == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "MediaDrm obj is null");
+ if (!CheckDrm(env, drm)) {
return;
}
@@ -1445,15 +1637,13 @@
static const JNINativeMethod gMethods[] = {
- { "release", "()V", (void *)android_media_MediaDrm_release },
+ { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
+
{ "native_init", "()V", (void *)android_media_MediaDrm_native_init },
{ "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
(void *)android_media_MediaDrm_native_setup },
- { "native_finalize", "()V",
- (void *)android_media_MediaDrm_native_finalize },
-
{ "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
(void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
@@ -1497,6 +1687,24 @@
{ "releaseAllSecureStops", "()V",
(void *)android_media_MediaDrm_releaseAllSecureStops },
+ { "getConnectedHdcpLevel", "()I",
+ (void *)android_media_MediaDrm_getConnectedHdcpLevel },
+
+ { "getMaxHdcpLevel", "()I",
+ (void *)android_media_MediaDrm_getMaxHdcpLevel },
+
+ { "getOpenSessionCount", "()I",
+ (void *)android_media_MediaDrm_getOpenSessionCount },
+
+ { "getMaxSessionCount", "()I",
+ (void *)android_media_MediaDrm_getMaxSessionCount },
+
+ { "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 },