diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 9a4aa3344374d..dea7f03d369a5 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -43,6 +43,8 @@ #include +#include + #include #include @@ -1276,7 +1278,8 @@ void JMediaCodec::handleCallback(const sp &msg) { 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; } @@ -1309,7 +1312,8 @@ void JMediaCodec::handleCallback(const sp &msg) { 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; } @@ -1322,7 +1326,9 @@ void JMediaCodec::handleCallback(const sp &msg) { 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; } @@ -1353,7 +1359,8 @@ void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp &ms 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; } @@ -1374,7 +1381,8 @@ void JMediaCodec::handleFrameRenderedNotification(const sp &msg) { 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; } @@ -1385,6 +1393,18 @@ void JMediaCodec::handleFrameRenderedNotification(const sp &msg) { 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 &msg) { switch (msg->what()) { case kWhatCallbackNotify: @@ -1471,9 +1491,17 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg, env->Throw(exception); } +static std::string GetExceptionMessage(const sp &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& crypto = NULL) { + const char *msg = NULL, const sp& crypto = NULL, + const sp &codec = NULL) { switch (err) { case OK: return 0; @@ -1488,23 +1516,38 @@ static jint throwExceptionAsNecessary( 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 &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, @@ -1512,13 +1555,13 @@ static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListene sp 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( @@ -1528,13 +1571,13 @@ static void android_media_MediaCodec_native_enableOnFrameRenderedListener( sp 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( @@ -1544,13 +1587,13 @@ static void android_media_MediaCodec_native_setCallback( sp 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( @@ -1564,7 +1607,7 @@ static void android_media_MediaCodec_native_configure( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } @@ -1602,7 +1645,7 @@ static void android_media_MediaCodec_native_configure( err = codec->configure(format, bufferProducer, crypto, descrambler, flags); - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); } static void android_media_MediaCodec_native_setSurface( @@ -1612,7 +1655,7 @@ static void android_media_MediaCodec_native_setSurface( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } @@ -1631,7 +1674,7 @@ static void android_media_MediaCodec_native_setSurface( } status_t err = codec->setSurface(bufferProducer); - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); } sp android_media_MediaCodec_getPersistentInputSurface( @@ -1735,7 +1778,7 @@ static void android_media_MediaCodec_setInputSurface( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } @@ -1749,7 +1792,7 @@ static void android_media_MediaCodec_setInputSurface( } status_t err = codec->setInputSurface(persistentSurface); if (err != NO_ERROR) { - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); } } @@ -1759,7 +1802,7 @@ static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return NULL; } @@ -1767,7 +1810,7 @@ static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, sp bufferProducer; status_t err = codec->createInputSurface(&bufferProducer); if (err != NO_ERROR) { - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); return NULL; } @@ -1782,13 +1825,13 @@ static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { sp 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) { @@ -1797,13 +1840,13 @@ static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { sp 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) { @@ -1812,7 +1855,7 @@ static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) { sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } @@ -1825,7 +1868,7 @@ static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) { // trigger an IllegalStateException. err = UNKNOWN_ERROR; } - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); } static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { @@ -1834,13 +1877,13 @@ static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { sp 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( @@ -1856,7 +1899,7 @@ static void android_media_MediaCodec_queueInputBuffer( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } @@ -1866,7 +1909,8 @@ static void android_media_MediaCodec_queueInputBuffer( 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 { @@ -1890,7 +1934,9 @@ struct NativeCryptoInfo { } 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; } @@ -2026,7 +2072,7 @@ static void android_media_MediaCodec_queueSecureInputBuffer( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } @@ -2056,7 +2102,9 @@ static void android_media_MediaCodec_queueSecureInputBuffer( } 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; } @@ -2175,8 +2223,8 @@ static void android_media_MediaCodec_queueSecureInputBuffer( 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) { @@ -2518,14 +2566,16 @@ static void android_media_MediaCodec_native_queueLinearBlock( sp codec = getMediaCodec(env, thiz); if (codec == nullptr || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } sp 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; } @@ -2545,15 +2595,23 @@ static void android_media_MediaCodec_native_queueLinearBlock( } 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 = @@ -2577,14 +2635,22 @@ static void android_media_MediaCodec_native_queueLinearBlock( 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( @@ -2595,14 +2661,16 @@ static void android_media_MediaCodec_native_queueHardwareBuffer( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } sp 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; } @@ -2627,7 +2695,9 @@ static void android_media_MediaCodec_native_queueHardwareBuffer( 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 block = _C2BlockFactory::CreateGraphicBlock(alloc); @@ -2636,7 +2706,9 @@ static void android_media_MediaCodec_native_queueHardwareBuffer( 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( @@ -2646,13 +2718,13 @@ static void android_media_MediaCodec_native_getOutputFrame( sp 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); } } @@ -2663,7 +2735,7 @@ static jint android_media_MediaCodec_dequeueInputBuffer( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return -1; } @@ -2674,7 +2746,7 @@ static jint android_media_MediaCodec_dequeueInputBuffer( return (jint) index; } - return throwExceptionAsNecessary(env, err); + return throwExceptionAsNecessary(env, err, codec); } static jint android_media_MediaCodec_dequeueOutputBuffer( @@ -2684,7 +2756,7 @@ static jint android_media_MediaCodec_dequeueOutputBuffer( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return 0; } @@ -2696,7 +2768,7 @@ static jint android_media_MediaCodec_dequeueOutputBuffer( return (jint) index; } - return throwExceptionAsNecessary(env, err); + return throwExceptionAsNecessary(env, err, codec); } static void android_media_MediaCodec_releaseOutputBuffer( @@ -2707,13 +2779,13 @@ static void android_media_MediaCodec_releaseOutputBuffer( sp 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, @@ -2722,13 +2794,13 @@ static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, sp 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( @@ -2738,7 +2810,7 @@ static jobject android_media_MediaCodec_getFormatNative( sp 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 @@ static jobject android_media_MediaCodec_getFormatNative( return format; } - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); return NULL; } @@ -2761,7 +2833,7 @@ static jobject android_media_MediaCodec_getOutputFormatForIndexNative( sp 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 @@ static jobject android_media_MediaCodec_getOutputFormatForIndexNative( return format; } - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); return NULL; } @@ -2784,7 +2856,7 @@ static jobjectArray android_media_MediaCodec_getBuffers( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return NULL; } @@ -2797,7 +2869,7 @@ static jobjectArray android_media_MediaCodec_getBuffers( // if we're out of memory, an exception was already thrown if (err != NO_MEMORY) { - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); } return NULL; @@ -2810,7 +2882,7 @@ static jobject android_media_MediaCodec_getBuffer( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return NULL; } @@ -2823,7 +2895,7 @@ static jobject android_media_MediaCodec_getBuffer( // if we're out of memory, an exception was already thrown if (err != NO_MEMORY) { - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); } return NULL; @@ -2836,7 +2908,7 @@ static jobject android_media_MediaCodec_getImage( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return NULL; } @@ -2849,7 +2921,7 @@ static jobject android_media_MediaCodec_getImage( // if we're out of memory, an exception was already thrown if (err != NO_MEMORY) { - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); } return NULL; @@ -2862,7 +2934,7 @@ static jobject android_media_MediaCodec_getName( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return NULL; } @@ -2873,7 +2945,7 @@ static jobject android_media_MediaCodec_getName( return name; } - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); return NULL; } @@ -2885,7 +2957,7 @@ static jobject android_media_MediaCodec_getOwnCodecInfo( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return NULL; } @@ -2896,7 +2968,7 @@ static jobject android_media_MediaCodec_getOwnCodecInfo( return codecInfoObj; } - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); return NULL; } @@ -2908,7 +2980,8 @@ android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz) sp 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; } @@ -2937,7 +3010,7 @@ static void android_media_MediaCodec_setParameters( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } @@ -2948,7 +3021,7 @@ static void android_media_MediaCodec_setParameters( err = codec->setParameters(params); } - throwExceptionAsNecessary(env, err); + throwExceptionAsNecessary(env, err, codec); } static void android_media_MediaCodec_setVideoScalingMode( @@ -2956,13 +3029,14 @@ static void android_media_MediaCodec_setVideoScalingMode( sp 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; } @@ -2974,7 +3048,7 @@ static void android_media_MediaCodec_setAudioPresentation( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return; } @@ -2986,14 +3060,14 @@ static jobject android_media_MediaCodec_getSupportedVendorParameters( sp 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; @@ -3004,7 +3078,7 @@ static jobject android_media_MediaCodec_getParameterDescriptor( sp codec = getMediaCodec(env, thiz); if (codec == NULL || codec->initCheck() != OK) { - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); return NULL; } @@ -3021,13 +3095,13 @@ static void android_media_MediaCodec_subscribeToVendorParameters( sp 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; } @@ -3037,13 +3111,13 @@ static void android_media_MediaCodec_unsubscribeFromVendorParameters( sp 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; } @@ -3440,11 +3514,15 @@ static jobject android_media_MediaCodec_LinearBlock_native_map( 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(); @@ -3492,7 +3570,9 @@ static jobject android_media_MediaCodec_LinearBlock_native_map( false, // readOnly true /* clearBuffer */); } - throwExceptionAsNecessary(env, INVALID_OPERATION); + throwExceptionAsNecessary( + env, INVALID_OPERATION, ACTION_CODE_FATAL, + "Underlying buffer is empty"); return nullptr; } @@ -3515,7 +3595,9 @@ static void PopulateNamesVector( } 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); @@ -3567,6 +3649,7 @@ static jboolean android_media_MediaCodec_LinearBlock_checkCompatible( } 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 616c31b29157d..fbaf64fda5728 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -176,6 +176,8 @@ struct JMediaCodec : public AHandler { const sp &getCrypto() { return mCrypto; } + std::string getExceptionMessage(const char *msg) const; + protected: virtual ~JMediaCodec();