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