Add testQueryKeyStatus tests to test Clearkey plugin implementation.

Add testQueryKeyStatus in ClearKeySystemTest and
NativeClearKeySystemTest.

Test: CTS - ClearSystemTests
  ANDROID_BUILD_droid-cts/tools/cts-tradefed run cts -m
  CtsMediaTestCases --test android.media.cts.ClearKeySystemTest

Test: CTS - NativeClearSystemTests
  ANDROID_BUILD_droid-cts/tools/cts-tradefed run cts -m
  CtsMediaTestCases --test android.media.cts.NativeClearKeySystemTest

bug: 64938501
Change-Id: I39df097afa0187818037dd0ce1bc38245e094821
diff --git a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
index aa549b2..fa7025e 100644
--- a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
@@ -493,6 +493,54 @@
     }
 }
 
+static void acquireLicense(
+    JNIEnv* env, const AMediaObjects& aMediaObjects, const AMediaDrmSessionId& sessionId,
+    AMediaDrmKeyType keyType) {
+    // Pointer to keyRequest memory, which remains until the next
+    // AMediaDrm_getKeyRequest call or until the drm object is released.
+    const uint8_t* keyRequest;
+    size_t keyRequestSize = 0;
+    std::string errorMessage;
+
+    // The server recognizes "video/mp4" but not "video/avc".
+    media_status_t status = AMediaDrm_getKeyRequest(aMediaObjects.getDrm(),
+            &sessionId, kClearkeyPssh, sizeof(kClearkeyPssh),
+            "video/mp4" /*mimeType*/, keyType,
+            NULL, 0, &keyRequest, &keyRequestSize);
+    if (status != AMEDIA_OK) {
+        errorMessage.assign("getKeyRequest failed, error = %d");
+        goto errorOut;
+    }
+
+    if (kKeyRequestSize != keyRequestSize) {
+        ALOGE("Invalid keyRequestSize %zd", kKeyRequestSize);
+        errorMessage.assign("Invalid key request size, error = %d");
+        status = AMEDIA_DRM_NEED_KEY;
+        goto errorOut;
+    }
+
+    if (memcmp(kKeyRequestData, keyRequest, kKeyRequestSize) != 0) {
+        errorMessage.assign("Invalid key request data is returned, error = %d");
+        status = AMEDIA_DRM_NEED_KEY;
+        goto errorOut;
+    }
+
+    AMediaDrmKeySetId keySetId;
+    gGotVendorDefinedEvent = false;
+    status = AMediaDrm_provideKeyResponse(aMediaObjects.getDrm(), &sessionId,
+            reinterpret_cast<const uint8_t*>(kResponse),
+            sizeof(kResponse), &keySetId);
+    if (status == AMEDIA_OK) {
+        return;  // success
+    }
+
+    errorMessage.assign("provideKeyResponse failed, error = %d");
+
+errorOut:
+    AMediaDrm_closeSession(aMediaObjects.getDrm(), &sessionId);
+    jniThrowExceptionFmt(env, "java/lang/RuntimeException", errorMessage.c_str(), status);
+}
+
 extern "C" jboolean Java_android_media_cts_NativeClearKeySystemTest_testClearKeyPlaybackNative(
     JNIEnv* env, jclass /*clazz*/, jbyteArray uuid, jobject playbackParams) {
     if (NULL == uuid || NULL == playbackParams) {
@@ -562,44 +610,7 @@
         return JNI_FALSE;
     }
 
-    // Pointer to keyRequest memory, which remains until the next
-    // AMediaDrm_getKeyRequest call or until the drm object is released.
-    const uint8_t* keyRequest;
-    size_t keyRequestSize = 0;
-
-    // The server recognizes "video/mp4" but not "video/avc".
-    status = AMediaDrm_getKeyRequest(aMediaObjects.getDrm(), &sessionId,
-            kClearkeyPssh, sizeof(kClearkeyPssh),
-            "video/mp4" /*mimeType*/, KEY_TYPE_STREAMING,
-            NULL, 0, &keyRequest, &keyRequestSize);
-    if (status != AMEDIA_OK) {
-        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
-                "getKeyRequest failed, error = %d", status);
-        AMediaDrm_closeSession(aMediaObjects.getDrm(), &sessionId);
-        return JNI_FALSE;
-    }
-
-    if (kKeyRequestSize != keyRequestSize) {
-        ALOGE("Invalid keyRequestSize %zd", keyRequestSize);
-        return JNI_FALSE;
-    }
-
-    if (memcmp(kKeyRequestData, keyRequest, kKeyRequestSize) != 0) {
-        ALOGE("Invalid keyRequest data is returned");
-        return JNI_FALSE;
-    }
-
-    AMediaDrmKeySetId keySetId;
-    gGotVendorDefinedEvent = false;
-    status = AMediaDrm_provideKeyResponse(aMediaObjects.getDrm(), &sessionId,
-            reinterpret_cast<const uint8_t*>(kResponse),
-            sizeof(kResponse), &keySetId);
-    if (status != AMEDIA_OK) {
-        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
-                "provideKeyResponse failed, error = %d", status);
-        AMediaDrm_closeSession(aMediaObjects.getDrm(), &sessionId);
-        return JNI_FALSE;
-    }
+    acquireLicense(env, aMediaObjects, sessionId, KEY_TYPE_STREAMING);
 
     // Check if the event listener has received the expected event sent by
     // provideKeyResponse. This is for testing AMediaDrm_setOnEventListener().
@@ -635,6 +646,88 @@
     return JNI_TRUE;
 }
 
+extern "C" jboolean Java_android_media_cts_NativeClearKeySystemTest_testQueryKeyStatusNative(
+    JNIEnv* env, jclass /*clazz*/, jbyteArray uuid) {
+
+    if (NULL == uuid) {
+        jniThrowException(env, "java/lang/NullPointerException", "null uuid");
+        return JNI_FALSE;
+    }
+
+    Uuid juuid = jbyteArrayToUuid(env, uuid);
+    if (!isUuidSizeValid(juuid)) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                "invalid UUID size, expected %u bytes", kUuidSize);
+        return JNI_FALSE;
+    }
+
+    AMediaObjects aMediaObjects;
+    media_status_t status = AMEDIA_OK;
+    aMediaObjects.setDrm(AMediaDrm_createByUUID(&juuid[0]));
+    if (NULL == aMediaObjects.getDrm()) {
+        jniThrowException(env, "java/lang/RuntimeException", "failed to create drm");
+        return JNI_FALSE;
+    }
+
+    AMediaDrmSessionId sessionId;
+    status = AMediaDrm_openSession(aMediaObjects.getDrm(), &sessionId);
+    if (status != AMEDIA_OK) {
+        jniThrowException(env, "java/lang/RuntimeException",
+                "openSession failed");
+        return JNI_FALSE;
+    }
+
+    size_t numPairs = 3;
+    AMediaDrmKeyValue keyStatus[numPairs];
+
+    // Test for AMEDIA_DRM_SHORT_BUFFER
+    --numPairs;
+    status = AMediaDrm_queryKeyStatus(aMediaObjects.getDrm(), &sessionId, keyStatus, &numPairs);
+    if (status != AMEDIA_DRM_SHORT_BUFFER) {
+        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+                "AMediaDrm_queryKeyStatus should return AMEDIA_DRM_SHORT_BUFFER, error = %d",
+                        status);
+        return JNI_FALSE;
+    }
+
+    // Test default key status
+    ++numPairs;
+    status = AMediaDrm_queryKeyStatus(aMediaObjects.getDrm(), &sessionId, keyStatus, &numPairs);
+    if (status != AMEDIA_OK) {
+        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+                "AMediaDrm_queryKeyStatus failed, error = %d", status);
+        return JNI_FALSE;
+    }
+
+    for (size_t i = 0; i < numPairs; ++i) {
+        ALOGI("AMediaDrm_queryKeyStatus: key=%s, value=%s", keyStatus[i].mKey, keyStatus[i].mValue);
+    }
+
+    acquireLicense(env, aMediaObjects, sessionId, KEY_TYPE_STREAMING);
+
+    // Test valid key status
+    numPairs = 3;
+    status = AMediaDrm_queryKeyStatus(aMediaObjects.getDrm(), &sessionId, keyStatus, &numPairs);
+    if (status != AMEDIA_OK) {
+        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+                "AMediaDrm_queryKeyStatus failed, error = %d", status);
+        return JNI_FALSE;
+    }
+
+    for (size_t i = 0; i < numPairs; ++i) {
+        ALOGI("AMediaDrm_queryKeyStatus: key=%s, value=%s", keyStatus[i].mKey, keyStatus[i].mValue);
+    }
+
+
+    status = AMediaDrm_closeSession(aMediaObjects.getDrm(), &sessionId);
+    if (status != AMEDIA_OK) {
+        jniThrowException(env, "java/lang/RuntimeException",
+                "closeSession failed");
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
 static JNINativeMethod gMethods[] = {
     { "isCryptoSchemeSupportedNative", "([B)Z",
             (void *)Java_android_media_cts_NativeClearKeySystemTest_isCryptoSchemeSupportedNative },
@@ -649,6 +742,9 @@
 
     { "testPsshNative", "([BLjava/lang/String;)Z",
             (void *)Java_android_media_cts_NativeClearKeySystemTest__testPsshNative },
+
+    { "testQueryKeyStatusNative", "([B)Z",
+            (void *)Java_android_media_cts_NativeClearKeySystemTest_testQueryKeyStatusNative },
 };
 
 int register_android_media_cts_NativeClearKeySystemTest(JNIEnv* env) {
diff --git a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
index 94f8885..398bf1b 100644
--- a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
@@ -31,6 +31,7 @@
 import android.net.Uri;
 import android.os.Environment;
 import android.os.Looper;
+import android.support.annotation.NonNull;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Base64;
 import android.util.Log;
@@ -42,8 +43,10 @@
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import java.util.Vector;
 
@@ -222,7 +225,7 @@
         }
     }
 
-    private MediaDrm startDrm(final byte[][] clearKeys, final String initDataType, final UUID drmSchemeUuid) {
+    private @NonNull MediaDrm startDrm(final byte[][] clearKeys, final String initDataType, final UUID drmSchemeUuid) {
         new Thread() {
             @Override
             public void run() {
@@ -279,7 +282,7 @@
         mLooper.quit();
     }
 
-    private byte[] openSession(MediaDrm drm) {
+    private @NonNull byte[] openSession(MediaDrm drm) {
         byte[] mSessionId = null;
         boolean mRetryOpen;
         do {
@@ -297,7 +300,7 @@
         drm.closeSession(sessionId);
     }
 
-    public boolean isResolutionSupported(String mime, String[] features,
+    private boolean isResolutionSupported(String mime, String[] features,
             int videoWidth, int videoHeight) {
         if (ApiLevelUtil.isBefore(android.os.Build.VERSION_CODES.JELLY_BEAN)) {
             if  (videoHeight <= 144) {
@@ -343,10 +346,6 @@
         mSessionId = null;
         if (!scrambled) {
             drm = startDrm(clearKeys, initDataType, drmSchemeUuid);
-            if (null == drm) {
-                throw new Error("Failed to create drm.");
-            }
-
             if (!drm.isCryptoSchemeSupported(drmSchemeUuid)) {
                 stopDrm(drm);
                 throw new Error("Crypto scheme is not supported.");
@@ -414,6 +413,64 @@
         }
     }
 
+    private boolean queryKeyStatus(@NonNull final MediaDrm drm, @NonNull final byte[] sessionId) {
+        final HashMap<String, String> keyStatus = drm.queryKeyStatus(sessionId);
+        if (keyStatus.isEmpty()) {
+            Log.e(TAG, "queryKeyStatus: empty key status");
+            return false;
+        }
+
+        final Set<String> keySet = keyStatus.keySet();
+        final int numKeys = keySet.size();
+        final String[] keys = keySet.toArray(new String[numKeys]);
+        for (int i = 0; i < numKeys; ++i) {
+            final String key = keys[i];
+            Log.i(TAG, "queryKeyStatus: key=" + key + ", value=" + keyStatus.get(key));
+        }
+
+        return true;
+    }
+
+    public void testQueryKeyStatus() throws Exception {
+        MediaDrm drm = startDrm(new byte[][] { CLEAR_KEY_CENC }, "cenc", COMMON_PSSH_SCHEME_UUID);
+        if (!drm.isCryptoSchemeSupported(COMMON_PSSH_SCHEME_UUID)) {
+            stopDrm(drm);
+            throw new Error("Crypto scheme is not supported.");
+        }
+
+        // Test default key status
+        mSessionId = openSession(drm);
+        if (!queryKeyStatus(drm, mSessionId)) {
+            closeSession(drm, mSessionId);
+            stopDrm(drm);
+            throw new Error("query default key status failed");
+        }
+
+        // Test valid key status
+        mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
+                getActivity().getSurfaceHolder(),
+                mSessionId, false,
+                mContext.getResources());
+        mMediaCodecPlayer.setAudioDataSource(CENC_AUDIO_URL, null, false);
+        mMediaCodecPlayer.setVideoDataSource(CENC_VIDEO_URL, null, true);
+        mMediaCodecPlayer.start();
+        mMediaCodecPlayer.prepare();
+
+        mDrmInitData = mMediaCodecPlayer.getDrmInitData();
+        getKeys(drm, "cenc", mSessionId, mDrmInitData, new byte[][] { CLEAR_KEY_CENC });
+        boolean success = true;
+        if (!queryKeyStatus(drm, mSessionId)) {
+            success = false;
+        }
+
+        mMediaCodecPlayer.reset();
+        closeSession(drm, mSessionId);
+        stopDrm(drm);
+        if (!success) {
+            throw new Error("query key status failed");
+        }
+    }
+
     public void testClearKeyPlaybackCenc() throws Exception {
         testClearKeyPlayback(
             COMMON_PSSH_SCHEME_UUID,
diff --git a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
index 2375d46..45b2b8b 100644
--- a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
@@ -127,6 +127,10 @@
                 CENC_CLEARKEY_VIDEO_URL.toString()));
     }
 
+    public void testQueryKeyStatus() throws Exception {
+        assertTrue(testQueryKeyStatusNative(uuidByteArray(COMMON_PSSH_SCHEME_UUID)));
+    }
+
     public void testGetPropertyString() throws Exception {
         StringBuffer value = new StringBuffer();
         testGetPropertyStringNative(uuidByteArray(COMMON_PSSH_SCHEME_UUID), "description", value);
@@ -230,6 +234,8 @@
 
     private static native boolean testPsshNative(final byte[] uuid, final String videoUrl);
 
+    private static native boolean testQueryKeyStatusNative(final byte[] uuid);
+
     public void testClearKeyPlaybackCenc() throws Exception {
         testClearKeyPlayback(
             COMMON_PSSH_SCHEME_UUID,