Merge "Update AnalogClock deprecation tag to be more explicit about the where it is deprecated and still supported"
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index 852edef..f0ed6ee 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,4 @@
 xutan@google.com
 
 # Give submodule owners in shell resource approval
-per-file res*/*/*.xml = hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
index 926cfb3..deb7c6d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
@@ -1,2 +1,3 @@
 # WM shell sub-module desktop owners
+atsjenk@google.com
 madym@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
index 0c2d5c4..ccbb9cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS
@@ -1,2 +1,3 @@
 # WM shell sub-module freeform owners
+atsjenk@google.com
 madym@google.com
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index 1c28c3d..64dfc3e 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -7,3 +7,4 @@
 madym@google.com
 hwwang@google.com
 chenghsiuchang@google.com
+atsjenk@google.com
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 60f7735..8f022ac 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -55,6 +55,10 @@
         // GCC false-positives on this warning, and since we -Werror that's
         // a problem
         "-Wno-free-nonheap-object",
+
+        // Do not de-optimise cold code paths in AFDO.
+        // Some code paths might be infrequently executed but critical to latency.
+        "-fno-profile-sample-accurate",
     ],
 
     include_dirs: [
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 5b0c2a2..b878bcf5 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -43,6 +43,8 @@
 
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 
+#include <android-base/stringprintf.h>
+
 #include <binder/MemoryDealer.h>
 
 #include <cutils/compiler.h>
@@ -1099,7 +1101,8 @@
                     ALOGE("Could not create MediaCodec.BufferInfo.");
                     env->ExceptionClear();
                 }
-                jniThrowException(env, "java/lang/IllegalStateException", NULL);
+                jniThrowException(env, "java/lang/IllegalStateException",
+                                  "Fatal error: could not create MediaCodec.BufferInfo object");
                 return;
             }
 
@@ -1121,7 +1124,8 @@
                     ALOGE("Could not create CodecException object.");
                     env->ExceptionClear();
                 }
-                jniThrowException(env, "java/lang/IllegalStateException", NULL);
+                jniThrowException(env, "java/lang/IllegalStateException",
+                                  "Fatal error: could not create CodecException object");
                 return;
             }
 
@@ -1134,7 +1138,9 @@
             CHECK(msg->findMessage("format", &format));
 
             if (OK != ConvertMessageToMap(env, format, &obj)) {
-                jniThrowException(env, "java/lang/IllegalStateException", NULL);
+                jniThrowException(env, "java/lang/IllegalStateException",
+                                  "Fatal error: failed to convert format "
+                                  "from native to Java object");
                 return;
             }
 
@@ -1166,7 +1172,8 @@
 
     status_t err = ConvertMessageToMap(env, data, &obj);
     if (err != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Fatal error: failed to convert format from native to Java object");
         return;
     }
 
@@ -1187,7 +1194,8 @@
 
     status_t err = ConvertMessageToMap(env, data, &obj);
     if (err != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Fatal error: failed to convert format from native to Java object");
         return;
     }
 
@@ -1198,6 +1206,18 @@
     env->DeleteLocalRef(obj);
 }
 
+std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
+    if (mCodec == nullptr) {
+        return msg ?: "";
+    }
+    std::string prefix = "";
+    if (msg && msg[0] != '\0') {
+        prefix.append(msg);
+        prefix.append("\n");
+    }
+    return prefix + mCodec->getErrorLog().extract();
+}
+
 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatCallbackNotify:
@@ -1347,9 +1367,17 @@
     env->Throw(exception);
 }
 
+static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
+    if (codec == NULL) {
+        return msg ?: "codec is released already";
+    }
+    return codec->getExceptionMessage(msg);
+}
+
 static jint throwExceptionAsNecessary(
         JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
-        const char *msg = NULL, const sp<ICrypto>& crypto = NULL) {
+        const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
+        const sp<JMediaCodec> &codec = NULL) {
     switch (err) {
         case OK:
             return 0;
@@ -1364,23 +1392,38 @@
             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
 
         case INVALID_OPERATION:
-            jniThrowException(env, "java/lang/IllegalStateException", msg);
+            jniThrowException(
+                    env, "java/lang/IllegalStateException",
+                    GetExceptionMessage(codec, msg).c_str());
             return 0;
 
         case BAD_VALUE:
-            jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+            jniThrowException(
+                    env, "java/lang/IllegalArgumentException",
+                    GetExceptionMessage(codec, msg).c_str());
             return 0;
 
         default:
             if (isCryptoError(err)) {
-                throwCryptoException(env, err, msg, crypto);
+                throwCryptoException(
+                        env, err,
+                        GetExceptionMessage(codec, msg).c_str(),
+                        crypto);
                 return 0;
             }
-            throwCodecException(env, err, actionCode, msg);
+            throwCodecException(
+                    env, err, actionCode,
+                    GetExceptionMessage(codec, msg).c_str());
             return 0;
     }
 }
 
+static jint throwExceptionAsNecessary(
+        JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
+        int32_t actionCode = ACTION_CODE_FATAL) {
+    return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
+}
+
 static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
         JNIEnv *env,
         jobject thiz,
@@ -1388,13 +1431,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
@@ -1404,13 +1447,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->enableOnFrameRenderedListener(enabled);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_native_setCallback(
@@ -1420,13 +1463,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->setCallback(cb);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_native_configure(
@@ -1440,7 +1483,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1478,7 +1521,7 @@
 
     err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_native_setSurface(
@@ -1488,7 +1531,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1507,7 +1550,7 @@
     }
 
     status_t err = codec->setSurface(bufferProducer);
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
@@ -1611,7 +1654,7 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1625,7 +1668,7 @@
     }
     status_t err = codec->setInputSurface(persistentSurface);
     if (err != NO_ERROR) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 }
 
@@ -1635,7 +1678,7 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -1643,7 +1686,7 @@
     sp<IGraphicBufferProducer> bufferProducer;
     status_t err = codec->createInputSurface(&bufferProducer);
     if (err != NO_ERROR) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
         return NULL;
     }
 
@@ -1658,13 +1701,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->start();
 
-    throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
@@ -1673,13 +1716,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->stop();
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
@@ -1688,7 +1731,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1701,7 +1744,7 @@
         // trigger an IllegalStateException.
         err = UNKNOWN_ERROR;
     }
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
@@ -1710,13 +1753,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->flush();
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_queueInputBuffer(
@@ -1732,7 +1775,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1742,7 +1785,8 @@
             index, offset, size, timestampUs, flags, &errorDetailMsg);
 
     throwExceptionAsNecessary(
-            env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
 }
 
 struct NativeCryptoInfo {
@@ -1766,7 +1810,9 @@
         } else if (jmode == gCryptoModes.AesCbc) {
             mMode = CryptoPlugin::kMode_AES_CBC;
         }  else {
-            throwExceptionAsNecessary(env, INVALID_OPERATION);
+            throwExceptionAsNecessary(
+                    env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                    base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
             return;
         }
 
@@ -1902,7 +1948,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -1932,7 +1978,9 @@
     } else if (jmode == gCryptoModes.AesCbc) {
         mode = CryptoPlugin::kMode_AES_CBC;
     }  else {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(
+                env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
         return;
     }
 
@@ -2051,8 +2099,8 @@
     subSamples = NULL;
 
     throwExceptionAsNecessary(
-            env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(),
-            codec->getCrypto());
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
 }
 
 static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
@@ -2394,14 +2442,16 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == nullptr || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     sp<AMessage> tunings;
     status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
     if (err != OK) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(
+                env, err, ACTION_CODE_FATAL,
+                "error occurred while converting tunings from Java to native");
         return;
     }
 
@@ -2421,15 +2471,23 @@
         }
         env->MonitorExit(lock.get());
     } else {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(
+                env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                "Failed to grab lock for a LinearBlock object");
         return;
     }
 
     AString errorDetailMsg;
     if (codec->hasCryptoOrDescrambler()) {
         if (!memory) {
+            // It means there was an unexpected failure in extractMemoryFromContext above
             ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
-            throwExceptionAsNecessary(env, BAD_VALUE);
+            throwExceptionAsNecessary(
+                    env, BAD_VALUE, ACTION_CODE_FATAL,
+                    "Unexpected error: the input buffer is not compatible with "
+                    "the secure codec, and a fallback logic failed.\n"
+                    "Suggestion: please try including the secure codec when calling "
+                    "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
             return;
         }
         auto cryptoInfo =
@@ -2453,14 +2511,22 @@
         ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
     } else {
         if (!buffer) {
+            // It means there was an unexpected failure in extractBufferFromContext above
             ALOGI("queueLinearBlock: no C2Buffer found");
-            throwExceptionAsNecessary(env, BAD_VALUE);
+            throwExceptionAsNecessary(
+                    env, BAD_VALUE, ACTION_CODE_FATAL,
+                    "Unexpected error: the input buffer is not compatible with "
+                    "the non-secure codec, and a fallback logic failed.\n"
+                    "Suggestion: please do not include the secure codec when calling "
+                    "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
             return;
         }
         err = codec->queueBuffer(
                 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
     }
-    throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
+    throwExceptionAsNecessary(
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
 }
 
 static void android_media_MediaCodec_native_queueHardwareBuffer(
@@ -2471,14 +2537,16 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     sp<AMessage> tunings;
     status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
     if (err != OK) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(
+                env, err, ACTION_CODE_FATAL,
+                "error occurred while converting tunings from Java to native");
         return;
     }
 
@@ -2503,7 +2571,9 @@
         ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
         native_handle_close(handle);
         native_handle_delete(handle);
-        throwExceptionAsNecessary(env, BAD_VALUE);
+        throwExceptionAsNecessary(
+                env, BAD_VALUE, ACTION_CODE_FATAL,
+                "HardwareBuffer not recognized");
         return;
     }
     std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
@@ -2512,7 +2582,9 @@
     AString errorDetailMsg;
     err = codec->queueBuffer(
             index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
-    throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
+    throwExceptionAsNecessary(
+            env, err, ACTION_CODE_FATAL,
+            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
 }
 
 static void android_media_MediaCodec_native_getOutputFrame(
@@ -2522,13 +2594,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->getOutputFrame(env, frame, index);
     if (err != OK) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 }
 
@@ -2539,7 +2611,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return -1;
     }
 
@@ -2550,7 +2622,7 @@
         return (jint) index;
     }
 
-    return throwExceptionAsNecessary(env, err);
+    return throwExceptionAsNecessary(env, err, codec);
 }
 
 static jint android_media_MediaCodec_dequeueOutputBuffer(
@@ -2560,7 +2632,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return 0;
     }
 
@@ -2572,7 +2644,7 @@
         return (jint) index;
     }
 
-    return throwExceptionAsNecessary(env, err);
+    return throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_releaseOutputBuffer(
@@ -2583,13 +2655,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
@@ -2598,13 +2670,13 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t err = codec->signalEndOfInputStream();
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static jobject android_media_MediaCodec_getFormatNative(
@@ -2614,7 +2686,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2625,7 +2697,7 @@
         return format;
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 
     return NULL;
 }
@@ -2637,7 +2709,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2648,7 +2720,7 @@
         return format;
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 
     return NULL;
 }
@@ -2660,7 +2732,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2673,7 +2745,7 @@
 
     // if we're out of memory, an exception was already thrown
     if (err != NO_MEMORY) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 
     return NULL;
@@ -2686,7 +2758,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2699,7 +2771,7 @@
 
     // if we're out of memory, an exception was already thrown
     if (err != NO_MEMORY) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 
     return NULL;
@@ -2712,7 +2784,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2725,7 +2797,7 @@
 
     // if we're out of memory, an exception was already thrown
     if (err != NO_MEMORY) {
-        throwExceptionAsNecessary(env, err);
+        throwExceptionAsNecessary(env, err, codec);
     }
 
     return NULL;
@@ -2738,7 +2810,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2749,7 +2821,7 @@
         return name;
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 
     return NULL;
 }
@@ -2761,7 +2833,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2772,7 +2844,7 @@
         return codecInfoObj;
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 
     return NULL;
 }
@@ -2784,7 +2856,8 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL || codec->initCheck() != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          GetExceptionMessage(codec, NULL).c_str());
         return 0;
     }
 
@@ -2813,7 +2886,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -2824,7 +2897,7 @@
         err = codec->setParameters(params);
     }
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, codec);
 }
 
 static void android_media_MediaCodec_setVideoScalingMode(
@@ -2832,13 +2905,14 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
             && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          String8::format("Unrecognized mode: %d", mode));
         return;
     }
 
@@ -2850,7 +2924,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
@@ -2862,14 +2936,14 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
     jobject ret = NULL;
     status_t status = codec->querySupportedVendorParameters(env, &ret);
     if (status != OK) {
-        throwExceptionAsNecessary(env, status);
+        throwExceptionAsNecessary(env, status, codec);
     }
 
     return ret;
@@ -2880,7 +2954,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return NULL;
     }
 
@@ -2897,13 +2971,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t status = codec->subscribeToVendorParameters(env, names);
     if (status != OK) {
-        throwExceptionAsNecessary(env, status);
+        throwExceptionAsNecessary(env, status, codec);
     }
     return;
 }
@@ -2913,13 +2987,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL || codec->initCheck() != OK) {
-        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
         return;
     }
 
     status_t status = codec->unsubscribeFromVendorParameters(env, names);
     if (status != OK) {
-        throwExceptionAsNecessary(env, status);
+        throwExceptionAsNecessary(env, status, codec);
     }
     return;
 }
@@ -3310,11 +3384,15 @@
         if (!context->mReadonlyMapping) {
             const C2BufferData data = buffer->data();
             if (data.type() != C2BufferData::LINEAR) {
-                throwExceptionAsNecessary(env, INVALID_OPERATION);
+                throwExceptionAsNecessary(
+                        env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                        "Underlying buffer is not a linear buffer");
                 return nullptr;
             }
             if (data.linearBlocks().size() != 1u) {
-                throwExceptionAsNecessary(env, INVALID_OPERATION);
+                throwExceptionAsNecessary(
+                        env, INVALID_OPERATION, ACTION_CODE_FATAL,
+                        "Underlying buffer contains more than one block");
                 return nullptr;
             }
             C2ConstLinearBlock block = data.linearBlocks().front();
@@ -3362,7 +3440,9 @@
                 false,  // readOnly
                 true /* clearBuffer */);
     }
-    throwExceptionAsNecessary(env, INVALID_OPERATION);
+    throwExceptionAsNecessary(
+            env, INVALID_OPERATION, ACTION_CODE_FATAL,
+            "Underlying buffer is empty");
     return nullptr;
 }
 
@@ -3385,7 +3465,9 @@
         }
         const char *cstr = env->GetStringUTFChars(jstr, nullptr);
         if (cstr == nullptr) {
-            throwExceptionAsNecessary(env, BAD_VALUE);
+            throwExceptionAsNecessary(
+                    env, BAD_VALUE, ACTION_CODE_FATAL,
+                    "Error converting Java string to native");
             return;
         }
         names->emplace_back(cstr);
@@ -3437,6 +3519,7 @@
     }
     status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
     if (err != OK) {
+        // TODO: CodecErrorLog
         throwExceptionAsNecessary(env, err);
     }
     return isCompatible;
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 616c31b..fbaf64f 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -176,6 +176,8 @@
 
     const sp<ICrypto> &getCrypto() { return mCrypto; }
 
+    std::string getExceptionMessage(const char *msg) const;
+
 protected:
     virtual ~JMediaCodec();
 
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
index 2d3ede0..f586126 100644
--- a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
@@ -70,12 +70,14 @@
                 Log.i(TAG, "Operation cancelled for client " + mCallback.hashCode());
                 wrapCallback(mCallback::onCancel);
             } else if (e instanceof RkpProxyException) {
-                Log.e(TAG, "RKP error fetching key for client " + mCallback.hashCode(), e);
+                Log.e(TAG, "RKP error fetching key for client " + mCallback.hashCode() + ": "
+                        + e.getMessage());
                 RkpProxyException rkpException = (RkpProxyException) e;
                 wrapCallback(() -> mCallback.onError(toGetKeyError(rkpException),
                         e.getMessage()));
             } else {
-                Log.e(TAG, "Error fetching key for client " + mCallback.hashCode(), e);
+                Log.e(TAG, "Unknown error fetching key for client " + mCallback.hashCode() + ": "
+                        + e.getMessage());
                 wrapCallback(() -> mCallback.onError(IGetKeyCallback.ErrorCode.ERROR_UNKNOWN,
                         e.getMessage()));
             }