DRM errors signaled by the CryptoPlugin are now visible to MediaCodec clients

through a custom exception "MediaCodec.CryptoException".

Change-Id: I30215e9e13bab68abad23e27dcead7c1accd07f1
related-to-bug: 6365261
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index a120a2f..8009fb5 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -36,6 +36,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/MediaErrors.h>
 
 namespace android {
@@ -129,8 +130,10 @@
 
 status_t JMediaCodec::queueInputBuffer(
         size_t index,
-        size_t offset, size_t size, int64_t timeUs, uint32_t flags) {
-    return mCodec->queueInputBuffer(index, offset, size, timeUs, flags);
+        size_t offset, size_t size, int64_t timeUs, uint32_t flags,
+        AString *errorDetailMsg) {
+    return mCodec->queueInputBuffer(
+            index, offset, size, timeUs, flags, errorDetailMsg);
 }
 
 status_t JMediaCodec::queueSecureInputBuffer(
@@ -142,10 +145,11 @@
         const uint8_t iv[16],
         CryptoPlugin::Mode mode,
         int64_t presentationTimeUs,
-        uint32_t flags) {
+        uint32_t flags,
+        AString *errorDetailMsg) {
     return mCodec->queueSecureInputBuffer(
             index, offset, subSamples, numSubSamples, key, iv, mode,
-            presentationTimeUs, flags);
+            presentationTimeUs, flags, errorDetailMsg);
 }
 
 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
@@ -251,7 +255,31 @@
     setMediaCodec(env, thiz, NULL);
 }
 
-static jint throwExceptionAsNecessary(JNIEnv *env, status_t err) {
+static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
+    jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException");
+    CHECK(clazz != NULL);
+
+    jmethodID constructID =
+        env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");
+    CHECK(constructID != NULL);
+
+    jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
+
+    jthrowable exception =
+        (jthrowable)env->NewObject(clazz, constructID, err, msgObj);
+
+    env->Throw(exception);
+}
+
+static jint throwExceptionAsNecessary(
+        JNIEnv *env, status_t err, const char *msg = NULL) {
+    if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) {
+        // We'll throw our custom MediaCodec.CryptoException
+
+        throwCryptoException(env, err, msg);
+        return 0;
+    }
+
     switch (err) {
         case OK:
             return 0;
@@ -383,10 +411,13 @@
         return;
     }
 
-    status_t err = codec->queueInputBuffer(
-            index, offset, size, timestampUs, flags);
+    AString errorDetailMsg;
 
-    throwExceptionAsNecessary(env, err);
+    status_t err = codec->queueInputBuffer(
+            index, offset, size, timestampUs, flags, &errorDetailMsg);
+
+    throwExceptionAsNecessary(
+            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
 }
 
 static void android_media_MediaCodec_queueSecureInputBuffer(
@@ -497,13 +528,17 @@
         }
     }
 
+    AString errorDetailMsg;
+
     if (err == OK) {
         err = codec->queueSecureInputBuffer(
                 index, offset,
                 subSamples, numSubSamples,
                 (const uint8_t *)key, (const uint8_t *)iv,
                 (CryptoPlugin::Mode)mode,
-                timestampUs, flags);
+                timestampUs,
+                flags,
+                &errorDetailMsg);
     }
 
     if (iv != NULL) {
@@ -519,7 +554,8 @@
     delete[] subSamples;
     subSamples = NULL;
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(
+            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
 }
 
 static jint android_media_MediaCodec_dequeueInputBuffer(
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 570c33b..e2688be 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -28,6 +28,7 @@
 
 struct ALooper;
 struct AMessage;
+struct AString;
 struct ICrypto;
 struct ISurfaceTexture;
 struct MediaCodec;
@@ -52,7 +53,8 @@
 
     status_t queueInputBuffer(
             size_t index,
-            size_t offset, size_t size, int64_t timeUs, uint32_t flags);
+            size_t offset, size_t size, int64_t timeUs, uint32_t flags,
+            AString *errorDetailMsg);
 
     status_t queueSecureInputBuffer(
             size_t index,
@@ -63,7 +65,8 @@
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
             int64_t presentationTimeUs,
-            uint32_t flags);
+            uint32_t flags,
+            AString *errorDetailMsg);
 
     status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs);