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/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 },